radv: dump annotated shaders using UMR
authorSamuel Pitoiset <samuel.pitoiset@gmail.com>
Mon, 11 Sep 2017 11:44:20 +0000 (13:44 +0200)
committerSamuel Pitoiset <samuel.pitoiset@gmail.com>
Thu, 14 Sep 2017 08:37:57 +0000 (10:37 +0200)
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@gmail.com>
Reviewed-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
src/amd/vulkan/radv_debug.c

index 14971341b7d6b44bb6ce450f5b57c2c90f7c5b92..733374cbb7c21a4c84d8ef86ef994a2dbf3f46a4 100644 (file)
 
 #define TRACE_BO_SIZE 4096
 
+#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 (offsets are 4 bytes):
  *
  * [0]: primary trace ID
@@ -136,6 +142,168 @@ 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,
+                          struct radv_shader_variant *shader,
+                          gl_shader_stage stage,
+                          struct ac_wave_info *waves, unsigned num_waves,
+                          FILE *f)
+{
+       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,
+                           struct radv_shader_variant *compute_shader,
+                           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);
+
+       /* Dump annotated active graphics shaders. */
+       mask = pipeline->active_stages;
+       while (mask) {
+               int stage = u_bit_scan(&mask);
+
+               radv_dump_annotated_shader(pipeline, pipeline->shaders[stage],
+                                          stage, waves, num_waves, f);
+       }
+
+       radv_dump_annotated_shader(pipeline, compute_shader,
+                                  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,
                 struct radv_shader_variant *shader, gl_shader_stage stage,
@@ -178,6 +346,7 @@ radv_dump_graphics_state(struct radv_pipeline *graphics_pipeline,
                return;
 
        radv_dump_shaders(graphics_pipeline, compute_shader, f);
+       radv_dump_annotated_shaders(graphics_pipeline, compute_shader, f);
 }
 
 static void
@@ -188,6 +357,9 @@ radv_dump_compute_state(struct radv_pipeline *compute_pipeline, FILE *f)
 
        radv_dump_shaders(compute_pipeline,
                          compute_pipeline->shaders[MESA_SHADER_COMPUTE], f);
+       radv_dump_annotated_shaders(compute_pipeline,
+                                   compute_pipeline->shaders[MESA_SHADER_COMPUTE],
+                                   f);
 }
 
 static struct radv_pipeline *