Module: Mesa Branch: main Commit: 80a319c0b444293761eb7e07cc4e97ad65d56cd5 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=80a319c0b444293761eb7e07cc4e97ad65d56cd5
Author: Mark Collins <[email protected]> Date: Fri Dec 1 13:27:15 2023 +0000 freedreno/rddecompiler: Add ability to read GPU buffer into file While running tests, it is be useful to have non-sequenced dumps of certain buffers to see their contents from changes in the decompiled CS. This introduces a function gpu_read_into_file(...) for specifying a file to read a specific GPU buffer into after replaying the CS. Signed-off-by: Mark Collins <[email protected]> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26465> --- src/freedreno/common/redump.h | 1 + src/freedreno/decode/rdcompiler-utils.h | 41 ++++++++++++++++++++++++ src/freedreno/decode/replay.c | 56 +++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) diff --git a/src/freedreno/common/redump.h b/src/freedreno/common/redump.h index 980e57488d1..7b97e1a8078 100644 --- a/src/freedreno/common/redump.h +++ b/src/freedreno/common/redump.h @@ -44,6 +44,7 @@ enum rd_sect_type { RD_CHIP_ID, RD_SHADER_LOG_BUFFER, /* Specifies buffer which has logs from shaders */ RD_CP_LOG_BUFFER, /* Specifies buffer which has logs from CP */ + RD_WRBUFFER, /* Specifies buffer which has data that needs to be written out to a file */ }; /* RD_PARAM types: */ diff --git a/src/freedreno/decode/rdcompiler-utils.h b/src/freedreno/decode/rdcompiler-utils.h index 45c4cc05c30..feef4a86ddd 100644 --- a/src/freedreno/decode/rdcompiler-utils.h +++ b/src/freedreno/decode/rdcompiler-utils.h @@ -45,6 +45,14 @@ cs_get_cur_iova(struct cmdstream *cs) return cs->iova + cs->cur * sizeof(uint32_t); } +struct wrbuf { + struct list_head link; + + uint64_t iova; + uint64_t size; + const char *name; +}; + struct replay_context { void *mem_ctx; @@ -59,6 +67,8 @@ struct replay_context { struct list_head cs_list; + struct list_head wrbuf_list; + struct ir3_compiler *compiler; struct hash_table_u64 *compiled_shaders; @@ -165,6 +175,18 @@ rd_write_cs_submit(FILE *out, struct cmdstream *cs) fwrite(packet, sizeof(packet), 1, out); } +static void +rd_write_wrbuffer(FILE *out, struct wrbuf *wrbuf) +{ + uint32_t name_len = strlen(wrbuf->name) + 1; + struct rd_section section = {.type = RD_WRBUFFER, + .size = (uint32_t)(sizeof(uint32_t) * 2) + name_len}; + fwrite(§ion, sizeof(section), 1, out); + fwrite(&wrbuf->iova, sizeof(uint64_t), 1, out); + fwrite(&wrbuf->size, sizeof(uint64_t), 1, out); + fwrite(wrbuf->name, sizeof(char), name_len, out); +} + static void print_usage(const char *name) { @@ -225,6 +247,7 @@ replay_context_init(struct replay_context *ctx, struct fd_dev_id *dev_id, ctx->mem_ctx = ralloc_context(NULL); list_inithead(&ctx->cs_list); + list_inithead(&ctx->wrbuf_list); util_vma_heap_init(&ctx->vma, va_start, ROUND_DOWN_TO(va_size, 4096)); @@ -270,6 +293,10 @@ replay_context_finish(struct replay_context *ctx) } rd_write_cs_submit(out, ctx->submit_cs); + list_for_each_entry (struct wrbuf, wrbuf, &ctx->wrbuf_list, link) { + rd_write_wrbuffer(out, wrbuf); + } + fclose(out); } @@ -379,3 +406,17 @@ gpu_print(struct replay_context *ctx, struct cmdstream *_cs, uint64_t iova, end_ib(); } + +static void +gpu_read_into_file(struct replay_context *ctx, struct cmdstream *_cs, + uint64_t iova, uint64_t size, const char *name) +{ + struct wrbuf *wrbuf = (struct wrbuf *) calloc(1, sizeof(struct wrbuf)); + wrbuf->iova = iova; + wrbuf->size = size; + wrbuf->name = strdup(name); + + assert(wrbuf->iova != 0); + + list_addtail(&wrbuf->link, &ctx->wrbuf_list); +} \ No newline at end of file diff --git a/src/freedreno/decode/replay.c b/src/freedreno/decode/replay.c index 5d22f994a06..6081640c711 100644 --- a/src/freedreno/decode/replay.c +++ b/src/freedreno/decode/replay.c @@ -170,6 +170,12 @@ struct cmdstream { uint64_t size; }; +struct wrbuf { + uint64_t iova; + uint64_t size; + char* name; +}; + struct device { int fd; @@ -190,6 +196,8 @@ struct device { #ifdef FD_REPLAY_KGSL uint32_t context_id; #endif + + struct u_vector wrbufs; }; void buffer_mem_free(struct device *dev, struct buffer *buf); @@ -325,6 +333,40 @@ device_print_cp_log(struct device *dev) } } +static void +device_dump_wrbuf(struct device *dev) +{ + if (!u_vector_length(&dev->wrbufs)) + return; + + char buffer_dir[256]; + snprintf(buffer_dir, sizeof(buffer_dir), "%s/buffers", exename); + rmdir(buffer_dir); + mkdir(buffer_dir, 0777); + + struct wrbuf *wrbuf; + u_vector_foreach(wrbuf, &dev->wrbufs) { + char buffer_path[256]; + snprintf(buffer_path, sizeof(buffer_path), "%s/%s", buffer_dir, wrbuf->name); + FILE *f = fopen(buffer_path, "wb"); + if (!f) { + fprintf(stderr, "Error opening %s\n", buffer_path); + goto end_it; + } + + struct buffer *buf = device_get_buffer(dev, wrbuf->iova); + if (!buf) { + fprintf(stderr, "Error getting buffer for %s\n", buffer_path); + goto end_it; + } + const void *buffer = buf->map + (wrbuf->iova - buf->iova); + fwrite(buffer, wrbuf->size, 1, f); + + end_it: + fclose(f); + } +} + #if !FD_REPLAY_KGSL static inline void get_abs_timeout(struct drm_msm_timespec *tv, uint64_t ns) @@ -401,6 +443,7 @@ device_create() rb_tree_init(&dev->buffers); util_vma_heap_init(&dev->vma, va_start, ROUND_DOWN_TO(va_size, 4096)); u_vector_init(&dev->cmdstreams, 8, sizeof(struct cmdstream)); + u_vector_init(&dev->wrbufs, 8, sizeof(struct wrbuf)); return dev; } @@ -521,6 +564,8 @@ device_submit_cmdstreams(struct device *dev) device_print_shader_log(dev); device_print_cp_log(dev); + + device_dump_wrbuf(dev); } static void @@ -714,6 +759,8 @@ device_submit_cmdstreams(struct device *dev) device_print_shader_log(dev); device_print_cp_log(dev); + + device_dump_wrbuf(dev); } static void @@ -834,6 +881,15 @@ override_cmdstream(struct device *dev, struct cmdstream *cs, parse_addr(ps.buf, ps.sz, &sizedwords, &dev->cp_log_iova); break; } + case RD_WRBUFFER: { + struct wrbuf *wrbuf = u_vector_add(&dev->wrbufs); + uint64_t *p = (uint64_t *)ps.buf; + wrbuf->iova = p[0]; + wrbuf->size = p[1]; + wrbuf->name = calloc(1, p[2]); + memcpy(wrbuf->name, (char *)ps.buf + 3 * sizeof(uint64_t), p[2]); + break; + } default: break; }
