[Mesa-dev] [PATCH v2 3/3] radeonsi: add RADEON_REPLACE_SHADERS debug option

Nicolai Hähnle nhaehnle at gmail.com
Mon Dec 21 13:18:22 PST 2015


From: Nicolai Hähnle <nicolai.haehnle at amd.com>

This option allows replacing a single shader by a pre-compiled ELF object
as generated by LLVM's llc, for example. This can be useful for debugging a
deterministically occuring error in shaders (and has in fact helped find
the causes of https://bugs.freedesktop.org/show_bug.cgi?id=93264).

v2: drop the debug flag, use DEBUG_GET_ONCE_OPTION instead
---
 src/gallium/drivers/radeonsi/si_debug.c  | 95 ++++++++++++++++++++++++++++++++
 src/gallium/drivers/radeonsi/si_pipe.h   |  1 +
 src/gallium/drivers/radeonsi/si_shader.c | 14 +++--
 3 files changed, 105 insertions(+), 5 deletions(-)

diff --git a/src/gallium/drivers/radeonsi/si_debug.c b/src/gallium/drivers/radeonsi/si_debug.c
index c45f8c0..a07b1c5 100644
--- a/src/gallium/drivers/radeonsi/si_debug.c
+++ b/src/gallium/drivers/radeonsi/si_debug.c
@@ -28,8 +28,11 @@
 #include "si_shader.h"
 #include "sid.h"
 #include "sid_tables.h"
+#include "radeon/radeon_elf_util.h"
 #include "ddebug/dd_util.h"
+#include "util/u_memory.h"
 
+DEBUG_GET_ONCE_OPTION(replace_shaders, "RADEON_REPLACE_SHADERS", NULL)
 
 static void si_dump_shader(struct si_shader_ctx_state *state, const char *name,
 			   FILE *f)
@@ -42,6 +45,98 @@ static void si_dump_shader(struct si_shader_ctx_state *state, const char *name,
 	fprintf(f, "%s\n\n", state->current->binary.disasm_string);
 }
 
+/**
+ * Shader compiles can be overridden with arbitrary ELF objects by setting
+ * the environment variable RADEON_REPLACE_SHADERS=num1:filename1[;num2:filename2]
+ */
+bool si_replace_shader(unsigned num, struct radeon_shader_binary *binary)
+{
+	const char *p = debug_get_option_replace_shaders();
+	const char *semicolon;
+	char *copy = NULL;
+	FILE *f;
+	long filesize, nread;
+	char *buf = NULL;
+	bool replaced = false;
+
+	if (!p)
+		return false;
+
+	while (*p) {
+		unsigned long i;
+		char *endp;
+		i = strtoul(p, &endp, 0);
+
+		p = endp;
+		if (*p != ':') {
+			fprintf(stderr, "RADEON_REPLACE_SHADERS formatted badly.\n");
+			exit(1);
+		}
+		++p;
+
+		if (i == num)
+			break;
+
+		p = strchr(p, ';');
+		if (!p)
+			return false;
+		++p;
+	}
+	if (!*p)
+		return false;
+
+	semicolon = strchr(p, ';');
+	if (semicolon) {
+		p = copy = strndup(p, semicolon - p);
+		if (!copy) {
+			fprintf(stderr, "out of memory\n");
+			return false;
+		}
+	}
+
+	fprintf(stderr, "radeonsi: replace shader %u by %s\n", num, p);
+
+	f = fopen(p, "r");
+	if (!f) {
+		perror("radeonsi: failed to open file");
+		goto out_free;
+	}
+
+	if (fseek(f, 0, SEEK_END) != 0)
+		goto file_error;
+
+	filesize = ftell(f);
+	if (filesize < 0)
+		goto file_error;
+
+	if (fseek(f, 0, SEEK_SET) != 0)
+		goto file_error;
+
+	buf = MALLOC(filesize);
+	if (!buf) {
+		fprintf(stderr, "out of memory\n");
+		goto out_close;
+	}
+
+	nread = fread(buf, 1, filesize, f);
+	if (nread != filesize)
+		goto file_error;
+
+	radeon_elf_read(buf, filesize, binary);
+	replaced = true;
+
+out_close:
+	fclose(f);
+out_free:
+	FREE(buf);
+	free(copy);
+	return replaced;
+
+file_error:
+	perror("radeonsi: reading shader");
+	goto out_close;
+}
+
 /* Parsed IBs are difficult to read without colors. Use "less -R file" to
  * read them, or use "aha -b -f file" to convert them to html.
  */
diff --git a/src/gallium/drivers/radeonsi/si_pipe.h b/src/gallium/drivers/radeonsi/si_pipe.h
index 65c7e19..f83cb02 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.h
+++ b/src/gallium/drivers/radeonsi/si_pipe.h
@@ -329,6 +329,7 @@ void si_init_cp_dma_functions(struct si_context *sctx);
 /* si_debug.c */
 void si_init_debug_functions(struct si_context *sctx);
 void si_check_vm_faults(struct si_context *sctx);
+bool si_replace_shader(unsigned num, struct radeon_shader_binary *binary);
 
 /* si_dma.c */
 void si_dma_copy(struct pipe_context *ctx,
diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c
index 511ed88..0e98784 100644
--- a/src/gallium/drivers/radeonsi/si_shader.c
+++ b/src/gallium/drivers/radeonsi/si_shader.c
@@ -3884,13 +3884,17 @@ int si_compile_llvm(struct si_screen *sscreen, struct si_shader *shader,
 	bool dump_asm = r600_can_dump_shader(&sscreen->b,
 				shader->selector ? shader->selector->tokens : NULL);
 	bool dump_ir = dump_asm && !(sscreen->b.debug_flags & DBG_NO_IR);
+	unsigned count = p_atomic_inc_return(&sscreen->b.num_compilations);
 
-	p_atomic_inc(&sscreen->b.num_compilations);
+	if (dump_ir || dump_asm)
+		fprintf(stderr, "radeonsi: Compiling shader %d\n", count);
 
-	r = radeon_llvm_compile(mod, &shader->binary,
-		r600_get_llvm_processor_name(sscreen->b.family), dump_ir, dump_asm, tm);
-	if (r)
-		return r;
+	if (!si_replace_shader(count, &shader->binary)) {
+		r = radeon_llvm_compile(mod, &shader->binary,
+			r600_get_llvm_processor_name(sscreen->b.family), dump_ir, dump_asm, tm);
+		if (r)
+			return r;
+	}
 
 	r = si_shader_binary_read(sscreen, shader);
 
-- 
2.5.0



More information about the mesa-dev mailing list