[Mesa-dev] [PATCH] radv: using tls to store llvm related info and speed up compiles (v8)
Dave Airlie
airlied at gmail.com
Mon Jul 9 21:03:05 UTC 2018
On 9 July 2018 at 05:58, Bas Nieuwenhuizen <bas at basnieuwenhuizen.nl> wrote:
> On Thu, Jul 5, 2018 at 2:03 AM, 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.
>> ---
>> 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 | 148 ++++++++++++++++++++++++++++
>> 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, 207 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,
In response to your second query, I'm not sure I understand.
NOTHREADLLVM is here!
>> };
>>
>> 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..dad881f6b1a
>> --- /dev/null
>> +++ b/src/amd/vulkan/radv_llvm_helper.cpp
>> @@ -0,0 +1,148 @@
>> +/*
>> + * 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) {}
>> +
>> + ~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())
>> + return false;
>
> Clean up the newly inserted list entry?
Once I figure out how to do it nicely :-)
Dave.
More information about the mesa-dev
mailing list