On Tuesday, 2018-07-03 11:26:44 +1000, Dave Airlie wrote: > From: Dave Airlie <airl...@redhat.com> > > I'd like to encourage people to test this to see if it helps (like > does it make app startup better or less hitching in dxvk). > > The basic idea is to store a bunch of LLVM related data structs > in thread local storage so we can avoid reiniting them every time > we compile a shader. Since we know llvm objects aren't thread safe > it has to be stored using TLS to avoid any collisions. > > This should remove all the fixed overheads setup costs of creating > the pass manager each time. > > This takes a demo app time to compile the radv meta shaders on nocache > and exit from 1.7s to 1s. It also has been reported to take the startup > time of uncached shaders on RoTR from 12m24s to 11m35s (Alex) > > v2: fix llvm6 build, inline emit function, handle multiple targets > in one thread > v3: rebase and port onto new structure > v4: rename some vars (Bas) > v5: drag all code into radv for now, we can refactor it out later > for radeonsi if we make it shareable > v6: use a bit more C++ in the wrapper > --- > src/amd/vulkan/Makefile.sources | 1 + > src/amd/vulkan/radv_debug.h | 1 + > src/amd/vulkan/radv_device.c | 1 + > src/amd/vulkan/radv_llvm_helper.cpp | 165 ++++++++++++++++++++++++++++ > src/amd/vulkan/radv_nir_to_llvm.c | 5 +- > src/amd/vulkan/radv_shader.c | 10 +- > src/amd/vulkan/radv_shader_helper.h | 45 ++++++++ > 7 files changed, 223 insertions(+), 5 deletions(-) > create mode 100644 src/amd/vulkan/radv_llvm_helper.cpp > create mode 100644 src/amd/vulkan/radv_shader_helper.h > > diff --git a/src/amd/vulkan/Makefile.sources b/src/amd/vulkan/Makefile.sources > index 70d56e88cb3..1e970599e83 100644 > --- a/src/amd/vulkan/Makefile.sources > +++ b/src/amd/vulkan/Makefile.sources > @@ -54,6 +54,7 @@ VULKAN_FILES := \ > radv_meta_resolve_cs.c \ > radv_meta_resolve_fs.c \ > radv_nir_to_llvm.c \ > + radv_llvm_helper.cpp \ > radv_pass.c \ > radv_pipeline.c \ > radv_pipeline_cache.c \
Let's not break the radv meson build ;) ---8<--- diff --git a/src/amd/vulkan/meson.build b/src/amd/vulkan/meson.build index 22857926fa1dee4ae05e..c1a99ab588e78916af73 100644 --- a/src/amd/vulkan/meson.build +++ b/src/amd/vulkan/meson.build @@ -81,6 +81,7 @@ libradv_files = files( 'radv_meta_resolve_cs.c', 'radv_meta_resolve_fs.c', 'radv_nir_to_llvm.c', + 'radv_llvm_helper.cpp', 'radv_pass.c', 'radv_pipeline.c', 'radv_pipeline_cache.c', --->8--- (FYI, in case this wasn't intentional: you're adding "l" between "n" and "p") > diff --git a/src/amd/vulkan/radv_debug.h b/src/amd/vulkan/radv_debug.h > index f1b0dc26a63..9fe4c3b7404 100644 > --- a/src/amd/vulkan/radv_debug.h > +++ b/src/amd/vulkan/radv_debug.h > @@ -49,6 +49,7 @@ enum { > RADV_DEBUG_ERRORS = 0x80000, > RADV_DEBUG_STARTUP = 0x100000, > RADV_DEBUG_CHECKIR = 0x200000, > + RADV_DEBUG_NOTHREADLLVM = 0x400000, > }; > > enum { > diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c > index ad3465f594e..73c48cef1f0 100644 > --- a/src/amd/vulkan/radv_device.c > +++ b/src/amd/vulkan/radv_device.c > @@ -436,6 +436,7 @@ static const struct debug_control radv_debug_options[] = { > {"errors", RADV_DEBUG_ERRORS}, > {"startup", RADV_DEBUG_STARTUP}, > {"checkir", RADV_DEBUG_CHECKIR}, > + {"nothreadllvm", RADV_DEBUG_NOTHREADLLVM}, > {NULL, 0} > }; > > diff --git a/src/amd/vulkan/radv_llvm_helper.cpp > b/src/amd/vulkan/radv_llvm_helper.cpp > new file mode 100644 > index 00000000000..2d763650f8a > --- /dev/null > +++ b/src/amd/vulkan/radv_llvm_helper.cpp > @@ -0,0 +1,165 @@ > +/* > + * Copyright © 2018 Red Hat. > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice (including the next > + * paragraph) shall be included in all copies or substantial portions of the > + * Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > DEALINGS > + * IN THE SOFTWARE. > + */ > +#include "ac_llvm_util.h" > +#include "ac_llvm_build.h" > +#include "radv_shader_helper.h" > +#include <llvm-c/Core.h> > +#include <llvm-c/Support.h> > +#include <llvm/Target/TargetMachine.h> > +#include <llvm/Analysis/TargetLibraryInfo.h> > +#include <llvm/IR/LegacyPassManager.h> > +#if HAVE_LLVM >= 0x0700 > +#include <llvm-c/Transforms/Utils.h> > +#endif > +#if HAVE_LLVM < 0x0700 > +#include "llvm/Support/raw_ostream.h" > +#endif > + > +class radv_llvm_per_thread_info { > +public: > + radv_llvm_per_thread_info(enum radeon_family arg_family, > + enum ac_target_machine_options arg_tm_options) > + : family(arg_family), tm_options(arg_tm_options), > + ostream(code_string) {} > + ~radv_llvm_per_thread_info() > + { > + ac_destroy_llvm_compiler(&llvm_info); > + } > + > + bool init(void) > + { > + if (ac_init_llvm_compiler(&llvm_info, > + true, > + family, > + tm_options)) > + return false; > + > + llvm::TargetMachine *TM = > reinterpret_cast<llvm::TargetMachine*>(llvm_info.tm); > + if (TM->addPassesToEmitFile(pass, ostream, > +#if HAVE_LLVM >= 0x0700 > + nullptr, > +#endif > + > llvm::TargetMachine::CGFT_ObjectFile)) { > + assert(0); > + return false; > + } > + return true; > + } > + > + void compile_to_memory_buffer(LLVMModuleRef module, > + char **error_message, > + LLVMMemoryBufferRef *out_mem_buf) > + { > + llvm::TargetMachine *tm = > reinterpret_cast<llvm::TargetMachine*>(llvm_info.tm); > + llvm::Module *llvm_mod = llvm::unwrap(module); > + llvm::StringRef data; > + > + llvm_mod->setDataLayout(tm->createDataLayout()); > + > + pass.run(*llvm_mod); > + > + data = ostream.str(); > + *out_mem_buf = > LLVMCreateMemoryBufferWithMemoryRangeCopy(data.data(), data.size(), ""); > + code_string = ""; > + } > + > + bool is_same(enum radeon_family arg_family, > + enum ac_target_machine_options arg_tm_options) { > + if (arg_family == family && > + arg_tm_options == tm_options) > + return true; > + return false; > + } > + struct ac_llvm_compiler llvm_info; > +private: > + enum radeon_family family; > + enum ac_target_machine_options tm_options; > + llvm::SmallString<0> code_string; > + llvm::raw_svector_ostream ostream; > + llvm::legacy::PassManager pass; > +}; > + > +/* we have to store a linked list per thread due to the possiblity of > multiple gpus being required */ > +static thread_local std::list<radv_llvm_per_thread_info> > radv_llvm_per_thread_list; > + > +bool radv_compile_to_memory_buffer(struct ac_llvm_compiler *info, > + LLVMModuleRef module, > + char **error_message, > + LLVMMemoryBufferRef *out_mem_buf) > +{ > + radv_llvm_per_thread_info *thread_info = nullptr; > + > + for (auto &I : radv_llvm_per_thread_list) { > + if (I.llvm_info.tm == info->tm) { > + thread_info = &I; > + break; > + } > + } > + > + if (!thread_info) { > + return LLVMTargetMachineEmitToMemoryBuffer(info->tm, module, > LLVMObjectFile, > + error_message, > out_mem_buf); > + } > + > + thread_info->compile_to_memory_buffer(module, error_message, > out_mem_buf); > + return false; > +} > + > +bool radv_init_llvm_compiler(struct ac_llvm_compiler *info, > + bool okay_to_leak_target_library_info, > + bool thread_compiler, > + enum radeon_family family, > + enum ac_target_machine_options tm_options) > +{ > + if (thread_compiler) { > + for (auto &I : radv_llvm_per_thread_list) { > + if (I.is_same(family, tm_options)) { > + *info = I.llvm_info; > + return true; > + } > + } > + > + radv_llvm_per_thread_list.emplace_back(family, tm_options); > + radv_llvm_per_thread_info &tinfo = > radv_llvm_per_thread_list.back(); > + > + if (tinfo.init()) > + return false; > + > + *info = tinfo.llvm_info; > + return true; > + } > + > + if (!ac_init_llvm_compiler(info, > + okay_to_leak_target_library_info, > + family, > + tm_options)) > + return false; > + return true; > +} > + > +void radv_destroy_llvm_compiler(struct ac_llvm_compiler *info, > + bool thread_compiler) > +{ > + if (thread_compiler) > + ac_destroy_llvm_compiler(info); > +} > diff --git a/src/amd/vulkan/radv_nir_to_llvm.c > b/src/amd/vulkan/radv_nir_to_llvm.c > index 45ac0854c17..76a6f1ea6da 100644 > --- a/src/amd/vulkan/radv_nir_to_llvm.c > +++ b/src/amd/vulkan/radv_nir_to_llvm.c > @@ -27,6 +27,7 @@ > > #include "radv_private.h" > #include "radv_shader.h" > +#include "radv_shader_helper.h" > #include "nir/nir.h" > > #include <llvm-c/Core.h> > @@ -3343,8 +3344,8 @@ static unsigned ac_llvm_compile(LLVMModuleRef M, > &retval); > > /* Compile IR*/ > - mem_err = LLVMTargetMachineEmitToMemoryBuffer(ac_llvm->tm, M, > LLVMObjectFile, > - &err, &out_buffer); > + mem_err = radv_compile_to_memory_buffer(ac_llvm, M, > + &err, &out_buffer); > > /* Process Errors/Warnings */ > if (mem_err) { > diff --git a/src/amd/vulkan/radv_shader.c b/src/amd/vulkan/radv_shader.c > index 5cca761d89e..13990059985 100644 > --- a/src/amd/vulkan/radv_shader.c > +++ b/src/amd/vulkan/radv_shader.c > @@ -30,6 +30,7 @@ > #include "radv_debug.h" > #include "radv_private.h" > #include "radv_shader.h" > +#include "radv_shader_helper.h" > #include "nir/nir.h" > #include "nir/nir_builder.h" > #include "spirv/nir_spirv.h" > @@ -542,7 +543,7 @@ shader_variant_create(struct radv_device *device, > struct radv_shader_variant *variant; > struct ac_shader_binary binary; > struct ac_llvm_compiler ac_llvm; > - > + bool thread_compiler; > variant = calloc(1, sizeof(struct radv_shader_variant)); > if (!variant) > return NULL; > @@ -564,8 +565,11 @@ shader_variant_create(struct radv_device *device, > if (options->check_ir) > tm_options |= AC_TM_CHECK_IR; > > + thread_compiler = !(device->instance->debug_flags & > RADV_DEBUG_NOTHREADLLVM); > radv_init_llvm_once(); > - ac_init_llvm_compiler(&ac_llvm, false, chip_family, tm_options); > + radv_init_llvm_compiler(&ac_llvm, false, > + thread_compiler, > + chip_family, tm_options); > if (gs_copy_shader) { > assert(shader_count == 1); > radv_compile_gs_copy_shader(&ac_llvm, *shaders, &binary, > @@ -577,7 +581,7 @@ shader_variant_create(struct radv_device *device, > options); > } > > - ac_destroy_llvm_compiler(&ac_llvm); > + radv_destroy_llvm_compiler(&ac_llvm, thread_compiler); > > radv_fill_shader_variant(device, variant, &binary, stage); > > diff --git a/src/amd/vulkan/radv_shader_helper.h > b/src/amd/vulkan/radv_shader_helper.h > new file mode 100644 > index 00000000000..c90c4cca7cb > --- /dev/null > +++ b/src/amd/vulkan/radv_shader_helper.h > @@ -0,0 +1,45 @@ > +/* > + * Copyright © 2018 Red Hat. > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice (including the next > + * paragraph) shall be included in all copies or substantial portions of the > + * Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > DEALINGS > + * IN THE SOFTWARE. > + */ > +#ifndef RADV_SHADER_HELPER_H > +#define RADV_SHADER_HELPER_H > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +bool radv_init_llvm_compiler(struct ac_llvm_compiler *info, > + bool okay_to_leak_target_library_info, > + bool thread_compiler, > + enum radeon_family family, > + enum ac_target_machine_options tm_options); > +void radv_destroy_llvm_compiler(struct ac_llvm_compiler *info, > + bool thread_compiler); > + > +bool radv_compile_to_memory_buffer(struct ac_llvm_compiler *info, > + LLVMModuleRef module, > + char **error_message, > + LLVMMemoryBufferRef *out_mem_buf); > + > +#ifdef __cplusplus > +} > +#endif > +#endif > -- > 2.17.1 > > _______________________________________________ > mesa-dev mailing list > mesa-dev@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/mesa-dev _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev