[Mesa-dev] [PATCH] radv: using tls to store llvm related info and speed up compiles (v9)

Bas Nieuwenhuizen bas at basnieuwenhuizen.nl
Mon Jul 9 21:24:42 UTC 2018


Reviewed-by: Bas Nieuwenhuizen <bas at basnieuwenhuizen.nl>

On Mon, Jul 9, 2018 at 11:14 PM, Dave Airlie <airlied at gmail.com> wrote:
> From: Dave Airlie <airlied at redhat.com>
>
> This uses the common compiler passes abstraction to help radv
> avoid fixed cost compiler overheads. This uses a linked list per
> thread stored in thread local storage, with an entry in the list
> for each target machine.
>
> 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
> v7: logic bugs fixed so it actually runs again.
> v8: rebase on top of radeonsi changes.
> v9: drop some C++ headers, cleanup list entry
> v10: use pop_back (didn't have enough caffeine)
> ---
>  src/amd/vulkan/Makefile.sources     |   2 +
>  src/amd/vulkan/meson.build          |   2 +
>  src/amd/vulkan/radv_debug.h         |   1 +
>  src/amd/vulkan/radv_device.c        |   1 +
>  src/amd/vulkan/radv_llvm_helper.cpp | 140 ++++++++++++++++++++++++++++
>  src/amd/vulkan/radv_nir_to_llvm.c   |  27 +-----
>  src/amd/vulkan/radv_shader.c        |  10 +-
>  src/amd/vulkan/radv_shader_helper.h |  44 +++++++++
>  8 files changed, 199 insertions(+), 28 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..152fdd7cb71 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 \
> @@ -62,6 +63,7 @@ VULKAN_FILES := \
>         radv_shader.c \
>         radv_shader_info.c \
>         radv_shader.h \
> +       radv_shader_helper.h \
>         radv_query.c \
>         radv_util.c \
>         radv_util.h \
> diff --git a/src/amd/vulkan/meson.build b/src/amd/vulkan/meson.build
> index 22857926fa1..9f2842182e7 100644
> --- a/src/amd/vulkan/meson.build
> +++ b/src/amd/vulkan/meson.build
> @@ -67,6 +67,7 @@ libradv_files = files(
>    'radv_descriptor_set.h',
>    'radv_formats.c',
>    'radv_image.c',
> +  'radv_llvm_helper.cpp',
>    'radv_meta.c',
>    'radv_meta.h',
>    'radv_meta_blit.c',
> @@ -88,6 +89,7 @@ libradv_files = files(
>    'radv_radeon_winsys.h',
>    'radv_shader.c',
>    'radv_shader.h',
> +  'radv_shader_helper.h',
>    'radv_shader_info.c',
>    'radv_query.c',
>    'radv_util.c',
> 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..ed05e1197ec
> --- /dev/null
> +++ b/src/amd/vulkan/radv_llvm_helper.cpp
> @@ -0,0 +1,140 @@
> +/*
> + * 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 <list>
> +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) {}
> +
> +       ~radv_llvm_per_thread_info()
> +       {
> +               ac_destroy_llvm_passes(passes);
> +               ac_destroy_llvm_compiler(&llvm_info);
> +       }
> +
> +       bool init(void)
> +       {
> +               if (!ac_init_llvm_compiler(&llvm_info,
> +                                         true,
> +                                         family,
> +                                         tm_options))
> +                       return false;
> +
> +               passes = ac_create_llvm_passes(llvm_info.tm);
> +               if (!passes)
> +                       return false;
> +
> +               return true;
> +       }
> +
> +       bool compile_to_memory_buffer(LLVMModuleRef module,
> +                                     struct ac_shader_binary *binary)
> +       {
> +               return ac_compile_module_to_binary(passes, module, binary);
> +       }
> +
> +       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;
> +       struct ac_compiler_passes *passes;
> +};
> +
> +/* 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_binary(struct ac_llvm_compiler *info,
> +                           LLVMModuleRef module,
> +                           struct ac_shader_binary *binary)
> +{
> +       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) {
> +               struct ac_compiler_passes *passes = ac_create_llvm_passes(info->tm);
> +               bool ret = ac_compile_module_to_binary(passes, module, binary);
> +               ac_destroy_llvm_passes(passes);
> +               return ret;
> +       }
> +
> +       return thread_info->compile_to_memory_buffer(module, binary);
> +}
> +
> +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()) {
> +                       radv_llvm_per_thread_list.pop_back();
> +                       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 cc3ae006aaa..c7d772fa652 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>
> @@ -3331,12 +3332,7 @@ static unsigned ac_llvm_compile(LLVMModuleRef M,
>                                  struct ac_llvm_compiler *ac_llvm)
>  {
>         unsigned retval = 0;
> -       char *err;
>         LLVMContextRef llvm_ctx;
> -       LLVMMemoryBufferRef out_buffer;
> -       unsigned buffer_size;
> -       const char *buffer_data;
> -       LLVMBool mem_err;
>
>         /* Setup Diagnostic Handler*/
>         llvm_ctx = LLVMGetModuleContext(M);
> @@ -3345,27 +3341,8 @@ static unsigned ac_llvm_compile(LLVMModuleRef M,
>                                         &retval);
>
>         /* Compile IR*/
> -       mem_err = LLVMTargetMachineEmitToMemoryBuffer(ac_llvm->tm, M, LLVMObjectFile,
> -                                                     &err, &out_buffer);
> -
> -       /* Process Errors/Warnings */
> -       if (mem_err) {
> -               fprintf(stderr, "%s: %s", __FUNCTION__, err);
> -               free(err);
> +       if (!radv_compile_to_binary(ac_llvm, M, binary))
>                 retval = 1;
> -               goto out;
> -       }
> -
> -       /* Extract Shader Code*/
> -       buffer_size = LLVMGetBufferSize(out_buffer);
> -       buffer_data = LLVMGetBufferStart(out_buffer);
> -
> -       ac_elf_read(buffer_data, buffer_size, binary);
> -
> -       /* Clean up */
> -       LLVMDisposeMemoryBuffer(out_buffer);
> -
> -out:
>         return retval;
>  }
>
> 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..3c81f5be54a
> --- /dev/null
> +++ b/src/amd/vulkan/radv_shader_helper.h
> @@ -0,0 +1,44 @@
> +/*
> + * 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_binary(struct ac_llvm_compiler *info,
> +                           LLVMModuleRef module,
> +                           struct ac_shader_binary *binary);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +#endif
> --
> 2.17.1
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/mesa-dev


More information about the mesa-dev mailing list