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

Reply via email to