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 <lionel.g.landwerlin@intel.com>
Co-Authored-by: Danylo Piliaiev <dpiliaiev@igalia.com>
Reviewed-by: Danylo Piliaiev <dpiliaiev@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/29944>
This commit is contained in:
Lionel Landwerlin 2024-06-26 20:37:28 +03:00 committed by Lionel Landwerlin
parent cb27b9541b
commit 0a17035b5c
18 changed files with 333 additions and 80 deletions

View File

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

View File

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

View File

@ -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.

View File

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

View File

@ -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);
/*

View File

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

View File

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

View File

@ -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++) {

View File

@ -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, \

View File

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

View File

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

View File

@ -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++) {

View File

@ -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++) {

View File

@ -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,

View File

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

View File

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

View File

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

View File

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