diff --git a/src/gallium/auxiliary/meson.build b/src/gallium/auxiliary/meson.build index ca272fe428d..1f16c598674 100644 --- a/src/gallium/auxiliary/meson.build +++ b/src/gallium/auxiliary/meson.build @@ -260,7 +260,6 @@ files_libgallium = files( 'util/u_dump_defines.c', 'util/u_dump.h', 'util/u_dump_state.c', - 'util/u_fifo.h', 'util/u_framebuffer.c', 'util/u_framebuffer.h', 'util/u_gen_mipmap.c', @@ -315,9 +314,6 @@ files_libgallium = files( 'util/u_texture.h', 'util/u_tile.c', 'util/u_tile.h', - 'util/u_trace.c', - 'util/u_trace.h', - 'util/u_trace_priv.h', 'util/u_transfer.c', 'util/u_transfer.h', 'util/u_transfer_helper.c', @@ -325,6 +321,8 @@ files_libgallium = files( 'util/u_threaded_context.c', 'util/u_threaded_context.h', 'util/u_threaded_context_calls.h', + 'util/u_trace_gallium.c', + 'util/u_trace_gallium.h', 'util/u_upload_mgr.c', 'util/u_upload_mgr.h', 'util/u_vbuf.c', @@ -484,15 +482,13 @@ if with_dri2 and with_platform_x11 endif endif -u_trace_py = files('util/u_trace.py') - files_libgallium += custom_target( 'u_tracepoints.c', input: 'util/u_tracepoints.py', output: 'u_tracepoints.c', command: [ prog_python, '@INPUT@', - '-p', join_paths(meson.source_root(), 'src/gallium/auxiliary/util/'), + '-p', join_paths(meson.source_root(), 'src/util/perf/'), '-C', '@OUTPUT@', ], depend_files: u_trace_py, @@ -504,7 +500,7 @@ files_u_tracepoints = custom_target( output: 'u_tracepoints.h', command: [ prog_python, '@INPUT@', - '-p', join_paths(meson.source_root(), 'src/gallium/auxiliary/util/'), + '-p', join_paths(meson.source_root(), 'src/util/perf/'), '-H', '@OUTPUT@', ], depend_files: u_trace_py, diff --git a/src/gallium/auxiliary/util/u_trace_gallium.c b/src/gallium/auxiliary/util/u_trace_gallium.c new file mode 100644 index 00000000000..dbc7f4d30cb --- /dev/null +++ b/src/gallium/auxiliary/util/u_trace_gallium.c @@ -0,0 +1,96 @@ +/* + * Copyright © 2020 Google, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "u_trace_gallium.h" +#include "u_inlines.h" +#include "pipe/p_state.h" +#include "pipe/p_context.h" +#include "pipe/p_screen.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static void * +u_trace_pipe_create_ts_buffer(struct u_trace_context *utctx, uint32_t size) +{ + struct pipe_context *ctx = utctx->pctx; + + struct pipe_resource tmpl = { + .target = PIPE_BUFFER, + .format = PIPE_FORMAT_R8_UNORM, + .bind = PIPE_BIND_QUERY_BUFFER | PIPE_BIND_LINEAR, + .width0 = size, + .height0 = 1, + .depth0 = 1, + .array_size = 1, + }; + + return ctx->screen->resource_create(ctx->screen, &tmpl); +} + +static void +u_trace_pipe_delete_ts_buffer(struct u_trace_context *utctx, void *timestamps) +{ + struct pipe_resource *buffer = timestamps; + pipe_resource_reference(&buffer, NULL); +} + +void +u_trace_pipe_context_init(struct u_trace_context *utctx, + struct pipe_context *pctx, + u_trace_record_ts record_timestamp, + u_trace_read_ts read_timestamp, + u_trace_delete_flush_data delete_flush_data) +{ + u_trace_context_init(utctx, pctx, + u_trace_pipe_create_ts_buffer, + u_trace_pipe_delete_ts_buffer, + record_timestamp, + read_timestamp, + delete_flush_data); +} + +void __trace_surface(struct u_trace *ut, const struct pipe_surface *psurf); +void __trace_framebuffer(struct u_trace *ut, const struct pipe_framebuffer_state *pfb); + +inline void +trace_framebuffer_state(struct u_trace *ut, const struct pipe_framebuffer_state *pfb) +{ + if (likely(!ut->enabled)) + return; + + __trace_framebuffer(ut, pfb); + for (unsigned i = 0; i < pfb->nr_cbufs; i++) { + if (pfb->cbufs[i]) { + __trace_surface(ut, pfb->cbufs[i]); + } + } + if (pfb->zsbuf) { + __trace_surface(ut, pfb->zsbuf); + } +} + +#ifdef __cplusplus +} +#endif diff --git a/src/gallium/auxiliary/util/u_trace_gallium.h b/src/gallium/auxiliary/util/u_trace_gallium.h new file mode 100644 index 00000000000..f4df9be9f5c --- /dev/null +++ b/src/gallium/auxiliary/util/u_trace_gallium.h @@ -0,0 +1,57 @@ +/* + * Copyright © 2020 Google, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _U_TRACE_GALLIUM_H +#define _U_TRACE_GALLIUM_H + +#include "util/perf/u_trace.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Gallium specific u_trace helpers */ + +struct pipe_context; +struct pipe_framebuffer_state; + +void +u_trace_pipe_context_init(struct u_trace_context *utctx, + struct pipe_context *pctx, + u_trace_record_ts record_timestamp, + u_trace_read_ts read_timestamp, + u_trace_delete_flush_data delete_flush_data); + +/* + * In some cases it is useful to have composite tracepoints like this, + * to log more complex data structures. + */ + +void +trace_framebuffer_state(struct u_trace *ut, const struct pipe_framebuffer_state *pfb); + +#ifdef __cplusplus +} +#endif + +#endif /* _U_TRACE_GALLIUM_H */ diff --git a/src/gallium/auxiliary/util/u_tracepoints.py b/src/gallium/auxiliary/util/u_tracepoints.py index f8a70d05c09..a9b83215c39 100644 --- a/src/gallium/auxiliary/util/u_tracepoints.py +++ b/src/gallium/auxiliary/util/u_tracepoints.py @@ -89,4 +89,4 @@ Tracepoint('grid_info', '__entry->grid_x', '__entry->grid_y', '__entry->grid_z'], ) -utrace_generate(cpath=args.src, hpath=args.hdr) +utrace_generate(cpath=args.src, hpath=args.hdr, ctx_param='struct pipe_context *pctx') diff --git a/src/gallium/drivers/freedreno/freedreno_batch.h b/src/gallium/drivers/freedreno/freedreno_batch.h index 842537f8c47..7b554c3cceb 100644 --- a/src/gallium/drivers/freedreno/freedreno_batch.h +++ b/src/gallium/drivers/freedreno/freedreno_batch.h @@ -31,7 +31,7 @@ #include "util/simple_mtx.h" #include "util/u_inlines.h" #include "util/u_queue.h" -#include "util/u_trace.h" +#include "util/perf/u_trace.h" #include "freedreno_context.h" #include "freedreno_fence.h" diff --git a/src/gallium/drivers/freedreno/freedreno_context.c b/src/gallium/drivers/freedreno/freedreno_context.c index b0f85e9ffc5..cd95721746c 100644 --- a/src/gallium/drivers/freedreno/freedreno_context.c +++ b/src/gallium/drivers/freedreno/freedreno_context.c @@ -38,6 +38,7 @@ #include "freedreno_state.h" #include "freedreno_texture.h" #include "freedreno_util.h" +#include "util/u_trace_gallium.h" static void fd_context_flush(struct pipe_context *pctx, struct pipe_fence_handle **fencep, @@ -451,30 +452,32 @@ fd_get_device_reset_status(struct pipe_context *pctx) } static void -fd_trace_record_ts(struct u_trace *ut, struct pipe_resource *timestamps, +fd_trace_record_ts(struct u_trace *ut, void *timestamps, unsigned idx) { struct fd_batch *batch = container_of(ut, struct fd_batch, trace); struct fd_ringbuffer *ring = batch->nondraw ? batch->draw : batch->gmem; + struct pipe_resource *buffer = timestamps; if (ring->cur == batch->last_timestamp_cmd) { - uint64_t *ts = fd_bo_map(fd_resource(timestamps)->bo); + uint64_t *ts = fd_bo_map(fd_resource(buffer)->bo); ts[idx] = U_TRACE_NO_TIMESTAMP; return; } unsigned ts_offset = idx * sizeof(uint64_t); - batch->ctx->record_timestamp(ring, fd_resource(timestamps)->bo, ts_offset); + batch->ctx->record_timestamp(ring, fd_resource(buffer)->bo, ts_offset); batch->last_timestamp_cmd = ring->cur; } static uint64_t fd_trace_read_ts(struct u_trace_context *utctx, - struct pipe_resource *timestamps, unsigned idx) + void *timestamps, unsigned idx, void *flush_data) { struct fd_context *ctx = container_of(utctx, struct fd_context, trace_context); - struct fd_bo *ts_bo = fd_resource(timestamps)->bo; + struct pipe_resource *buffer = timestamps; + struct fd_bo *ts_bo = fd_resource(buffer)->bo; /* Only need to stall on results for the first entry: */ if (idx == 0) { @@ -497,6 +500,12 @@ fd_trace_read_ts(struct u_trace_context *utctx, return ctx->ts_to_ns(ts[idx]); } +static void +fd_trace_delete_flush_data(struct u_trace_context *utctx, void *flush_data) +{ + /* We don't use flush_data at the moment. */ +} + /* TODO we could combine a few of these small buffers (solid_vbuf, * blit_texcoord_vbuf, and vsc_size_mem, into a single buffer and * save a tiny bit of memory @@ -667,8 +676,10 @@ fd_context_init(struct fd_context *ctx, struct pipe_screen *pscreen, ctx->current_scissor = &ctx->disabled_scissor; - u_trace_context_init(&ctx->trace_context, pctx, fd_trace_record_ts, - fd_trace_read_ts); + u_trace_pipe_context_init(&ctx->trace_context, pctx, + fd_trace_record_ts, + fd_trace_read_ts, + fd_trace_delete_flush_data); fd_autotune_init(&ctx->autotune, screen->dev); diff --git a/src/gallium/drivers/freedreno/freedreno_context.h b/src/gallium/drivers/freedreno/freedreno_context.h index 6633e7992cf..d07fa618aa2 100644 --- a/src/gallium/drivers/freedreno/freedreno_context.h +++ b/src/gallium/drivers/freedreno/freedreno_context.h @@ -34,7 +34,7 @@ #include "util/u_blitter.h" #include "util/u_string.h" #include "util/u_threaded_context.h" -#include "util/u_trace.h" +#include "util/perf/u_trace.h" #include "freedreno_autotune.h" #include "freedreno_gmem.h" diff --git a/src/gallium/drivers/freedreno/freedreno_gmem.c b/src/gallium/drivers/freedreno/freedreno_gmem.c index 47f4e6f6754..3cf36bef139 100644 --- a/src/gallium/drivers/freedreno/freedreno_gmem.c +++ b/src/gallium/drivers/freedreno/freedreno_gmem.c @@ -33,6 +33,7 @@ #include "util/u_memory.h" #include "util/u_string.h" #include "u_tracepoints.h" +#include "util/u_trace_gallium.h" #include "freedreno_context.h" #include "freedreno_fence.h" @@ -761,7 +762,7 @@ fd_gmem_render_tiles(struct fd_batch *batch) flush_ring(batch); - u_trace_flush(&batch->trace); + u_trace_flush(&batch->trace, NULL, false); } /* Determine a worst-case estimate (ie. assuming we don't eliminate an diff --git a/src/gallium/drivers/freedreno/freedreno_perfetto.cc b/src/gallium/drivers/freedreno/freedreno_perfetto.cc index bc10a510b03..20b7c513edd 100644 --- a/src/gallium/drivers/freedreno/freedreno_perfetto.cc +++ b/src/gallium/drivers/freedreno/freedreno_perfetto.cc @@ -322,6 +322,7 @@ fd_perfetto_submit(struct fd_context *ctx) void fd_start_render_pass(struct pipe_context *pctx, uint64_t ts_ns, + const void *flush_data, const struct trace_start_render_pass *payload) { stage_start(pctx, ts_ns, SURFACE_STAGE_ID); @@ -342,6 +343,7 @@ 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, + const void *flush_data, const struct trace_end_render_pass *payload) { stage_end(pctx, ts_ns, SURFACE_STAGE_ID); @@ -349,6 +351,7 @@ 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, + const void *flush_data, const struct trace_start_binning_ib *payload) { stage_start(pctx, ts_ns, BINNING_STAGE_ID); @@ -356,6 +359,7 @@ 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, + const void *flush_data, const struct trace_end_binning_ib *payload) { stage_end(pctx, ts_ns, BINNING_STAGE_ID); @@ -363,6 +367,7 @@ 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, + const void *flush_data, const struct trace_start_draw_ib *payload) { stage_start( @@ -372,6 +377,7 @@ 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, + const void *flush_data, const struct trace_end_draw_ib *payload) { stage_end( @@ -381,6 +387,7 @@ fd_end_draw_ib(struct pipe_context *pctx, uint64_t ts_ns, void fd_start_blit(struct pipe_context *pctx, uint64_t ts_ns, + const void *flush_data, const struct trace_start_blit *payload) { stage_start(pctx, ts_ns, BLIT_STAGE_ID); @@ -388,6 +395,7 @@ fd_start_blit(struct pipe_context *pctx, uint64_t ts_ns, void fd_end_blit(struct pipe_context *pctx, uint64_t ts_ns, + const void *flush_data, const struct trace_end_blit *payload) { stage_end(pctx, ts_ns, BLIT_STAGE_ID); @@ -395,6 +403,7 @@ fd_end_blit(struct pipe_context *pctx, uint64_t ts_ns, void fd_start_compute(struct pipe_context *pctx, uint64_t ts_ns, + const void *flush_data, const struct trace_start_compute *payload) { stage_start(pctx, ts_ns, COMPUTE_STAGE_ID); @@ -402,6 +411,7 @@ fd_start_compute(struct pipe_context *pctx, uint64_t ts_ns, void fd_end_compute(struct pipe_context *pctx, uint64_t ts_ns, + const void *flush_data, const struct trace_end_compute *payload) { stage_end(pctx, ts_ns, COMPUTE_STAGE_ID); @@ -409,6 +419,7 @@ fd_end_compute(struct pipe_context *pctx, uint64_t ts_ns, void fd_start_clear_restore(struct pipe_context *pctx, uint64_t ts_ns, + const void *flush_data, const struct trace_start_clear_restore *payload) { stage_start(pctx, ts_ns, CLEAR_RESTORE_STAGE_ID); @@ -416,6 +427,7 @@ fd_start_clear_restore(struct pipe_context *pctx, uint64_t ts_ns, void fd_end_clear_restore(struct pipe_context *pctx, uint64_t ts_ns, + const void *flush_data, const struct trace_end_clear_restore *payload) { stage_end(pctx, ts_ns, CLEAR_RESTORE_STAGE_ID); @@ -423,6 +435,7 @@ fd_end_clear_restore(struct pipe_context *pctx, uint64_t ts_ns, void fd_start_resolve(struct pipe_context *pctx, uint64_t ts_ns, + const void *flush_data, const struct trace_start_resolve *payload) { stage_start(pctx, ts_ns, RESOLVE_STAGE_ID); @@ -430,6 +443,7 @@ fd_start_resolve(struct pipe_context *pctx, uint64_t ts_ns, void fd_end_resolve(struct pipe_context *pctx, uint64_t ts_ns, + const void *flush_data, const struct trace_end_resolve *payload) { stage_end(pctx, ts_ns, RESOLVE_STAGE_ID); diff --git a/src/gallium/drivers/freedreno/freedreno_tracepoints.py b/src/gallium/drivers/freedreno/freedreno_tracepoints.py index ea7f01120ce..b0a5a016c6b 100644 --- a/src/gallium/drivers/freedreno/freedreno_tracepoints.py +++ b/src/gallium/drivers/freedreno/freedreno_tracepoints.py @@ -141,4 +141,4 @@ Tracepoint('start_compute', Tracepoint('end_compute', tp_perfetto='fd_end_compute') -utrace_generate(cpath=args.src, hpath=args.hdr) +utrace_generate(cpath=args.src, hpath=args.hdr, ctx_param='struct pipe_context *pctx') diff --git a/src/gallium/drivers/freedreno/meson.build b/src/gallium/drivers/freedreno/meson.build index 6cf833d335b..ed231384501 100644 --- a/src/gallium/drivers/freedreno/meson.build +++ b/src/gallium/drivers/freedreno/meson.build @@ -223,7 +223,7 @@ freedreno_tracepoints = custom_target( output: ['freedreno_tracepoints.c', 'freedreno_tracepoints.h'], command: [ prog_python, '@INPUT@', - '-p', join_paths(meson.source_root(), 'src/gallium/auxiliary/util/'), + '-p', join_paths(meson.source_root(), 'src/util/perf/'), '-C', '@OUTPUT0@', '-H', '@OUTPUT1@', ], diff --git a/src/util/meson.build b/src/util/meson.build index 88f06e23268..1d4f85f889f 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -77,6 +77,9 @@ files_mesa_util = files( 'os_misc.h', 'os_socket.c', 'os_socket.h', + 'perf/u_trace.h', + 'perf/u_trace.c', + 'perf/u_trace_priv.h', 'u_process.c', 'u_process.h', 'u_qsort.cpp', @@ -116,6 +119,7 @@ files_mesa_util = files( 'u_atomic.h', 'u_dynarray.h', 'u_endian.h', + 'u_fifo.h', 'u_queue.c', 'u_queue.h', 'u_string.h', @@ -212,6 +216,8 @@ if with_perfetto deps_for_libmesa_util += dep_perfetto endif +u_trace_py = files('perf/u_trace.py') + _libmesa_util = static_library( 'mesa_util', [files_mesa_util, files_debug_stack, format_srgb], diff --git a/src/gallium/auxiliary/util/u_trace.c b/src/util/perf/u_trace.c similarity index 84% rename from src/gallium/auxiliary/util/u_trace.c rename to src/util/perf/u_trace.c index a3d0ef7824a..4cc783ebbc7 100644 --- a/src/gallium/auxiliary/util/u_trace.c +++ b/src/util/perf/u_trace.c @@ -23,15 +23,12 @@ #include -#include "pipe/p_context.h" -#include "pipe/p_state.h" - #include "util/list.h" #include "util/ralloc.h" #include "util/u_debug.h" #include "util/u_inlines.h" +#include "util/u_fifo.h" -#include "u_fifo.h" #include "u_trace.h" #define __NEEDS_TRACE_PRIV @@ -77,7 +74,7 @@ struct u_trace_chunk { /* table of driver recorded 64b timestamps, index matches index * into traces table */ - struct pipe_resource *timestamps; + void *timestamps; /** * For trace payload, we sub-allocate from ralloc'd buffers which @@ -90,6 +87,14 @@ struct u_trace_chunk { bool last; /* this chunk is last in batch */ bool eof; /* this chunk is last in frame */ + + void *flush_data; /* assigned by u_trace_flush */ + + /** + * Several chunks reference a single flush_data instance thus only + * one chunk should be designated to free the data. + */ + bool free_flush_data; }; static void @@ -97,7 +102,7 @@ free_chunk(void *ptr) { struct u_trace_chunk *chunk = ptr; - pipe_resource_reference(&chunk->timestamps, NULL); + chunk->utctx->delete_timestamp_buffer(chunk->utctx, chunk->timestamps); list_del(&chunk->node); } @@ -134,20 +139,7 @@ get_chunk(struct u_trace *ut) ralloc_set_destructor(chunk, free_chunk); chunk->utctx = ut->utctx; - - struct pipe_resource tmpl = { - .target = PIPE_BUFFER, - .format = PIPE_FORMAT_R8_UNORM, - .bind = PIPE_BIND_QUERY_BUFFER | PIPE_BIND_LINEAR, - .width0 = TIMESTAMP_BUF_SIZE, - .height0 = 1, - .depth0 = 1, - .array_size = 1, - }; - - struct pipe_screen *pscreen = ut->utctx->pctx->screen; - chunk->timestamps = pscreen->resource_create(pscreen, &tmpl); - + chunk->timestamps = ut->utctx->create_timestamp_buffer(ut->utctx, TIMESTAMP_BUF_SIZE); chunk->last = true; list_addtail(&chunk->node, &ut->trace_chunks); @@ -155,8 +147,8 @@ get_chunk(struct u_trace *ut) return chunk; } -DEBUG_GET_ONCE_BOOL_OPTION(trace, "GALLIUM_GPU_TRACE", false) -DEBUG_GET_ONCE_FILE_OPTION(trace_file, "GALLIUM_GPU_TRACEFILE", NULL, "w") +DEBUG_GET_ONCE_BOOL_OPTION(trace, "GPU_TRACE", false) +DEBUG_GET_ONCE_FILE_OPTION(trace_file, "GPU_TRACEFILE", NULL, "w") static FILE * get_tracefile(void) @@ -193,13 +185,19 @@ queue_init(struct u_trace_context *utctx) void u_trace_context_init(struct u_trace_context *utctx, - struct pipe_context *pctx, - u_trace_record_ts record_timestamp, - u_trace_read_ts read_timestamp) + void *pctx, + u_trace_create_ts_buffer create_timestamp_buffer, + u_trace_delete_ts_buffer delete_timestamp_buffer, + u_trace_record_ts record_timestamp, + u_trace_read_ts read_timestamp, + u_trace_delete_flush_data delete_flush_data) { utctx->pctx = pctx; + utctx->create_timestamp_buffer = create_timestamp_buffer; + utctx->delete_timestamp_buffer = delete_timestamp_buffer; utctx->record_timestamp = record_timestamp; - utctx->read_timestamp = read_timestamp; + utctx->read_timestamp = read_timestamp; + utctx->delete_flush_data = delete_flush_data; utctx->last_time_ns = 0; utctx->first_time_ns = 0; @@ -213,7 +211,7 @@ u_trace_context_init(struct u_trace_context *utctx, list_add(&utctx->node, &ctx_list); #endif - if (!(utctx->out || ut_perfetto_enabled)) + if (!u_trace_context_tracing(utctx)) return; queue_init(utctx); @@ -225,7 +223,7 @@ u_trace_context_fini(struct u_trace_context *utctx) #ifdef HAVE_PERFETTO list_del(&utctx->node); #endif - if (!utctx->out) + if (!utctx->queue.jobs) return; util_queue_finish(&utctx->queue); util_queue_destroy(&utctx->queue); @@ -264,7 +262,7 @@ process_chunk(void *job, void *gdata, int thread_index) for (unsigned idx = 0; idx < chunk->num_traces; idx++) { const struct u_trace_event *evt = &chunk->traces[idx]; - uint64_t ns = utctx->read_timestamp(utctx, chunk->timestamps, idx); + uint64_t ns = utctx->read_timestamp(utctx, chunk->timestamps, idx, chunk->flush_data); int32_t delta; if (!utctx->first_time_ns) @@ -291,7 +289,7 @@ process_chunk(void *job, void *gdata, int thread_index) } #ifdef HAVE_PERFETTO if (evt->tp->perfetto) { - evt->tp->perfetto(utctx->pctx, ns, evt->payload); + evt->tp->perfetto(utctx->pctx, ns, chunk->flush_data, evt->payload); } #endif } @@ -306,6 +304,10 @@ process_chunk(void *job, void *gdata, int thread_index) utctx->first_time_ns = 0; } + if (chunk->free_flush_data && utctx->delete_flush_data) { + utctx->delete_flush_data(utctx, chunk->flush_data); + } + if (utctx->out && chunk->eof) { fprintf(utctx->out, "END OF FRAME %u\n", utctx->frame_nr++); } @@ -350,7 +352,7 @@ u_trace_init(struct u_trace *ut, struct u_trace_context *utctx) { ut->utctx = utctx; list_inithead(&ut->trace_chunks); - ut->enabled = !!utctx->out; + ut->enabled = u_trace_context_tracing(utctx); } void @@ -401,8 +403,19 @@ u_trace_append(struct u_trace *ut, const struct u_tracepoint *tp) } void -u_trace_flush(struct u_trace *ut) +u_trace_flush(struct u_trace *ut, void *flush_data, bool free_data) { + list_for_each_entry(struct u_trace_chunk, chunk, &ut->trace_chunks, node) { + chunk->flush_data = flush_data; + chunk->free_flush_data = false; + } + + if (free_data && !list_is_empty(&ut->trace_chunks)) { + struct u_trace_chunk *last_chunk = + list_last_entry(&ut->trace_chunks, struct u_trace_chunk, node); + last_chunk->free_flush_data = true; + } + /* transfer batch's log chunks to context: */ list_splicetail(&ut->trace_chunks, &ut->utctx->flushed_trace_chunks); list_inithead(&ut->trace_chunks); diff --git a/src/gallium/auxiliary/util/u_trace.h b/src/util/perf/u_trace.h similarity index 80% rename from src/gallium/auxiliary/util/u_trace.h rename to src/util/perf/u_trace.h index c44593d7821..f67a359dbfa 100644 --- a/src/gallium/auxiliary/util/u_trace.h +++ b/src/util/perf/u_trace.h @@ -30,9 +30,6 @@ #include "util/u_queue.h" -#include "pipe/p_context.h" -#include "pipe/p_state.h" - #ifdef __cplusplus extern "C" { #endif @@ -73,14 +70,25 @@ struct u_trace_context; struct u_trace; struct u_trace_chunk; -struct pipe_resource; - /** * Special reserved value to indicate that no timestamp was captured, * and that the timestamp of the previous trace should be reused. */ #define U_TRACE_NO_TIMESTAMP ((uint64_t)0) +/** + * Driver provided callback to create a timestamp buffer which will be + * read by u_trace_read_ts function. + */ +typedef void* (*u_trace_create_ts_buffer)(struct u_trace_context *utctx, + uint32_t timestamps_count); + +/** + * Driver provided callback to delete a timestamp buffer. + */ +typedef void (*u_trace_delete_ts_buffer)(struct u_trace_context *utctx, + void *timestamps); + /** * Driver provided callback to emit commands to capture a 64b timestamp * into the specified timestamps buffer, at the specified index. @@ -90,7 +98,7 @@ struct pipe_resource; * GL_TIMESTAMP queries should be appropriate. */ typedef void (*u_trace_record_ts)(struct u_trace *ut, - struct pipe_resource *timestamps, unsigned idx); + void *timestamps, unsigned idx); /** * Driver provided callback to read back a previously recorded timestamp. @@ -98,6 +106,8 @@ typedef void (*u_trace_record_ts)(struct u_trace *ut, * the timestamps. (The timestamps will be read back in order, so it is * safe to only synchronize on idx==0.) * + * flush_data is data provided by the driver via u_trace_flush. + * * The returned timestamp should be in units of nanoseconds. The same * timebase as GL_TIMESTAMP queries should be used. * @@ -109,16 +119,26 @@ typedef void (*u_trace_record_ts)(struct u_trace *ut, * capturing the same timestamp multiple times in a row. */ typedef uint64_t (*u_trace_read_ts)(struct u_trace_context *utctx, - struct pipe_resource *timestamps, unsigned idx); + void *timestamps, unsigned idx, void *flush_data); + +/** + * Driver provided callback to delete flush data. + */ +typedef void (*u_trace_delete_flush_data)(struct u_trace_context *utctx, + void *flush_data); /** * The trace context provides tracking for "in-flight" traces, once the * cmdstream that records timestamps has been flushed. */ struct u_trace_context { - struct pipe_context *pctx; + void *pctx; + + u_trace_create_ts_buffer create_timestamp_buffer; + u_trace_delete_ts_buffer delete_timestamp_buffer; u_trace_record_ts record_timestamp; u_trace_read_ts read_timestamp; + u_trace_delete_flush_data delete_flush_data; FILE *out; @@ -165,9 +185,12 @@ struct u_trace { }; void u_trace_context_init(struct u_trace_context *utctx, - struct pipe_context *pctx, - u_trace_record_ts record_timestamp, - u_trace_read_ts read_timestamp); + void *pctx, + u_trace_create_ts_buffer create_timestamp_buffer, + u_trace_delete_ts_buffer delete_timestamp_buffer, + u_trace_record_ts record_timestamp, + u_trace_read_ts read_timestamp, + u_trace_delete_flush_data delete_flush_data); void u_trace_context_fini(struct u_trace_context *utctx); /** @@ -186,10 +209,16 @@ void u_trace_fini(struct u_trace *ut); * is that all the tracepoints are "executed" by the GPU following any previously * flushed u_trace batch. * + * flush_data is a way for driver to pass additional data, which becomes available + * only at the point of flush, to the u_trace_read_ts callback and perfetto. + * The typical example of such data would be a fence to wait on in u_trace_read_ts, + * and a submission_id to pass into perfetto. + * The destruction of the data is done via u_trace_delete_flush_data. + * * This should typically be called when the corresponding cmdstream (containing * the timestamp reads) is flushed to the kernel. */ -void u_trace_flush(struct u_trace *ut); +void u_trace_flush(struct u_trace *ut, void *flush_data, bool free_data); #ifdef HAVE_PERFETTO extern int ut_perfetto_enabled; @@ -200,30 +229,10 @@ void u_trace_perfetto_stop(void); # define ut_perfetto_enabled 0 #endif -/* - * TODO in some cases it is useful to have composite tracepoints like this, - * to log more complex data structures.. but this is probably not where they - * should live: - */ - -void __trace_surface(struct u_trace *ut, const struct pipe_surface *psurf); -void __trace_framebuffer(struct u_trace *ut, const struct pipe_framebuffer_state *pfb); - -static inline void -trace_framebuffer_state(struct u_trace *ut, const struct pipe_framebuffer_state *pfb) +static inline bool +u_trace_context_tracing(struct u_trace_context *utctx) { - if (likely(!ut->enabled)) - return; - - __trace_framebuffer(ut, pfb); - for (unsigned i = 0; i < pfb->nr_cbufs; i++) { - if (pfb->cbufs[i]) { - __trace_surface(ut, pfb->cbufs[i]); - } - } - if (pfb->zsbuf) { - __trace_surface(ut, pfb->zsbuf); - } + return !!utctx->out || (ut_perfetto_enabled > 0); } #ifdef __cplusplus diff --git a/src/gallium/auxiliary/util/u_trace.py b/src/util/perf/u_trace.py similarity index 91% rename from src/gallium/auxiliary/util/u_trace.py rename to src/util/perf/u_trace.py index 67470a8dd96..e6b74d498e0 100644 --- a/src/gallium/auxiliary/util/u_trace.py +++ b/src/util/perf/u_trace.py @@ -75,6 +75,19 @@ class Header(object): HEADERS.append(self) + +FORWARD_DECLS = [] + +class ForwardDecl(object): + """Class that represents a forward declaration + """ + def __init__(self, decl): + assert isinstance(decl, str) + self.decl = decl + + FORWARD_DECLS.append(self) + + hdr_template = """\ /* Copyright (C) 2020 Google, Inc. * @@ -106,12 +119,16 @@ hdr_template = """\ #include "${header.hdr}" % endfor -#include "util/u_trace.h" +#include "util/perf/u_trace.h" #ifdef __cplusplus extern "C" { #endif +% for declaration in FORWARD_DECLS: +${declaration.decl}; +% endfor + % for trace_name, trace in TRACEPOINTS.items(): /* * ${trace_name} @@ -134,7 +151,7 @@ struct trace_${trace_name} { }; % if trace.tp_perfetto is not None: #ifdef HAVE_PERFETTO -void ${trace.tp_perfetto}(struct pipe_context *pctx, uint64_t ts_ns, const struct trace_${trace_name} *payload); +void ${trace.tp_perfetto}(${ctx_param}, uint64_t ts_ns, const void *flush_data, const struct trace_${trace_name} *payload); #endif % endif void __trace_${trace_name}(struct u_trace *ut @@ -198,7 +215,7 @@ src_template = """\ #include "${hdr}" #define __NEEDS_TRACE_PRIV -#include "util/u_trace_priv.h" +#include "util/perf/u_trace_priv.h" % for trace_name, trace in TRACEPOINTS.items(): /* @@ -223,7 +240,7 @@ static const struct u_tracepoint __tp_${trace_name} = { __print_${trace_name}, % if trace.tp_perfetto is not None: #ifdef HAVE_PERFETTO - (void (*)(struct pipe_context *, uint64_t, const void *))${trace.tp_perfetto}, + (void (*)(void *pctx, uint64_t, const void *, const void *))${trace.tp_perfetto}, #endif % endif }; @@ -243,12 +260,13 @@ void __trace_${trace_name}(struct u_trace *ut % endfor """ -def utrace_generate(cpath, hpath): +def utrace_generate(cpath, hpath, ctx_param): if cpath is not None: hdr = os.path.basename(cpath).rsplit('.', 1)[0] + '.h' with open(cpath, 'w') as f: f.write(Template(src_template).render( hdr=hdr, + ctx_param=ctx_param, HEADERS=HEADERS, TRACEPOINTS=TRACEPOINTS)) @@ -257,5 +275,7 @@ def utrace_generate(cpath, hpath): with open(hpath, 'w') as f: f.write(Template(hdr_template).render( hdrname=hdr.rstrip('.h').upper(), + ctx_param=ctx_param, HEADERS=HEADERS, + FORWARD_DECLS=FORWARD_DECLS, TRACEPOINTS=TRACEPOINTS)) diff --git a/src/gallium/auxiliary/util/u_trace_priv.h b/src/util/perf/u_trace_priv.h similarity index 95% rename from src/gallium/auxiliary/util/u_trace_priv.h rename to src/util/perf/u_trace_priv.h index 3e764ed6e9f..242c63f22e0 100644 --- a/src/gallium/auxiliary/util/u_trace_priv.h +++ b/src/util/perf/u_trace_priv.h @@ -47,7 +47,7 @@ struct u_tracepoint { /** * Callback to emit a perfetto event, such as render-stage trace */ - void (*perfetto)(struct pipe_context *pctx, uint64_t ts_ns, const void *payload); + void (*perfetto)(void *pctx, uint64_t ts_ns, const void *flush_data, const void *payload); #endif }; diff --git a/src/gallium/auxiliary/util/u_fifo.h b/src/util/u_fifo.h similarity index 100% rename from src/gallium/auxiliary/util/u_fifo.h rename to src/util/u_fifo.h