summaryrefslogtreecommitdiff
path: root/src/gallium/auxiliary
diff options
context:
space:
mode:
authorDanylo Piliaiev <dpiliaiev@igalia.com>2021-05-24 12:11:46 +0300
committerDanylo Piliaiev <dpiliaiev@igalia.com>2021-09-10 14:58:28 +0300
commite14f525280ee9f09988239adbead1c9dff5476f0 (patch)
treeed2e284e7c34af41971ee2230165c1166245ddfb /src/gallium/auxiliary
parent9033916d84e11cc8272b89411a9ec74b8f642685 (diff)
util/u_trace: make u_trace usable for other than gallium drivers
With little modifications u_trace could be usable for Vulkan drivers. Beside removing dependencies on gallium, the other notable change is the passing of opaque flush_data pointer via u_trace_flush. There is data which becomes available only at this point which other drivers may want to pass. For example Vulkan drivers would want to pass at least submission id (for perfetto) and a sync object to wait on in u_trace_read_ts. Signed-off-by: Danylo Piliaiev <dpiliaiev@igalia.com> Reviewed-by: Rob Clark <robdclark@chromium.org> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10969>
Diffstat (limited to 'src/gallium/auxiliary')
-rw-r--r--src/gallium/auxiliary/meson.build12
-rw-r--r--src/gallium/auxiliary/util/u_fifo.h94
-rw-r--r--src/gallium/auxiliary/util/u_trace.c409
-rw-r--r--src/gallium/auxiliary/util/u_trace.h233
-rw-r--r--src/gallium/auxiliary/util/u_trace.py261
-rw-r--r--src/gallium/auxiliary/util/u_trace_gallium.c96
-rw-r--r--src/gallium/auxiliary/util/u_trace_gallium.h (renamed from src/gallium/auxiliary/util/u_trace_priv.h)51
-rw-r--r--src/gallium/auxiliary/util/u_tracepoints.py2
8 files changed, 125 insertions, 1033 deletions
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_fifo.h b/src/gallium/auxiliary/util/u_fifo.h
deleted file mode 100644
index b53a3ddd52d..00000000000
--- a/src/gallium/auxiliary/util/u_fifo.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/**************************************************************************
- *
- * Copyright © 2009 Jakob Bornecrantz
- *
- * 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_FIFO_H
-#define U_FIFO_H
-
-#include "util/u_memory.h"
-
-struct util_fifo
-{
- size_t head;
- size_t tail;
- size_t num;
- size_t size;
-};
-
-static inline struct util_fifo *
-u_fifo_create(size_t size)
-{
- struct util_fifo *fifo;
- fifo = MALLOC(sizeof(*fifo) + size * sizeof(void*));
-
- fifo->head = 0;
- fifo->tail = 0;
- fifo->num = 0;
- fifo->size = size;
-
- return fifo;
-}
-
-static inline boolean
-u_fifo_add(struct util_fifo *fifo, void *ptr)
-{
- void **array = (void**)&fifo[1];
- if (fifo->num >= fifo->size)
- return FALSE;
-
- if (++fifo->head >= fifo->size)
- fifo->head = 0;
-
- array[fifo->head] = ptr;
-
- ++fifo->num;
-
- return TRUE;
-}
-
-static inline boolean
-u_fifo_pop(struct util_fifo *fifo, void **ptr)
-{
- void **array = (void**)&fifo[1];
-
- if (!fifo->num)
- return FALSE;
-
- if (++fifo->tail >= fifo->size)
- fifo->tail = 0;
-
- *ptr = array[fifo->tail];
-
- --fifo->num;
-
- return TRUE;
-}
-
-static inline void
-u_fifo_destroy(struct util_fifo *fifo)
-{
- FREE(fifo);
-}
-
-#endif
diff --git a/src/gallium/auxiliary/util/u_trace.c b/src/gallium/auxiliary/util/u_trace.c
deleted file mode 100644
index a3d0ef7824a..00000000000
--- a/src/gallium/auxiliary/util/u_trace.c
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * 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 <inttypes.h>
-
-#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 "u_fifo.h"
-#include "u_trace.h"
-
-#define __NEEDS_TRACE_PRIV
-#include "u_trace_priv.h"
-
-#define TIMESTAMP_BUF_SIZE 0x1000
-#define TRACES_PER_CHUNK (TIMESTAMP_BUF_SIZE / sizeof(uint64_t))
-
-#ifdef HAVE_PERFETTO
-int ut_perfetto_enabled;
-
-/**
- * Global list of contexts, so we can defer starting the queue until
- * perfetto tracing is started.
- *
- * TODO locking
- */
-struct list_head ctx_list = { &ctx_list, &ctx_list };
-#endif
-
-struct u_trace_event {
- const struct u_tracepoint *tp;
- const void *payload;
-};
-
-/**
- * A "chunk" of trace-events and corresponding timestamp buffer. As
- * trace events are emitted, additional trace chucks will be allocated
- * as needed. When u_trace_flush() is called, they are transferred
- * from the u_trace to the u_trace_context queue.
- */
-struct u_trace_chunk {
- struct list_head node;
-
- struct u_trace_context *utctx;
-
- /* The number of traces this chunk contains so far: */
- unsigned num_traces;
-
- /* table of trace events: */
- struct u_trace_event traces[TRACES_PER_CHUNK];
-
- /* table of driver recorded 64b timestamps, index matches index
- * into traces table
- */
- struct pipe_resource *timestamps;
-
- /**
- * For trace payload, we sub-allocate from ralloc'd buffers which
- * hang off of the chunk's ralloc context, so they are automatically
- * free'd when the chunk is free'd
- */
- uint8_t *payload_buf, *payload_end;
-
- struct util_queue_fence fence;
-
- bool last; /* this chunk is last in batch */
- bool eof; /* this chunk is last in frame */
-};
-
-static void
-free_chunk(void *ptr)
-{
- struct u_trace_chunk *chunk = ptr;
-
- pipe_resource_reference(&chunk->timestamps, NULL);
-
- list_del(&chunk->node);
-}
-
-static void
-free_chunks(struct list_head *chunks)
-{
- while (!list_is_empty(chunks)) {
- struct u_trace_chunk *chunk = list_first_entry(chunks,
- struct u_trace_chunk, node);
- ralloc_free(chunk);
- }
-}
-
-static struct u_trace_chunk *
-get_chunk(struct u_trace *ut)
-{
- struct u_trace_chunk *chunk;
-
- /* do we currently have a non-full chunk to append msgs to? */
- if (!list_is_empty(&ut->trace_chunks)) {
- chunk = list_last_entry(&ut->trace_chunks,
- struct u_trace_chunk, node);
- if (chunk->num_traces < TRACES_PER_CHUNK)
- return chunk;
- /* we need to expand to add another chunk to the batch, so
- * the current one is no longer the last one of the batch:
- */
- chunk->last = false;
- }
-
- /* .. if not, then create a new one: */
- chunk = rzalloc_size(NULL, sizeof(*chunk));
- 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->last = true;
-
- list_addtail(&chunk->node, &ut->trace_chunks);
-
- return chunk;
-}
-
-DEBUG_GET_ONCE_BOOL_OPTION(trace, "GALLIUM_GPU_TRACE", false)
-DEBUG_GET_ONCE_FILE_OPTION(trace_file, "GALLIUM_GPU_TRACEFILE", NULL, "w")
-
-static FILE *
-get_tracefile(void)
-{
- static FILE *tracefile = NULL;
- static bool firsttime = true;
-
- if (firsttime) {
- tracefile = debug_get_option_trace_file();
- if (!tracefile && debug_get_option_trace()) {
- tracefile = stdout;
- }
-
- firsttime = false;
- }
-
- return tracefile;
-}
-
-static void
-queue_init(struct u_trace_context *utctx)
-{
- if (utctx->queue.jobs)
- return;
-
- bool ret = util_queue_init(&utctx->queue, "traceq", 256, 1,
- UTIL_QUEUE_INIT_USE_MINIMUM_PRIORITY |
- UTIL_QUEUE_INIT_RESIZE_IF_FULL, NULL);
- assert(ret);
-
- if (!ret)
- utctx->out = NULL;
-}
-
-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)
-{
- utctx->pctx = pctx;
- utctx->record_timestamp = record_timestamp;
- utctx->read_timestamp = read_timestamp;
-
- utctx->last_time_ns = 0;
- utctx->first_time_ns = 0;
- utctx->frame_nr = 0;
-
- list_inithead(&utctx->flushed_trace_chunks);
-
- utctx->out = get_tracefile();
-
-#ifdef HAVE_PERFETTO
- list_add(&utctx->node, &ctx_list);
-#endif
-
- if (!(utctx->out || ut_perfetto_enabled))
- return;
-
- queue_init(utctx);
-}
-
-void
-u_trace_context_fini(struct u_trace_context *utctx)
-{
-#ifdef HAVE_PERFETTO
- list_del(&utctx->node);
-#endif
- if (!utctx->out)
- return;
- util_queue_finish(&utctx->queue);
- util_queue_destroy(&utctx->queue);
- fflush(utctx->out);
- free_chunks(&utctx->flushed_trace_chunks);
-}
-
-#ifdef HAVE_PERFETTO
-void
-u_trace_perfetto_start(void)
-{
- list_for_each_entry (struct u_trace_context, utctx, &ctx_list, node)
- queue_init(utctx);
- ut_perfetto_enabled++;
-}
-
-void
-u_trace_perfetto_stop(void)
-{
- assert(ut_perfetto_enabled > 0);
- ut_perfetto_enabled--;
-}
-#endif
-
-static void
-process_chunk(void *job, void *gdata, int thread_index)
-{
- struct u_trace_chunk *chunk = job;
- struct u_trace_context *utctx = chunk->utctx;
-
- /* For first chunk of batch, accumulated times will be zerod: */
- if (utctx->out && !utctx->last_time_ns) {
- fprintf(utctx->out, "+----- NS -----+ +-- Δ --+ +----- MSG -----\n");
- }
-
- 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);
- int32_t delta;
-
- if (!utctx->first_time_ns)
- utctx->first_time_ns = ns;
-
- if (ns != U_TRACE_NO_TIMESTAMP) {
- delta = utctx->last_time_ns ? ns - utctx->last_time_ns : 0;
- utctx->last_time_ns = ns;
- } else {
- /* we skipped recording the timestamp, so it should be
- * the same as last msg:
- */
- ns = utctx->last_time_ns;
- delta = 0;
- }
-
- if (utctx->out) {
- if (evt->tp->print) {
- fprintf(utctx->out, "%016"PRIu64" %+9d: %s: ", ns, delta, evt->tp->name);
- evt->tp->print(utctx->out, evt->payload);
- } else {
- fprintf(utctx->out, "%016"PRIu64" %+9d: %s\n", ns, delta, evt->tp->name);
- }
- }
-#ifdef HAVE_PERFETTO
- if (evt->tp->perfetto) {
- evt->tp->perfetto(utctx->pctx, ns, evt->payload);
- }
-#endif
- }
-
- if (chunk->last) {
- if (utctx->out) {
- uint64_t elapsed = utctx->last_time_ns - utctx->first_time_ns;
- fprintf(utctx->out, "ELAPSED: %"PRIu64" ns\n", elapsed);
- }
-
- utctx->last_time_ns = 0;
- utctx->first_time_ns = 0;
- }
-
- if (utctx->out && chunk->eof) {
- fprintf(utctx->out, "END OF FRAME %u\n", utctx->frame_nr++);
- }
-}
-
-static void
-cleanup_chunk(void *job, void *gdata, int thread_index)
-{
- ralloc_free(job);
-}
-
-void
-u_trace_context_process(struct u_trace_context *utctx, bool eof)
-{
- struct list_head *chunks = &utctx->flushed_trace_chunks;
-
- if (list_is_empty(chunks))
- return;
-
- struct u_trace_chunk *last_chunk = list_last_entry(chunks,
- struct u_trace_chunk, node);
- last_chunk->eof = eof;
-
- while (!list_is_empty(chunks)) {
- struct u_trace_chunk *chunk = list_first_entry(chunks,
- struct u_trace_chunk, node);
-
- /* remove from list before enqueuing, because chunk is freed
- * once it is processed by the queue:
- */
- list_delinit(&chunk->node);
-
- util_queue_add_job(&utctx->queue, chunk, &chunk->fence,
- process_chunk, cleanup_chunk,
- TIMESTAMP_BUF_SIZE);
- }
-}
-
-
-void
-u_trace_init(struct u_trace *ut, struct u_trace_context *utctx)
-{
- ut->utctx = utctx;
- list_inithead(&ut->trace_chunks);
- ut->enabled = !!utctx->out;
-}
-
-void
-u_trace_fini(struct u_trace *ut)
-{
- /* Normally the list of trace-chunks would be empty, if they
- * have been flushed to the trace-context.
- */
- free_chunks(&ut->trace_chunks);
-}
-
-/**
- * Append a trace event, returning pointer to buffer of tp->payload_sz
- * to be filled in with trace payload. Called by generated tracepoint
- * functions.
- */
-void *
-u_trace_append(struct u_trace *ut, const struct u_tracepoint *tp)
-{
- struct u_trace_chunk *chunk = get_chunk(ut);
-
- assert(tp->payload_sz == ALIGN_NPOT(tp->payload_sz, 8));
-
- if (unlikely((chunk->payload_buf + tp->payload_sz) > chunk->payload_end)) {
- const unsigned payload_chunk_sz = 0x100; /* TODO arbitrary size? */
-
- assert(tp->payload_sz < payload_chunk_sz);
-
- chunk->payload_buf = ralloc_size(chunk, payload_chunk_sz);
- chunk->payload_end = chunk->payload_buf + payload_chunk_sz;
- }
-
- /* sub-allocate storage for trace payload: */
- void *payload = chunk->payload_buf;
- chunk->payload_buf += tp->payload_sz;
-
- /* record a timestamp for the trace: */
- ut->utctx->record_timestamp(ut, chunk->timestamps, chunk->num_traces);
-
- chunk->traces[chunk->num_traces] = (struct u_trace_event) {
- .tp = tp,
- .payload = payload,
- };
-
- chunk->num_traces++;
-
- return payload;
-}
-
-void
-u_trace_flush(struct u_trace *ut)
-{
- /* 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/gallium/auxiliary/util/u_trace.h
deleted file mode 100644
index c44593d7821..00000000000
--- a/src/gallium/auxiliary/util/u_trace.h
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * 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_H
-#define _U_TRACE_H
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include "util/u_queue.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_state.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* A trace mechanism (very) loosely inspired by the linux kernel tracepoint
- * mechanism, in that it allows for defining driver specific (or common)
- * tracepoints, which generate 'trace_$name()' functions that can be
- * called at various points in commandstream emit.
- *
- * Currently a printf backend is implemented, but the expectation is to
- * also implement a perfetto backend for shipping out traces to a tool like
- * AGI.
- *
- * Notable differences:
- *
- * - GPU timestamps! A driver provided callback is used to emit timestamps
- * to a buffer. At a later point in time (when stalling to wait for the
- * GPU is not required), the timestamps are re-united with the trace
- * payload. This makes the trace mechanism suitable for profiling.
- *
- * - Instead of a systemwide trace ringbuffer, buffering of un-retired
- * tracepoints is split into two stages. Traces are emitted to a
- * 'u_trace' instance, and at a later time flushed to a 'u_trace_context'
- * instance. This avoids the requirement that commandstream containing
- * tracepoints is emitted in the same order as it is generated.
- *
- * If the hw has multiple parallel "engines" (for example, 3d/blit/compute)
- * then a `u_trace_context` per-engine should be used.
- *
- * - Unlike kernel tracepoints, u_trace tracepoints are defined in py
- * from which header and src files are generated. Since we already have
- * a build dependency on python+mako, this gives more flexibility than
- * clunky preprocessor macro magic.
- *
- */
-
-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 emit commands to capture a 64b timestamp
- * into the specified timestamps buffer, at the specified index.
- *
- * The hw counter that the driver records should be something that runs at
- * a fixed rate, even as the GPU freq changes. The same source used for
- * GL_TIMESTAMP queries should be appropriate.
- */
-typedef void (*u_trace_record_ts)(struct u_trace *ut,
- struct pipe_resource *timestamps, unsigned idx);
-
-/**
- * Driver provided callback to read back a previously recorded timestamp.
- * If necessary, this should block until the GPU has finished writing back
- * the timestamps. (The timestamps will be read back in order, so it is
- * safe to only synchronize on idx==0.)
- *
- * The returned timestamp should be in units of nanoseconds. The same
- * timebase as GL_TIMESTAMP queries should be used.
- *
- * The driver can return the special U_TRACE_NO_TIMESTAMP value to indicate
- * that no timestamp was captured and the timestamp from the previous trace
- * will be re-used. (The first trace in the u_trace buf may not do this.)
- * This allows the driver to detect cases where multiple tracepoints are
- * emitted with no other intervening cmdstream, to avoid pointlessly
- * 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);
-
-/**
- * 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;
- u_trace_record_ts record_timestamp;
- u_trace_read_ts read_timestamp;
-
- FILE *out;
-
- /* Once u_trace_flush() is called u_trace_chunk's are queued up to
- * render tracepoints on a queue. The per-chunk queue jobs block until
- * timestamps are available.
- */
- struct util_queue queue;
-
-#ifdef HAVE_PERFETTO
- /* node in global list of trace contexts. */
- struct list_head node;
-#endif
-
- /* State to accumulate time across N chunks associated with a single
- * batch (u_trace).
- */
- uint64_t last_time_ns;
- uint64_t first_time_ns;
-
- uint32_t frame_nr;
-
- /* list of unprocessed trace chunks in fifo order: */
- struct list_head flushed_trace_chunks;
-};
-
-/**
- * The u_trace ptr is passed as the first arg to generated tracepoints.
- * It provides buffering for tracepoint payload until the corresponding
- * driver cmdstream containing the emitted commands to capture is
- * flushed.
- *
- * Individual tracepoints emitted to u_trace are expected to be "executed"
- * (ie. timestamp captured) in FIFO order with respect to other tracepoints
- * emitted to the same u_trace. But the order WRT other u_trace instances
- * is undefined util u_trace_flush().
- */
-struct u_trace {
- struct u_trace_context *utctx;
-
- struct list_head trace_chunks; /* list of unflushed trace chunks in fifo order */
-
- bool enabled;
-};
-
-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 u_trace_context_fini(struct u_trace_context *utctx);
-
-/**
- * Flush (trigger processing) of traces previously flushed to the trace-context
- * by u_trace_flush().
- *
- * This should typically be called in the driver's pctx->flush().
- */
-void u_trace_context_process(struct u_trace_context *utctx, bool eof);
-
-void u_trace_init(struct u_trace *ut, struct u_trace_context *utctx);
-void u_trace_fini(struct u_trace *ut);
-
-/**
- * Flush traces to the parent trace-context. At this point, the expectation
- * is that all the tracepoints are "executed" by the GPU following any previously
- * flushed u_trace batch.
- *
- * 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);
-
-#ifdef HAVE_PERFETTO
-extern int ut_perfetto_enabled;
-
-void u_trace_perfetto_start(void);
-void u_trace_perfetto_stop(void);
-#else
-# 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)
-{
- 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
-
-#endif /* _U_TRACE_H */
diff --git a/src/gallium/auxiliary/util/u_trace.py b/src/gallium/auxiliary/util/u_trace.py
deleted file mode 100644
index 67470a8dd96..00000000000
--- a/src/gallium/auxiliary/util/u_trace.py
+++ /dev/null
@@ -1,261 +0,0 @@
-#
-# Copyright (C) 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.
-#
-
-from mako.template import Template
-import os
-
-TRACEPOINTS = {}
-
-class Tracepoint(object):
- """Class that represents all the information about a tracepoint
- """
- def __init__(self, name, args=[], tp_struct=None, tp_print=None, tp_perfetto=None):
- """Parameters:
-
- - name: the tracepoint name, a tracepoint function with the given
- name (prefixed by 'trace_') will be generated with the specied
- args (following a u_trace ptr). Calling this tracepoint will
- emit a trace, if tracing is enabled.
- - args: the tracepoint func args, an array of [type, name] pairs
- - tp_struct: (optional) array of [type, name, expr] tuples to
- convert from tracepoint args to trace payload. If not specified
- it will be generated from `args` (ie, [type, name, name])
- - tp_print: (optional) array of format string followed by expressions
- - tp_perfetto: (optional) driver provided callback which can generate
- perfetto events
- """
- assert isinstance(name, str)
- assert isinstance(args, list)
- assert name not in TRACEPOINTS
-
- self.name = name
- self.args = args
- if tp_struct is None:
- tp_struct = []
- for arg in args:
- tp_struct.append([arg[0], arg[1], arg[1]])
- self.tp_struct = tp_struct
- self.tp_print = tp_print
- self.tp_perfetto = tp_perfetto
-
- TRACEPOINTS[name] = self
-
-HEADERS = []
-
-class Header(object):
- """Class that represents a header file dependency of generated tracepoints
- """
- def __init__(self, hdr):
- """Parameters:
-
- - hdr: the required header path
- """
- assert isinstance(hdr, str)
- self.hdr = hdr
-
- HEADERS.append(self)
-
-hdr_template = """\
-/* Copyright (C) 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.
- */
-
-<% guard_name = '_' + hdrname + '_H' %>
-#ifndef ${guard_name}
-#define ${guard_name}
-
-% for header in HEADERS:
-#include "${header.hdr}"
-% endfor
-
-#include "util/u_trace.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-% for trace_name, trace in TRACEPOINTS.items():
-/*
- * ${trace_name}
- */
-struct trace_${trace_name} {
-% for member in trace.tp_struct:
- ${member[0]} ${member[1]};
-% endfor
-% if len(trace.tp_struct) == 0:
-#ifdef __cplusplus
- /* avoid warnings about empty struct size mis-match in C vs C++..
- * the size mis-match is harmless because (a) nothing will deref
- * the empty struct, and (b) the code that cares about allocating
- * sizeof(struct trace_${trace_name}) (and wants this to be zero
- * if there is no payload) is C
- */
- uint8_t dummy;
-#endif
-% endif
-};
-% 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);
-#endif
-% endif
-void __trace_${trace_name}(struct u_trace *ut
-% for arg in trace.args:
- , ${arg[0]} ${arg[1]}
-% endfor
-);
-static inline void trace_${trace_name}(struct u_trace *ut
-% for arg in trace.args:
- , ${arg[0]} ${arg[1]}
-% endfor
-) {
-% if trace.tp_perfetto is not None:
- if (!unlikely(ut->enabled || ut_perfetto_enabled))
-% else:
- if (!unlikely(ut->enabled))
-% endif
- return;
- __trace_${trace_name}(ut
-% for arg in trace.args:
- , ${arg[1]}
-% endfor
- );
-}
-% endfor
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* ${guard_name} */
-"""
-
-src_template = """\
-/* Copyright (C) 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.
- */
-
-% for header in HEADERS:
-#include "${header.hdr}"
-% endfor
-
-#include "${hdr}"
-
-#define __NEEDS_TRACE_PRIV
-#include "util/u_trace_priv.h"
-
-% for trace_name, trace in TRACEPOINTS.items():
-/*
- * ${trace_name}
- */
-% if trace.tp_print is not None:
-static void __print_${trace_name}(FILE *out, const void *arg) {
- const struct trace_${trace_name} *__entry =
- (const struct trace_${trace_name} *)arg;
- fprintf(out, "${trace.tp_print[0]}\\n"
-% for arg in trace.tp_print[1:]:
- , ${arg}
-% endfor
- );
-}
-% else:
-#define __print_${trace_name} NULL
-% endif
-static const struct u_tracepoint __tp_${trace_name} = {
- ALIGN_POT(sizeof(struct trace_${trace_name}), 8), /* keep size 64b aligned */
- "${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},
-#endif
-% endif
-};
-void __trace_${trace_name}(struct u_trace *ut
-% for arg in trace.args:
- , ${arg[0]} ${arg[1]}
-% endfor
-) {
- struct trace_${trace_name} *__entry =
- (struct trace_${trace_name} *)u_trace_append(ut, &__tp_${trace_name});
- (void)__entry;
-% for member in trace.tp_struct:
- __entry->${member[1]} = ${member[2]};
-% endfor
-}
-
-% endfor
-"""
-
-def utrace_generate(cpath, hpath):
- 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,
- HEADERS=HEADERS,
- TRACEPOINTS=TRACEPOINTS))
-
- if hpath is not None:
- hdr = os.path.basename(hpath)
- with open(hpath, 'w') as f:
- f.write(Template(hdr_template).render(
- hdrname=hdr.rstrip('.h').upper(),
- HEADERS=HEADERS,
- TRACEPOINTS=TRACEPOINTS))
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_priv.h b/src/gallium/auxiliary/util/u_trace_gallium.h
index 3e764ed6e9f..f4df9be9f5c 100644
--- a/src/gallium/auxiliary/util/u_trace_priv.h
+++ b/src/gallium/auxiliary/util/u_trace_gallium.h
@@ -21,40 +21,37 @@
* SOFTWARE.
*/
-#ifndef __NEEDS_TRACE_PRIV
-# error "Do not use this header!"
+#ifndef _U_TRACE_GALLIUM_H
+#define _U_TRACE_GALLIUM_H
+
+#include "util/perf/u_trace.h"
+
+#ifdef __cplusplus
+extern "C" {
#endif
-#ifndef _U_TRACE_PRIV_H
-#define _U_TRACE_PRIV_H
+/* Gallium specific u_trace helpers */
-#include <stdio.h>
+struct pipe_context;
+struct pipe_framebuffer_state;
-#include "u_trace.h"
+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);
/*
- * Internal interface used by generated tracepoints
+ * In some cases it is useful to have composite tracepoints like this,
+ * to log more complex data structures.
*/
-/**
- * Tracepoint descriptor.
- */
-struct u_tracepoint {
- unsigned payload_sz;
- const char *name;
- void (*print)(FILE *out, const void *payload);
-#ifdef HAVE_PERFETTO
- /**
- * Callback to emit a perfetto event, such as render-stage trace
- */
- void (*perfetto)(struct pipe_context *pctx, uint64_t ts_ns, const void *payload);
-#endif
-};
+void
+trace_framebuffer_state(struct u_trace *ut, const struct pipe_framebuffer_state *pfb);
-/**
- * Append a tracepoint, returning pointer that can be filled with trace
- * payload.
- */
-void * u_trace_append(struct u_trace *ut, const struct u_tracepoint *tp);
+#ifdef __cplusplus
+}
+#endif
-#endif /* _U_TRACE_PRIV_H */
+#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')