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 <mark@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26465>
This commit is contained in:
Mark Collins 2023-12-01 13:27:15 +00:00 committed by Marge Bot
parent 3c89b2882f
commit 80a319c0b4
3 changed files with 98 additions and 0 deletions

View file

@ -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: */

View file

@ -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(&section, 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);
}

View file

@ -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;
}