[Mesa-dev] [PATCH] radv: using tls to store llvm related info and speed up compiles (v8)
Bas Nieuwenhuizen
bas at basnieuwenhuizen.nl
Mon Jul 9 21:07:59 UTC 2018
On Mon, Jul 9, 2018 at 11:03 PM, Dave Airlie <airlied at gmail.com> wrote:
> 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!
woops, I somehow missed it.
>
>>> };
>>>
>>> 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