From 0a17035b5cd3e181a2bf4ab6feea8b4d5763b613 Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin Date: Wed, 26 Jun 2024 20:37:28 +0300 Subject: [PATCH] u_trace: add support for indirect data Allows a driver to declare indirect arguments for its tracepoints and pass an address. u_trace will request a copy of the data which should be implemented on the command processor. Signed-off-by: Lionel Landwerlin Co-Authored-by: Danylo Piliaiev Reviewed-by: Danylo Piliaiev Part-of: --- docs/u_trace.rst | 3 + src/freedreno/vulkan/tu_device.cc | 3 + src/freedreno/vulkan/tu_perfetto.cc | 18 ++-- src/gallium/auxiliary/util/u_trace_gallium.c | 6 ++ src/gallium/auxiliary/util/u_trace_gallium.h | 3 + .../drivers/freedreno/freedreno_context.c | 3 + .../drivers/freedreno/freedreno_perfetto.cc | 66 ++++++++----- src/gallium/drivers/iris/iris_utrace.c | 3 + src/gallium/drivers/radeonsi/si_perfetto.cpp | 6 +- src/gallium/drivers/radeonsi/si_utrace.c | 5 +- src/intel/ds/intel_driver_ds.cc | 40 ++++---- src/intel/vulkan/anv_utrace.c | 3 + src/intel/vulkan_hasvk/anv_utrace.c | 3 + src/util/perf/u_trace.c | 77 +++++++++++++-- src/util/perf/u_trace.h | 53 +++++++++++ src/util/perf/u_trace.py | 95 +++++++++++++++---- src/util/perf/u_trace_priv.h | 23 +++-- src/util/tests/perf/u_trace_test.cpp | 3 +- 18 files changed, 333 insertions(+), 80 deletions(-) diff --git a/docs/u_trace.rst b/docs/u_trace.rst index 97326ac1e93..02d2cd7db68 100644 --- a/docs/u_trace.rst +++ b/docs/u_trace.rst @@ -44,6 +44,9 @@ u_trace is controlled by environment variables: - For Turnip, ``cffdump`` can be used to view the markers in the trace. + ``indirects`` + enables indirect data capture for some of the tracepoints (like + indirect draw count or indirect dispatch size) .. envvar:: MESA_GPU_TRACEFILE diff --git a/src/freedreno/vulkan/tu_device.cc b/src/freedreno/vulkan/tu_device.cc index 3886c34e1a4..73b79fca7c7 100644 --- a/src/freedreno/vulkan/tu_device.cc +++ b/src/freedreno/vulkan/tu_device.cc @@ -2521,10 +2521,13 @@ tu_CreateDevice(VkPhysicalDevice physicalDevice, device->submit_count = 0; u_trace_context_init(&device->trace_context, device, sizeof(uint64_t), + 0, tu_trace_create_buffer, tu_trace_destroy_buffer, TU_CALLX(device, tu_trace_record_ts), tu_trace_read_ts, + NULL, + NULL, tu_trace_delete_flush_data); tu_breadcrumbs_init(device); diff --git a/src/freedreno/vulkan/tu_perfetto.cc b/src/freedreno/vulkan/tu_perfetto.cc index 9b3b248b7df..85788b6dfdc 100644 --- a/src/freedreno/vulkan/tu_perfetto.cc +++ b/src/freedreno/vulkan/tu_perfetto.cc @@ -474,7 +474,8 @@ tu_perfetto_submit(struct tu_device *dev, #define CREATE_EVENT_CALLBACK(event_name, stage_id) \ void tu_perfetto_start_##event_name( \ struct tu_device *dev, uint64_t ts_ns, uint16_t tp_idx, \ - const void *flush_data, const struct trace_start_##event_name *payload) \ + const void *flush_data, const struct trace_start_##event_name *payload, \ + const void *indirect_data) \ { \ stage_start( \ dev, ts_ns, stage_id, NULL, payload, sizeof(*payload), \ @@ -483,7 +484,8 @@ tu_perfetto_submit(struct tu_device *dev, \ void tu_perfetto_end_##event_name( \ struct tu_device *dev, uint64_t ts_ns, uint16_t tp_idx, \ - const void *flush_data, const struct trace_end_##event_name *payload) \ + const void *flush_data, const struct trace_end_##event_name *payload, \ + const void *indirect_data) \ { \ stage_end( \ dev, ts_ns, stage_id, flush_data, payload, \ @@ -510,7 +512,8 @@ tu_perfetto_start_cmd_buffer_annotation( uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_start_cmd_buffer_annotation *payload) + const struct trace_start_cmd_buffer_annotation *payload, + const void *indirect_data) { /* No extra func necessary, the only arg is in the end payload.*/ stage_start(dev, ts_ns, CMD_BUFFER_ANNOTATION_STAGE_ID, payload->str, payload, @@ -523,7 +526,8 @@ tu_perfetto_end_cmd_buffer_annotation( uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_end_cmd_buffer_annotation *payload) + const struct trace_end_cmd_buffer_annotation *payload, + const void *indirect_data) { /* Pass the payload string as the app_event, which will appear right on the * event block, rather than as metadata inside. @@ -538,7 +542,8 @@ tu_perfetto_start_cmd_buffer_annotation_rp( uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_start_cmd_buffer_annotation_rp *payload) + const struct trace_start_cmd_buffer_annotation_rp *payload, + const void *indirect_data) { /* No extra func necessary, the only arg is in the end payload.*/ stage_start(dev, ts_ns, CMD_BUFFER_ANNOTATION_RENDER_PASS_STAGE_ID, @@ -551,7 +556,8 @@ tu_perfetto_end_cmd_buffer_annotation_rp( uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_end_cmd_buffer_annotation_rp *payload) + const struct trace_end_cmd_buffer_annotation_rp *payload, + const void *indirect_data) { /* Pass the payload string as the app_event, which will appear right on the * event block, rather than as metadata inside. diff --git a/src/gallium/auxiliary/util/u_trace_gallium.c b/src/gallium/auxiliary/util/u_trace_gallium.c index 694a00eb838..df79a7c3011 100644 --- a/src/gallium/auxiliary/util/u_trace_gallium.c +++ b/src/gallium/auxiliary/util/u_trace_gallium.c @@ -62,16 +62,22 @@ void u_trace_pipe_context_init(struct u_trace_context *utctx, struct pipe_context *pctx, uint32_t timestamp_size_B, + uint32_t max_indirect_size_B, u_trace_record_ts record_timestamp, u_trace_read_ts read_timestamp, + u_trace_capture_data capture_data, + u_trace_get_data get_data, u_trace_delete_flush_data delete_flush_data) { u_trace_context_init(utctx, pctx, timestamp_size_B, + max_indirect_size_B, u_trace_pipe_create_buffer, u_trace_pipe_delete_buffer, record_timestamp, read_timestamp, + capture_data, + get_data, delete_flush_data); } diff --git a/src/gallium/auxiliary/util/u_trace_gallium.h b/src/gallium/auxiliary/util/u_trace_gallium.h index e303c5a97a9..33eaf54846e 100644 --- a/src/gallium/auxiliary/util/u_trace_gallium.h +++ b/src/gallium/auxiliary/util/u_trace_gallium.h @@ -39,8 +39,11 @@ void u_trace_pipe_context_init(struct u_trace_context *utctx, struct pipe_context *pctx, uint32_t timestamp_size_B, + uint32_t max_indirect_size_B, u_trace_record_ts record_timestamp, u_trace_read_ts read_timestamp, + u_trace_capture_data capture_data, + u_trace_get_data get_data, u_trace_delete_flush_data delete_flush_data); /* diff --git a/src/gallium/drivers/freedreno/freedreno_context.c b/src/gallium/drivers/freedreno/freedreno_context.c index f809c70ac7c..b2d2693105b 100644 --- a/src/gallium/drivers/freedreno/freedreno_context.c +++ b/src/gallium/drivers/freedreno/freedreno_context.c @@ -718,8 +718,11 @@ fd_context_init(struct fd_context *ctx, struct pipe_screen *pscreen, fd_gpu_tracepoint_config_variable(); u_trace_pipe_context_init(&ctx->trace_context, pctx, sizeof(uint64_t), + 0, fd_trace_record_ts, fd_trace_read_ts, + NULL, + NULL, fd_trace_delete_flush_data); fd_autotune_init(&ctx->autotune, screen->dev); diff --git a/src/gallium/drivers/freedreno/freedreno_perfetto.cc b/src/gallium/drivers/freedreno/freedreno_perfetto.cc index 28ad7757ab3..b9e61462596 100644 --- a/src/gallium/drivers/freedreno/freedreno_perfetto.cc +++ b/src/gallium/drivers/freedreno/freedreno_perfetto.cc @@ -357,7 +357,8 @@ fd_perfetto_submit(struct fd_context *ctx) void fd_start_render_pass(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_start_render_pass *payload) + const struct trace_start_render_pass *payload, + const void *indirect_data) { stage_start(pctx, ts_ns, SURFACE_STAGE_ID); @@ -378,7 +379,8 @@ fd_start_render_pass(struct pipe_context *pctx, uint64_t ts_ns, void fd_end_render_pass(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_end_render_pass *payload) + const struct trace_end_render_pass *payload, + const void *indirect_data) { stage_end(pctx, ts_ns, SURFACE_STAGE_ID); } @@ -386,7 +388,8 @@ fd_end_render_pass(struct pipe_context *pctx, uint64_t ts_ns, void fd_start_binning_ib(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_start_binning_ib *payload) + const struct trace_start_binning_ib *payload, + const void *indirect_data) { stage_start(pctx, ts_ns, BINNING_STAGE_ID); } @@ -394,7 +397,8 @@ fd_start_binning_ib(struct pipe_context *pctx, uint64_t ts_ns, void fd_end_binning_ib(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_end_binning_ib *payload) + const struct trace_end_binning_ib *payload, + const void *indirect_data) { stage_end(pctx, ts_ns, BINNING_STAGE_ID); } @@ -402,7 +406,8 @@ fd_end_binning_ib(struct pipe_context *pctx, uint64_t ts_ns, void fd_start_draw_ib(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_start_draw_ib *payload) + const struct trace_start_draw_ib *payload, + const void *indirect_data) { stage_start( pctx, ts_ns, @@ -412,7 +417,8 @@ fd_start_draw_ib(struct pipe_context *pctx, uint64_t ts_ns, void fd_end_draw_ib(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_end_draw_ib *payload) + const struct trace_end_draw_ib *payload, + const void *indirect_data) { stage_end( pctx, ts_ns, @@ -422,7 +428,8 @@ fd_end_draw_ib(struct pipe_context *pctx, uint64_t ts_ns, void fd_start_blit(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_start_blit *payload) + const struct trace_start_blit *payload, + const void *indirect_data) { stage_start(pctx, ts_ns, BLIT_STAGE_ID); } @@ -430,7 +437,8 @@ fd_start_blit(struct pipe_context *pctx, uint64_t ts_ns, void fd_end_blit(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_end_blit *payload) + const struct trace_end_blit *payload, + const void *indirect_data) { stage_end(pctx, ts_ns, BLIT_STAGE_ID); } @@ -438,7 +446,8 @@ fd_end_blit(struct pipe_context *pctx, uint64_t ts_ns, void fd_start_compute(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_start_compute *payload) + const struct trace_start_compute *payload, + const void *indirect_data) { stage_start(pctx, ts_ns, COMPUTE_STAGE_ID); @@ -458,7 +467,8 @@ fd_start_compute(struct pipe_context *pctx, uint64_t ts_ns, void fd_end_compute(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_end_compute *payload) + const struct trace_end_compute *payload, + const void *indirect_data) { stage_end(pctx, ts_ns, COMPUTE_STAGE_ID); } @@ -466,7 +476,8 @@ fd_end_compute(struct pipe_context *pctx, uint64_t ts_ns, void fd_start_clears(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_start_clears *payload) + const struct trace_start_clears *payload, + const void *indirect_data) { stage_start(pctx, ts_ns, CLEAR_STAGE_ID); } @@ -474,7 +485,8 @@ fd_start_clears(struct pipe_context *pctx, uint64_t ts_ns, void fd_end_clears(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_end_clears *payload) + const struct trace_end_clears *payload, + const void *indirect_data) { stage_end(pctx, ts_ns, CLEAR_STAGE_ID); } @@ -482,7 +494,8 @@ fd_end_clears(struct pipe_context *pctx, uint64_t ts_ns, void fd_start_tile_loads(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_start_tile_loads *payload) + const struct trace_start_tile_loads *payload, + const void *indirect_data) { stage_start(pctx, ts_ns, TILE_LOAD_STAGE_ID); } @@ -490,7 +503,8 @@ fd_start_tile_loads(struct pipe_context *pctx, uint64_t ts_ns, void fd_end_tile_loads(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_end_tile_loads *payload) + const struct trace_end_tile_loads *payload, + const void *indirect_data) { stage_end(pctx, ts_ns, TILE_LOAD_STAGE_ID); } @@ -498,7 +512,8 @@ fd_end_tile_loads(struct pipe_context *pctx, uint64_t ts_ns, void fd_start_tile_stores(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_start_tile_stores *payload) + const struct trace_start_tile_stores *payload, + const void *indirect_data) { stage_start(pctx, ts_ns, TILE_STORE_STAGE_ID); } @@ -506,7 +521,8 @@ fd_start_tile_stores(struct pipe_context *pctx, uint64_t ts_ns, void fd_end_tile_stores(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_end_tile_stores *payload) + const struct trace_end_tile_stores *payload, + const void *indirect_data) { stage_end(pctx, ts_ns, TILE_STORE_STAGE_ID); } @@ -514,7 +530,8 @@ fd_end_tile_stores(struct pipe_context *pctx, uint64_t ts_ns, void fd_start_state_restore(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_start_state_restore *payload) + const struct trace_start_state_restore *payload, + const void *indirect_data) { stage_start(pctx, ts_ns, STATE_RESTORE_STAGE_ID); } @@ -522,7 +539,8 @@ fd_start_state_restore(struct pipe_context *pctx, uint64_t ts_ns, void fd_end_state_restore(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_end_state_restore *payload) + const struct trace_end_state_restore *payload, + const void *indirect_data) { stage_end(pctx, ts_ns, STATE_RESTORE_STAGE_ID); } @@ -530,7 +548,8 @@ fd_end_state_restore(struct pipe_context *pctx, uint64_t ts_ns, void fd_start_vsc_overflow_test(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_start_vsc_overflow_test *payload) + const struct trace_start_vsc_overflow_test *payload, + const void *indirect_data) { stage_start(pctx, ts_ns, VSC_OVERFLOW_STAGE_ID); } @@ -538,7 +557,8 @@ fd_start_vsc_overflow_test(struct pipe_context *pctx, uint64_t ts_ns, void fd_end_vsc_overflow_test(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_end_vsc_overflow_test *payload) + const struct trace_end_vsc_overflow_test *payload, + const void *indirect_data) { stage_end(pctx, ts_ns, VSC_OVERFLOW_STAGE_ID); } @@ -546,7 +566,8 @@ fd_end_vsc_overflow_test(struct pipe_context *pctx, uint64_t ts_ns, void fd_start_prologue(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_start_prologue *payload) + const struct trace_start_prologue *payload, + const void *indirect_data) { stage_start(pctx, ts_ns, PROLOGUE_STAGE_ID); } @@ -554,7 +575,8 @@ fd_start_prologue(struct pipe_context *pctx, uint64_t ts_ns, void fd_end_prologue(struct pipe_context *pctx, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_end_prologue *payload) + const struct trace_end_prologue *payload, + const void *indirect_data) { stage_end(pctx, ts_ns, PROLOGUE_STAGE_ID); } diff --git a/src/gallium/drivers/iris/iris_utrace.c b/src/gallium/drivers/iris/iris_utrace.c index 73239ea5ed2..259f45d48f4 100644 --- a/src/gallium/drivers/iris/iris_utrace.c +++ b/src/gallium/drivers/iris/iris_utrace.c @@ -188,10 +188,13 @@ void iris_utrace_init(struct iris_context *ice) u_trace_context_init(&ice->ds.trace_context, &ice->ctx, sizeof(union iris_utrace_timestamp), + 0, iris_utrace_create_buffer, iris_utrace_delete_buffer, iris_utrace_record_ts, iris_utrace_read_ts, + NULL, + NULL, iris_utrace_delete_flush_data); for (int i = 0; i < IRIS_BATCH_COUNT; i++) { diff --git a/src/gallium/drivers/radeonsi/si_perfetto.cpp b/src/gallium/drivers/radeonsi/si_perfetto.cpp index 1a5547b880b..7c22f7995ea 100644 --- a/src/gallium/drivers/radeonsi/si_perfetto.cpp +++ b/src/gallium/drivers/radeonsi/si_perfetto.cpp @@ -260,7 +260,8 @@ extern "C" { #define CREATE_DUAL_EVENT_CALLBACK(event_name, stage) \ void si_ds_begin_##event_name(struct si_ds_device *device, uint64_t ts_ns, uint16_t tp_idx, \ const void *flush_data, \ - const struct trace_si_begin_##event_name *payload) \ + const struct trace_si_begin_##event_name *payload, \ + const void *indirect_data) \ { \ const struct si_ds_flush_data *flush = (const struct si_ds_flush_data *) flush_data; \ begin_event(flush->queue, ts_ns, stage); \ @@ -268,7 +269,8 @@ void si_ds_begin_##event_name(struct si_ds_device *device, uint64_t ts_ns, uint1 \ void si_ds_end_##event_name(struct si_ds_device *device, uint64_t ts_ns, uint16_t tp_idx, \ const void *flush_data, \ - const struct trace_si_end_##event_name *payload) \ + const struct trace_si_end_##event_name *payload, \ + const void *indirect_data) \ { \ const struct si_ds_flush_data *flush = (const struct si_ds_flush_data *) flush_data; \ end_event(flush->queue, ts_ns, stage, flush->submission_id, NULL, payload, \ diff --git a/src/gallium/drivers/radeonsi/si_utrace.c b/src/gallium/drivers/radeonsi/si_utrace.c index af0a7a172e6..d0e978e86cb 100644 --- a/src/gallium/drivers/radeonsi/si_utrace.c +++ b/src/gallium/drivers/radeonsi/si_utrace.c @@ -61,8 +61,9 @@ void si_utrace_init(struct si_context *sctx) si_ds_device_init(&sctx->ds, &sctx->screen->info, gpu_id, AMD_DS_API_OPENGL); u_trace_pipe_context_init(&sctx->ds.trace_context, &sctx->b, - sizeof(uint64_t), si_utrace_record_ts, - si_utrace_read_ts, si_utrace_delete_flush_data); + sizeof(uint64_t), 0, si_utrace_record_ts, + si_utrace_read_ts, NULL, NULL, + si_utrace_delete_flush_data); si_ds_device_init_queue(&sctx->ds, &sctx->ds_queue, "%s", "render"); } diff --git a/src/intel/ds/intel_driver_ds.cc b/src/intel/ds/intel_driver_ds.cc index 9a4db3b4931..7c1377cd4bf 100644 --- a/src/intel/ds/intel_driver_ds.cc +++ b/src/intel/ds/intel_driver_ds.cc @@ -229,7 +229,7 @@ send_descriptors(IntelRenderpassDataSource::TraceContext &ctx, sync_timestamp(ctx, device); } -typedef void (*trace_payload_as_extra_func)(perfetto::protos::pbzero::GpuRenderStageEvent *, const void*); +typedef void (*trace_payload_as_extra_func)(perfetto::protos::pbzero::GpuRenderStageEvent *, const void*, const void *); static void begin_event(struct intel_ds_queue *queue, uint64_t ts_ns, @@ -258,7 +258,8 @@ end_event(struct intel_ds_queue *queue, uint64_t ts_ns, uint32_t submission_id, uint16_t tracepoint_idx, const char *app_event, - const void* payload = nullptr, + const void *payload = nullptr, + const void *indirect_data = nullptr, trace_payload_as_extra_func payload_as_extra = nullptr) { struct intel_ds_device *device = queue->device; @@ -280,7 +281,6 @@ end_event(struct intel_ds_queue *queue, uint64_t ts_ns, if (!start_ns) return; - IntelRenderpassDataSource::Trace([=](IntelRenderpassDataSource::TraceContext tctx) { if (auto state = tctx.GetIncrementalState(); state->was_cleared) { send_descriptors(tctx, queue->device); @@ -317,7 +317,7 @@ end_event(struct intel_ds_queue *queue, uint64_t ts_ns, event->set_submission_id(submission_id); if (payload && payload_as_extra) { - payload_as_extra(event, payload); + payload_as_extra(event, payload, indirect_data); } }); @@ -384,7 +384,8 @@ extern "C" { uint64_t ts_ns, \ uint16_t tp_idx, \ const void *flush_data, \ - const struct trace_intel_begin_##event_name *payload) \ + const struct trace_intel_begin_##event_name *payload, \ + const void *indirect_data) \ { \ const struct intel_ds_flush_data *flush = \ (const struct intel_ds_flush_data *) flush_data; \ @@ -396,12 +397,13 @@ extern "C" { uint64_t ts_ns, \ uint16_t tp_idx, \ const void *flush_data, \ - const struct trace_intel_end_##event_name *payload) \ + const struct trace_intel_end_##event_name *payload, \ + const void *indirect_data) \ { \ const struct intel_ds_flush_data *flush = \ (const struct intel_ds_flush_data *) flush_data; \ end_event(flush->queue, ts_ns, stage, flush->submission_id, \ - tp_idx, NULL, payload, \ + tp_idx, NULL, payload, indirect_data, \ (trace_payload_as_extra_func) \ &trace_payload_as_extra_intel_end_##event_name); \ } \ @@ -442,7 +444,8 @@ intel_ds_begin_cmd_buffer_annotation(struct intel_ds_device *device, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_intel_begin_cmd_buffer_annotation *payload) + const struct trace_intel_begin_cmd_buffer_annotation *payload, + const void *indirect_data) { const struct intel_ds_flush_data *flush = (const struct intel_ds_flush_data *) flush_data; @@ -454,12 +457,13 @@ intel_ds_end_cmd_buffer_annotation(struct intel_ds_device *device, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_intel_end_cmd_buffer_annotation *payload) + const struct trace_intel_end_cmd_buffer_annotation *payload, + const void *indirect_data) { const struct intel_ds_flush_data *flush = (const struct intel_ds_flush_data *) flush_data; end_event(flush->queue, ts_ns, INTEL_DS_QUEUE_STAGE_CMD_BUFFER, - flush->submission_id, tp_idx, payload->str, NULL, NULL); + flush->submission_id, tp_idx, payload->str, NULL, NULL, NULL); } void @@ -467,7 +471,8 @@ intel_ds_begin_queue_annotation(struct intel_ds_device *device, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_intel_begin_queue_annotation *payload) + const struct trace_intel_begin_queue_annotation *payload, + const void *indirect_data) { const struct intel_ds_flush_data *flush = (const struct intel_ds_flush_data *) flush_data; @@ -479,12 +484,13 @@ intel_ds_end_queue_annotation(struct intel_ds_device *device, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_intel_end_queue_annotation *payload) + const struct trace_intel_end_queue_annotation *payload, + const void *indirect_data) { const struct intel_ds_flush_data *flush = (const struct intel_ds_flush_data *) flush_data; end_event(flush->queue, ts_ns, INTEL_DS_QUEUE_STAGE_QUEUE, - flush->submission_id, tp_idx, payload->str, NULL, NULL); + flush->submission_id, tp_idx, payload->str, NULL, NULL, NULL); } void @@ -492,7 +498,8 @@ intel_ds_begin_stall(struct intel_ds_device *device, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_intel_begin_stall *payload) + const struct trace_intel_begin_stall *payload, + const void *indirect_data) { const struct intel_ds_flush_data *flush = (const struct intel_ds_flush_data *) flush_data; @@ -504,12 +511,13 @@ intel_ds_end_stall(struct intel_ds_device *device, uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_intel_end_stall *payload) + const struct trace_intel_end_stall *payload, + const void *indirect_data) { const struct intel_ds_flush_data *flush = (const struct intel_ds_flush_data *) flush_data; end_event(flush->queue, ts_ns, INTEL_DS_QUEUE_STAGE_STALL, - flush->submission_id, tp_idx, NULL, payload, + flush->submission_id, tp_idx, NULL, payload, indirect_data, (trace_payload_as_extra_func)custom_trace_payload_as_extra_end_stall); } diff --git a/src/intel/vulkan/anv_utrace.c b/src/intel/vulkan/anv_utrace.c index 34b43cdcb03..4ad2e946c5f 100644 --- a/src/intel/vulkan/anv_utrace.c +++ b/src/intel/vulkan/anv_utrace.c @@ -449,10 +449,13 @@ anv_device_utrace_init(struct anv_device *device) u_trace_context_init(&device->ds.trace_context, &device->ds, device->utrace_timestamp_size, + 0, anv_utrace_create_buffer, anv_utrace_destroy_buffer, anv_utrace_record_ts, anv_utrace_read_ts, + NULL, + NULL, anv_utrace_delete_submit); for (uint32_t q = 0; q < device->queue_count; q++) { diff --git a/src/intel/vulkan_hasvk/anv_utrace.c b/src/intel/vulkan_hasvk/anv_utrace.c index b0cbfa1cd0d..1ed6453ca7f 100644 --- a/src/intel/vulkan_hasvk/anv_utrace.c +++ b/src/intel/vulkan_hasvk/anv_utrace.c @@ -282,10 +282,13 @@ anv_device_utrace_init(struct anv_device *device) u_trace_context_init(&device->ds.trace_context, &device->ds, sizeof(uint64_t), + 0, anv_utrace_create_buffer, anv_utrace_destroy_buffer, anv_utrace_record_ts, anv_utrace_read_ts, + NULL, + NULL, anv_utrace_delete_flush_data); for (uint32_t q = 0; q < device->queue_count; q++) { diff --git a/src/util/perf/u_trace.c b/src/util/perf/u_trace.c index fd62d884c27..b5a671bb135 100644 --- a/src/util/perf/u_trace.c +++ b/src/util/perf/u_trace.c @@ -91,6 +91,10 @@ struct u_trace_chunk { */ void *timestamps; + /* table of indirect data captured by u_trace + */ + void *indirects; + /* Array of u_trace_payload_buf referenced by traces[] elements. */ struct u_vector payloads; @@ -100,6 +104,7 @@ struct u_trace_chunk { struct util_queue_fence fence; + bool has_indirect; bool last; /* this chunk is last in batch */ bool eof; /* this chunk is last in frame, unless frame_nr is set */ uint32_t frame_nr; /* frame idx from the driver */ @@ -124,7 +129,8 @@ struct u_trace_printer { struct u_trace_chunk *chunk, const struct u_trace_event *evt, uint64_t ns, - int32_t delta); + int32_t delta, + const void *indirect); }; static void @@ -156,12 +162,13 @@ print_txt_event(struct u_trace_context *utctx, struct u_trace_chunk *chunk, const struct u_trace_event *evt, uint64_t ns, - int32_t delta) + int32_t delta, + const void *indirect) { if (evt->tp->print) { fprintf(utctx->out, "%016" PRIu64 " %+9d: %s: ", ns, delta, evt->tp->name); - evt->tp->print(utctx->out, evt->payload); + evt->tp->print(utctx->out, evt->payload, indirect); } else { fprintf(utctx->out, "%016" PRIu64 " %+9d: %s\n", ns, delta, evt->tp->name); @@ -228,7 +235,8 @@ print_json_event(struct u_trace_context *utctx, struct u_trace_chunk *chunk, const struct u_trace_event *evt, uint64_t ns, - int32_t delta) + int32_t delta, + const void *indirect) { if (utctx->event_nr != 0) fprintf(utctx->out, ",\n"); @@ -236,7 +244,7 @@ print_json_event(struct u_trace_context *utctx, fprintf(utctx->out, "\"time_ns\": \"%016" PRIu64 "\",\n", ns); fprintf(utctx->out, "\"params\": {"); if (evt->tp->print) - evt->tp->print_json(utctx->out, evt->payload); + evt->tp->print_json(utctx->out, evt->payload, indirect); fprintf(utctx->out, "}\n}\n"); } @@ -285,6 +293,8 @@ free_chunk(void *ptr) struct u_trace_chunk *chunk = ptr; chunk->utctx->delete_buffer(chunk->utctx, chunk->timestamps); + if (chunk->indirects) + chunk->utctx->delete_buffer(chunk->utctx, chunk->indirects); /* Unref payloads attached to this chunk. */ struct u_trace_payload_buf **payload; @@ -349,6 +359,12 @@ get_chunk(struct u_trace *ut, size_t payload_size) chunk->timestamps = ut->utctx->create_buffer(ut->utctx, chunk->utctx->timestamp_size_bytes * TIMESTAMP_BUF_SIZE); + if (chunk->utctx->max_indirect_size_bytes && + (chunk->utctx->enabled_traces & U_TRACE_TYPE_INDIRECTS)) { + chunk->indirects = + ut->utctx->create_buffer(ut->utctx, + chunk->utctx->max_indirect_size_bytes * TIMESTAMP_BUF_SIZE); + } chunk->last = true; u_vector_init(&chunk->payloads, 4, sizeof(struct u_trace_payload_buf *)); if (payload_size > 0) { @@ -369,6 +385,7 @@ static const struct debug_named_value config_control[] = { { "perfetto", U_TRACE_TYPE_PERFETTO_ENV, "Enable perfetto" }, #endif { "markers", U_TRACE_TYPE_MARKERS, "Enable marker trace" }, + { "indirects", U_TRACE_TYPE_INDIRECTS, "Enable indirect data capture" }, DEBUG_NAMED_VALUE_END }; @@ -436,10 +453,13 @@ void u_trace_context_init(struct u_trace_context *utctx, void *pctx, uint32_t timestamp_size_bytes, + uint32_t max_indirect_size_bytes, u_trace_create_buffer create_buffer, u_trace_delete_buffer delete_buffer, u_trace_record_ts record_timestamp, u_trace_read_ts read_timestamp, + u_trace_capture_data capture_data, + u_trace_get_data get_data, u_trace_delete_flush_data delete_flush_data) { u_trace_state_init(); @@ -449,9 +469,12 @@ u_trace_context_init(struct u_trace_context *utctx, utctx->create_buffer = create_buffer; utctx->delete_buffer = delete_buffer; utctx->record_timestamp = record_timestamp; + utctx->capture_data = capture_data; + utctx->get_data = get_data; utctx->read_timestamp = read_timestamp; utctx->delete_flush_data = delete_flush_data; utctx->timestamp_size_bytes = timestamp_size_bytes; + utctx->max_indirect_size_bytes = max_indirect_size_bytes; utctx->last_time_ns = 0; utctx->first_time_ns = 0; @@ -460,6 +483,8 @@ u_trace_context_init(struct u_trace_context *utctx, utctx->event_nr = 0; utctx->start_of_frame = true; + utctx->dummy_indirect_data = calloc(1, max_indirect_size_bytes); + list_inithead(&utctx->flushed_trace_chunks); if (utctx->enabled_traces & U_TRACE_TYPE_PRINT) { @@ -515,6 +540,8 @@ u_trace_context_fini(struct u_trace_context *utctx) fflush(utctx->out); } + free (utctx->dummy_indirect_data); + if (!utctx->queue.jobs) return; util_queue_finish(&utctx->queue); @@ -614,14 +641,26 @@ process_chunk(void *job, void *gdata, int thread_index) delta = 0; } + const void *indirect_data = NULL; + if (evt->tp->indirect_sz > 0) { + if (utctx->enabled_traces & U_TRACE_TYPE_INDIRECTS) { + indirect_data = utctx->get_data(utctx, chunk->indirects, + utctx->max_indirect_size_bytes * idx, + evt->tp->indirect_sz); + } else { + indirect_data = utctx->dummy_indirect_data; + } + } + if (utctx->out) { - utctx->out_printer->event(utctx, chunk, evt, ns, delta); + utctx->out_printer->event(utctx, chunk, evt, ns, delta, indirect_data); } #ifdef HAVE_PERFETTO if (evt->tp->perfetto && (p_atomic_read_relaxed(&utctx->enabled_traces) & U_TRACE_TYPE_PERFETTO_ACTIVE)) { - evt->tp->perfetto(utctx->pctx, ns, evt->tp->tp_idx, chunk->flush_data, evt->payload); + evt->tp->perfetto(utctx->pctx, ns, evt->tp->tp_idx, chunk->flush_data, + evt->payload, indirect_data); } #endif @@ -782,6 +821,15 @@ u_trace_clone_append(struct u_trace_iterator begin_it, begin_it.ut->utctx->timestamp_size_bytes * to_chunk->num_traces, begin_it.ut->utctx->timestamp_size_bytes * to_copy); + if (from_chunk->has_indirect) { + copy_buffer(begin_it.ut->utctx, cmdstream, + from_chunk->indirects, + begin_it.ut->utctx->max_indirect_size_bytes * from_idx, + to_chunk->indirects, + begin_it.ut->utctx->max_indirect_size_bytes * to_chunk->num_traces, + begin_it.ut->utctx->max_indirect_size_bytes * to_copy); + } + memcpy(&to_chunk->traces[to_chunk->num_traces], &from_chunk->traces[from_idx], to_copy * sizeof(struct u_trace_event)); @@ -845,7 +893,10 @@ void * u_trace_appendv(struct u_trace *ut, void *cs, const struct u_tracepoint *tp, - unsigned variable_sz) + unsigned variable_sz, + unsigned n_indirects, + const struct u_trace_address *addresses, + const uint8_t *indirect_sizes_B) { assert(tp->payload_sz == ALIGN_NPOT(tp->payload_sz, 8)); @@ -865,6 +916,16 @@ u_trace_appendv(struct u_trace *ut, ut->utctx->timestamp_size_bytes * tp_idx, tp->flags); + if (ut->utctx->enabled_traces & U_TRACE_TYPE_INDIRECTS) { + for (unsigned i = 0; i < n_indirects; i++) { + ut->utctx->capture_data(ut, cs, chunk->indirects, + ut->utctx->max_indirect_size_bytes * tp_idx, + addresses[i].bo, addresses[i].offset, + indirect_sizes_B[i]); + } + chunk->has_indirect |= n_indirects > 0; + } + chunk->traces[tp_idx] = (struct u_trace_event) { .tp = tp, .payload = payload, diff --git a/src/util/perf/u_trace.h b/src/util/perf/u_trace.h index c7109c1bdb1..1c99634e514 100644 --- a/src/util/perf/u_trace.h +++ b/src/util/perf/u_trace.h @@ -79,6 +79,20 @@ struct u_trace_printer; */ #define U_TRACE_NO_TIMESTAMP ((uint64_t) 0) +/** + * Address representation + */ +struct u_trace_address { + /** + * Pointer to a buffer object + */ + void *bo; + /** + * Offset inside the buffer object or address of bo is NULL + */ + uint64_t offset; +}; + /** * Driver provided callback to create a buffer which will be read by * u_trace_read_ts function. @@ -107,6 +121,24 @@ typedef void (*u_trace_record_ts)(struct u_trace *ut, uint64_t offset_B, uint32_t flags); +/** + * Driver provided callback to capture indirect data. + */ +typedef void (*u_trace_capture_data)(struct u_trace *ut, + void *cs, + void *dst_buffer, + uint64_t dst_offset_B, + void *src_buffer, + uint64_t src_offset_B, + uint32_t size_B); + +/** + * Driver provided callback to read back previously recorded indirect data. + */ +typedef const void *(*u_trace_get_data)(struct u_trace_context *utctx, + void *buffer, + uint64_t offset_B, + uint32_t size_B); /** * Driver provided callback to read back a previously recorded timestamp. * If necessary, this should block until the GPU has finished writing back @@ -130,6 +162,18 @@ typedef uint64_t (*u_trace_read_ts)(struct u_trace_context *utctx, uint64_t offset_B, void *flush_data); +/** + * Driver provided callback to create a buffer which will be read by + * u_trace_read_ts function. + */ +typedef void *(*u_trace_copy_data)(struct u_trace *ut, + void *cs, + void *dst, + uint64_t dst_offset_B, + void *src, + uint64_t src_offset_B, + uint64_t size_B); + /** * Driver provided callback to delete flush data. */ @@ -142,6 +186,7 @@ enum u_trace_type { U_TRACE_TYPE_PERFETTO_ACTIVE = 1u << 2, U_TRACE_TYPE_PERFETTO_ENV = 1u << 3, U_TRACE_TYPE_MARKERS = 1u << 4, + U_TRACE_TYPE_INDIRECTS = 1u << 5, U_TRACE_TYPE_PRINT_JSON = U_TRACE_TYPE_PRINT | U_TRACE_TYPE_JSON, U_TRACE_TYPE_PERFETTO = @@ -170,11 +215,14 @@ struct u_trace_context { u_trace_create_buffer create_buffer; u_trace_delete_buffer delete_buffer; + u_trace_capture_data capture_data; + u_trace_get_data get_data; u_trace_record_ts record_timestamp; u_trace_read_ts read_timestamp; u_trace_delete_flush_data delete_flush_data; uint64_t timestamp_size_bytes; + uint64_t max_indirect_size_bytes; FILE *out; struct u_trace_printer *out_printer; @@ -201,6 +249,8 @@ struct u_trace_context { uint32_t event_nr; bool start_of_frame; + void *dummy_indirect_data; + /* list of unprocessed trace chunks in fifo order: */ struct list_head flushed_trace_chunks; }; @@ -228,10 +278,13 @@ struct u_trace { void u_trace_context_init(struct u_trace_context *utctx, void *pctx, uint32_t timestamp_size_bytes, + uint32_t max_indirect_size_bytes, u_trace_create_buffer create_buffer, u_trace_delete_buffer delete_buffer, u_trace_record_ts record_timestamp, u_trace_read_ts read_timestamp, + u_trace_capture_data capture_data, + u_trace_get_data get_data, u_trace_delete_flush_data delete_flush_data); void u_trace_context_fini(struct u_trace_context *utctx); diff --git a/src/util/perf/u_trace.py b/src/util/perf/u_trace.py index 32c83941165..d0ef6ddf643 100644 --- a/src/util/perf/u_trace.py +++ b/src/util/perf/u_trace.py @@ -59,6 +59,8 @@ class Tracepoint(object): def needs_storage(a): if a.c_format is None: return False + if a.is_indirect: + return False return True self.name = name @@ -81,6 +83,14 @@ class Tracepoint(object): self.has_variable_arg = True break self.tp_print_custom = tp_print + + # Compute the offset of each indirect argument + self.indirect_args = [x for x in args if x.is_indirect] + indirect_sizes = [] + for indirect in self.indirect_args: + indirect.indirect_offset = ' + '.join(indirect_sizes) if len(indirect_sizes) > 0 else 0 + indirect_sizes.append(f"sizeof({indirect.type}") + self.tp_perfetto = tp_perfetto self.tp_markers = tp_markers self.tp_flags = tp_flags @@ -105,7 +115,7 @@ class Tracepoint(object): class TracepointArgStruct(): """Represents struct that is being passed as an argument """ - def __init__(self, type, var, c_format=None, fields=[]): + def __init__(self, type, var, c_format=None, fields=[], is_indirect=False): """Parameters: - type: argument's C type. @@ -117,17 +127,25 @@ class TracepointArgStruct(): self.type = type self.var = var self.name = var + self.is_indirect = is_indirect + self.indirect_offset = 0 self.is_struct = True self.c_format = c_format self.fields = fields self.to_prim_type = None - self.func_param = f"{self.type} {self.var}" + if self.is_indirect: + self.func_param = f"struct u_trace_address {self.var}" + else: + self.func_param = f"{self.type} {self.var}" def value_expr(self, entry_name): ret = None if self.is_struct: - ret = ", ".join([f"{entry_name}->{self.name}.{f}" for f in self.fields]) + if self.is_indirect: + ret = ", ".join([f"__{self.name}->{f}" for f in self.fields]) + else: + ret = ", ".join([f"{entry_name}->{self.name}.{f}" for f in self.fields]) else: ret = f"{entry_name}->{self.name}" return ret @@ -136,7 +154,7 @@ class TracepointArg(object): """Class that represents either an argument being passed or a field in a struct """ def __init__(self, type, var, c_format=None, name=None, to_prim_type=None, - length_arg=None, copy_func=None): + length_arg=None, copy_func=None, is_indirect=False): """Parameters: - type: argument's C type. @@ -162,8 +180,12 @@ class TracepointArg(object): self.copy_func = copy_func self.is_struct = False + self.is_indirect = is_indirect + self.indirect_offset = 0 - if self.type == "str": + if self.is_indirect: + pass + elif self.type == "str": if self.length_arg and self.length_arg.isdigit(): self.struct_member = f"char {self.name}[{length_arg} + 1]" else: @@ -171,13 +193,18 @@ class TracepointArg(object): else: self.struct_member = f"{self.type} {self.name}" - if self.type == "str": + if self.is_indirect: + self.func_param = f"struct u_trace_address {self.var}" + elif self.type == "str": self.func_param = f"const char *{self.var}" else: self.func_param = f"{self.type} {self.var}" def value_expr(self, entry_name): - ret = f"{entry_name}->{self.name}" + if self.is_indirect: + ret = f"*__{self.name}" + else: + ret = f"{entry_name}->{self.name}" if not self.is_struct and self.to_prim_type: ret = self.to_prim_type.format(ret) return ret @@ -298,7 +325,8 @@ void ${trace.tp_perfetto}( uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const struct trace_${trace_name} *payload); + const struct trace_${trace_name} *payload, + const void *indirect_data); #endif % endif void __trace_${trace_name}( @@ -416,11 +444,14 @@ ${trace_toggle_name}_config_variable(void) * ${trace_name} */ % if trace.can_generate_print(): -static void __print_${trace_name}(FILE *out, const void *arg) { +static void __print_${trace_name}(FILE *out, const void *arg, const void *indirect) { % if len(trace.tp_struct) > 0: const struct trace_${trace_name} *__entry = (const struct trace_${trace_name} *)arg; % endif + % for arg in trace.indirect_args: + const ${arg.type} *__${arg.name} = (const ${arg.type} *) ((char *)indirect + ${arg.indirect_offset}); + % endfor % if trace.tp_print_custom is not None: fprintf(out, "${trace.tp_print_custom[0]}\\n" % for arg in trace.tp_print_custom[1:]: @@ -439,11 +470,14 @@ static void __print_${trace_name}(FILE *out, const void *arg) { ); } -static void __print_json_${trace_name}(FILE *out, const void *arg) { +static void __print_json_${trace_name}(FILE *out, const void *arg, const void *indirect) { % if len(trace.tp_struct) > 0: const struct trace_${trace_name} *__entry = (const struct trace_${trace_name} *)arg; % endif + % for arg in trace.indirect_args: + const ${arg.type} *__${arg.var} = (const ${arg.type} *) ((char *)indirect + ${arg.indirect_offset}); + % endfor % if trace.tp_print_custom is not None: fprintf(out, "\\"unstructured\\": \\"${trace.tp_print_custom[0]}\\"" % for arg in trace.tp_print_custom[1:]: @@ -475,26 +509,35 @@ __attribute__((format(printf, 3, 4))) void ${trace.tp_markers}(struct u_trace_co static void __emit_label_${trace_name}(struct u_trace_context *utctx, void *cs, struct trace_${trace_name} *entry) { ${trace.tp_markers}(utctx, cs, "${trace_name}(" % for idx,arg in enumerate(trace.tp_print): + % if not arg.is_indirect: "${"," if idx != 0 else ""}${arg.name}=${arg.c_format}" + % endif % endfor ")" % for arg in trace.tp_print: + % if not arg.is_indirect: ,${arg.value_expr('entry')} + % endif % endfor ); } % endif static const struct u_tracepoint __tp_${trace_name} = { - ALIGN_POT(sizeof(struct trace_${trace_name}), 8), /* keep size 64b aligned */ "${trace_name}", + ALIGN_POT(sizeof(struct trace_${trace_name}), 8), /* keep size 64b aligned */ + 0 + % for arg in trace.indirect_args: + + sizeof(${arg.type}) + % endfor + , ${0 if len(trace.tp_flags) == 0 else " | ".join(trace.tp_flags)}, ${index}, __print_${trace_name}, __print_json_${trace_name}, % if trace.tp_perfetto is not None: #ifdef HAVE_PERFETTO - (void (*)(void *pctx, uint64_t, uint16_t, const void *, const void *))${trace.tp_perfetto}, + (void (*)(void *pctx, uint64_t, uint16_t, const void *, const void *, const void *))${trace.tp_perfetto}, #endif % endif }; @@ -509,9 +552,20 @@ void __trace_${trace_name}( % endfor ) { struct trace_${trace_name} entry; + % if len(trace.indirect_args) > 0: + struct u_trace_address indirects[] = { + % for arg in trace.indirect_args: + ${arg.var}, + % endfor + }; + uint8_t indirect_sizes[] = { + % for arg in trace.indirect_args: + sizeof(${arg.type}), + % endfor + }; + % endif UNUSED struct trace_${trace_name} *__entry = enabled_traces & U_TRACE_TYPE_REQUIRE_QUEUING ? - % if trace.has_variable_arg: (struct trace_${trace_name} *)u_trace_appendv(ut, ${"cs," if trace.need_cs_param else "NULL,"} &__tp_${trace_name}, 0 % for arg in trace.tp_struct: @@ -519,10 +573,13 @@ void __trace_${trace_name}( + ${arg.length_arg} % endif % endfor + , + % if len(trace.indirect_args) > 0: + ARRAY_SIZE(indirects), indirects, indirect_sizes + % else: + 0, NULL, NULL + % endif ) : - % else: - (struct trace_${trace_name} *)u_trace_append(ut, ${"cs," if trace.need_cs_param else "NULL,"} &__tp_${trace_name}) : - % endif &entry; % for arg in trace.tp_struct: % if arg.copy_func is None: @@ -625,7 +682,8 @@ UNUSED static const char *${basename}_names[] = { % for trace_name, trace in TRACEPOINTS.items(): static void UNUSED trace_payload_as_extra_${trace_name}(perfetto::protos::pbzero::GpuRenderStageEvent *event, - const struct trace_${trace_name} *payload) + const struct trace_${trace_name} *payload, + const void *indirect_data) { % if trace.tp_perfetto is not None and len(trace.tp_print) > 0: char buf[128]; @@ -635,6 +693,9 @@ trace_payload_as_extra_${trace_name}(perfetto::protos::pbzero::GpuRenderStageEve auto data = event->add_extra_data(); data->set_name("${arg.name}"); + % if arg.is_indirect: + const ${arg.type}* __${arg.var} = (const ${arg.type}*)((uint8_t *)indirect_data + ${arg.indirect_offset}); + % endif sprintf(buf, "${arg.c_format}", ${arg.value_expr("payload")}); data->set_value(buf); diff --git a/src/util/perf/u_trace_priv.h b/src/util/perf/u_trace_priv.h index 8f76c18075d..258c0f7943a 100644 --- a/src/util/perf/u_trace_priv.h +++ b/src/util/perf/u_trace_priv.h @@ -43,8 +43,15 @@ extern "C" { * Tracepoint descriptor. */ struct u_tracepoint { - unsigned payload_sz; const char *name; + /** + * Size of the CPU data associated with this tracepoint. + */ + uint16_t payload_sz; + /** + * Size of the GPU data associated with this tracepoint. + */ + uint16_t indirect_sz; /** * A bitfield of driver agnostic flags */ @@ -56,8 +63,8 @@ struct u_tracepoint { * to event->set_stage_iid(). */ uint16_t tp_idx; - void (*print)(FILE *out, const void *payload); - void (*print_json)(FILE *out, const void *payload); + void (*print)(FILE *out, const void *payload, const void *indirect); + void (*print_json)(FILE *out, const void *payload, const void *indirect); #ifdef HAVE_PERFETTO /** * Callback to emit a perfetto event, such as render-stage trace @@ -66,7 +73,8 @@ struct u_tracepoint { uint64_t ts_ns, uint16_t tp_idx, const void *flush_data, - const void *payload); + const void *payload, + const void *indirect); #endif }; @@ -77,7 +85,10 @@ struct u_tracepoint { void *u_trace_appendv(struct u_trace *ut, void *cs, const struct u_tracepoint *tp, - unsigned variable_sz); + unsigned variable_sz, + unsigned n_indirects, + const struct u_trace_address *addresses, + const uint8_t *indirect_sizes_B); /** * Append a trace event, returning pointer to buffer of tp->payload_sz @@ -87,7 +98,7 @@ void *u_trace_appendv(struct u_trace *ut, static inline void * u_trace_append(struct u_trace *ut, void *cs, const struct u_tracepoint *tp) { - return u_trace_appendv(ut, cs, tp, 0); + return u_trace_appendv(ut, cs, tp, 0, 0, NULL, NULL); } #ifdef __cplusplus diff --git a/src/util/tests/perf/u_trace_test.cpp b/src/util/tests/perf/u_trace_test.cpp index 34134ec607c..b7d8960416d 100644 --- a/src/util/tests/perf/u_trace_test.cpp +++ b/src/util/tests/perf/u_trace_test.cpp @@ -11,7 +11,8 @@ static int test_thread(void *_state) { struct u_trace_context ctx = {}; - u_trace_context_init(&ctx, NULL, NULL, NULL, NULL, NULL, NULL); + u_trace_context_init(&ctx, NULL, 8, 0, NULL, NULL, NULL, + NULL, NULL, NULL, NULL); u_trace_context_fini(&ctx); return 0;