[Mesa-dev] [PATCH 11/15] radv: dump annotated shaders using UMR
Samuel Pitoiset
samuel.pitoiset at gmail.com
Tue Sep 12 10:35:48 UTC 2017
This might be very useful in order to figure out where a shader
is stucked. This uses UMR to detect which instruction is executing
bad things.
Signed-off-by: Samuel Pitoiset <samuel.pitoiset at gmail.com>
---
src/amd/vulkan/radv_debug.c | 166 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 166 insertions(+)
diff --git a/src/amd/vulkan/radv_debug.c b/src/amd/vulkan/radv_debug.c
index 6f7337b028..497aef96fc 100644
--- a/src/amd/vulkan/radv_debug.c
+++ b/src/amd/vulkan/radv_debug.c
@@ -34,6 +34,12 @@
#include "radv_debug.h"
#include "radv_shader.h"
+#define COLOR_RESET "\033[0m"
+#define COLOR_RED "\033[31m"
+#define COLOR_GREEN "\033[1;32m"
+#define COLOR_YELLOW "\033[1;33m"
+#define COLOR_CYAN "\033[1;36m"
+
/* Trace BO layout:
*
* [0]: primary trace ID
@@ -131,6 +137,165 @@ radv_dump_debug_registers(struct radv_device *device, FILE *f)
fprintf(f, "\n");
}
+struct radv_shader_inst {
+ char text[160]; /* one disasm line */
+ unsigned offset; /* instruction offset */
+ unsigned size; /* instruction size = 4 or 8 */
+};
+
+/* Split a disassembly string into lines and add them to the array pointed
+ * to by "instructions". */
+static void si_add_split_disasm(const char *disasm,
+ uint64_t start_addr,
+ unsigned *num,
+ struct radv_shader_inst *instructions)
+{
+ struct radv_shader_inst *last_inst = *num ? &instructions[*num - 1] : NULL;
+ char *next;
+
+ while ((next = strchr(disasm, '\n'))) {
+ struct radv_shader_inst *inst = &instructions[*num];
+ unsigned len = next - disasm;
+
+ assert(len < ARRAY_SIZE(inst->text));
+ memcpy(inst->text, disasm, len);
+ inst->text[len] = 0;
+ inst->offset = last_inst ? last_inst->offset + last_inst->size : 0;
+
+ const char *semicolon = strchr(disasm, ';');
+ assert(semicolon);
+ /* More than 16 chars after ";" means the instruction is 8 bytes long. */
+ inst->size = next - semicolon > 16 ? 8 : 4;
+
+ snprintf(inst->text + len, ARRAY_SIZE(inst->text) - len,
+ " [PC=0x%"PRIx64", off=%u, size=%u]",
+ start_addr + inst->offset, inst->offset, inst->size);
+
+ last_inst = inst;
+ (*num)++;
+ disasm = next + 1;
+ }
+}
+
+static void
+radv_dump_annotated_shader(struct radv_pipeline *pipeline,
+ gl_shader_stage stage,
+ struct ac_wave_info *waves, unsigned num_waves,
+ FILE *f)
+{
+ struct radv_shader_variant *shader = pipeline->shaders[stage];
+ struct radv_device *device = pipeline->device;
+ uint64_t start_addr, end_addr;
+ unsigned i;
+
+ if (!shader)
+ return;
+
+ start_addr = device->ws->buffer_get_va(shader->bo) + shader->bo_offset;
+ end_addr = start_addr + shader->code_size;
+
+ /* See if any wave executes the shader. */
+ for (i = 0; i < num_waves; i++) {
+ if (start_addr <= waves[i].pc && waves[i].pc <= end_addr)
+ break;
+ }
+
+ if (i == num_waves)
+ return; /* the shader is not being executed */
+
+ /* Remember the first found wave. The waves are sorted according to PC. */
+ waves = &waves[i];
+ num_waves -= i;
+
+ /* Get the list of instructions.
+ * Buffer size / 4 is the upper bound of the instruction count.
+ */
+ unsigned num_inst = 0;
+ struct radv_shader_inst *instructions =
+ calloc(shader->code_size / 4, sizeof(struct radv_shader_inst));
+
+ si_add_split_disasm(shader->disasm_string,
+ start_addr, &num_inst, instructions);
+
+ fprintf(f, COLOR_YELLOW "%s - annotated disassembly:" COLOR_RESET "\n",
+ radv_get_shader_name(shader, stage));
+
+ /* Print instructions with annotations. */
+ for (i = 0; i < num_inst; i++) {
+ struct radv_shader_inst *inst = &instructions[i];
+
+ fprintf(f, "%s\n", inst->text);
+
+ /* Print which waves execute the instruction right now. */
+ while (num_waves && start_addr + inst->offset == waves->pc) {
+ fprintf(f,
+ " " COLOR_GREEN "^ SE%u SH%u CU%u "
+ "SIMD%u WAVE%u EXEC=%016"PRIx64 " ",
+ waves->se, waves->sh, waves->cu, waves->simd,
+ waves->wave, waves->exec);
+
+ if (inst->size == 4) {
+ fprintf(f, "INST32=%08X" COLOR_RESET "\n",
+ waves->inst_dw0);
+ } else {
+ fprintf(f, "INST64=%08X %08X" COLOR_RESET "\n",
+ waves->inst_dw0, waves->inst_dw1);
+ }
+
+ waves->matched = true;
+ waves = &waves[1];
+ num_waves--;
+ }
+ }
+
+ fprintf(f, "\n\n");
+ free(instructions);
+}
+
+static void
+radv_dump_annotated_shaders(struct radv_pipeline *pipeline, FILE *f)
+{
+ struct ac_wave_info waves[AC_MAX_WAVES_PER_CHIP];
+ unsigned num_waves = ac_get_wave_info(waves);
+ unsigned mask;
+
+ fprintf(f, COLOR_CYAN "The number of active waves = %u" COLOR_RESET
+ "\n\n", num_waves);
+
+ mask = pipeline->active_stages;
+ while (mask) {
+ int stage = u_bit_scan(&mask);
+
+ radv_dump_annotated_shader(pipeline, stage, waves,
+ num_waves, f);
+ }
+
+ radv_dump_annotated_shader(pipeline, MESA_SHADER_COMPUTE, waves,
+ num_waves, f);
+
+ /* Print waves executing shaders that are not currently bound. */
+ unsigned i;
+ bool found = false;
+ for (i = 0; i < num_waves; i++) {
+ if (waves[i].matched)
+ continue;
+
+ if (!found) {
+ fprintf(f, COLOR_CYAN
+ "Waves not executing currently-bound shaders:"
+ COLOR_RESET "\n");
+ found = true;
+ }
+ fprintf(f, " SE%u SH%u CU%u SIMD%u WAVE%u EXEC=%016"PRIx64
+ " INST=%08X %08X PC=%"PRIx64"\n",
+ waves[i].se, waves[i].sh, waves[i].cu, waves[i].simd,
+ waves[i].wave, waves[i].exec, waves[i].inst_dw0,
+ waves[i].inst_dw1, waves[i].pc);
+ }
+ if (found)
+ fprintf(f, "\n\n");
+}
+
static void
radv_dump_shader(struct radv_pipeline *pipeline, gl_shader_stage stage, FILE *f)
{
@@ -167,6 +332,7 @@ radv_dump_state(struct radv_pipeline *pipeline, FILE *f)
return;
radv_dump_shaders(pipeline, f);
+ radv_dump_annotated_shaders(pipeline, f);
}
static struct radv_pipeline *
--
2.14.1
More information about the mesa-dev
mailing list