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

Eric Engestrom eric.engestrom at intel.com
Tue Jul 3 10:16:34 UTC 2018


On Tuesday, 2018-07-03 11:26:44 +1000, Dave Airlie wrote:
> From: Dave Airlie <airlied at 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 at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/mesa-dev


More information about the mesa-dev mailing list