freedreno: Add GPU tracepoints

Add support for u_trace, and freedreno tracepoints.

Signed-off-by: Rob Clark <robdclark@chromium.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7818>
This commit is contained in:
Rob Clark 2020-11-30 08:38:18 -08:00 committed by Marge Bot
parent 7a70f28de2
commit a02dcb970f
11 changed files with 246 additions and 2 deletions

View File

@ -32,6 +32,7 @@
#include "freedreno_fence.h"
#include "freedreno_log.h"
#include "freedreno_resource.h"
#include "freedreno_tracepoints.h"
#include "fd6_blitter.h"
#include "fd6_format.h"
@ -823,6 +824,8 @@ handle_rgba_blit(struct fd_context *ctx, const struct pipe_blit_info *info)
emit_setup(batch);
trace_start_blit(&batch->trace, info->src.resource->target, info->dst.resource->target);
if ((info->src.resource->target == PIPE_BUFFER) &&
(info->dst.resource->target == PIPE_BUFFER)) {
assert(fd_resource(info->src.resource)->layout.tile_mode == TILE6_LINEAR);
@ -839,6 +842,8 @@ handle_rgba_blit(struct fd_context *ctx, const struct pipe_blit_info *info)
fd_log(batch, "END BLIT (TEXTURE)");
}
trace_end_blit(&batch->trace);
fd6_event_write(batch, batch->draw, PC_CCU_FLUSH_COLOR_TS, true);
fd6_event_write(batch, batch->draw, PC_CCU_FLUSH_DEPTH_TS, true);
fd6_event_write(batch, batch->draw, CACHE_FLUSH_TS, true);

View File

@ -26,9 +26,11 @@
#include "pipe/p_state.h"
#include "util/u_dump.h"
#include "u_tracepoints.h"
#include "freedreno_log.h"
#include "freedreno_resource.h"
#include "freedreno_tracepoints.h"
#include "fd6_compute.h"
#include "fd6_const.h"
@ -192,6 +194,9 @@ fd6_launch_grid(struct fd_context *ctx, const struct pipe_grid_info *info)
OUT_RING(ring, 1); /* HLSQ_CS_KERNEL_GROUP_Y */
OUT_RING(ring, 1); /* HLSQ_CS_KERNEL_GROUP_Z */
trace_grid_info(&ctx->batch->trace, info);
trace_start_compute(&ctx->batch->trace);
fd_log(ctx->batch, "COMPUTE: START");
fd_log_stream(ctx->batch, stream, util_dump_grid_info(stream, info));
@ -212,6 +217,8 @@ fd6_launch_grid(struct fd_context *ctx, const struct pipe_grid_info *info)
OUT_RING(ring, CP_EXEC_CS_3_NGROUPS_Z(info->grid[2]));
}
trace_end_compute(&ctx->batch->trace);
fd_log(ctx->batch, "COMPUTE: END");
OUT_WFI5(ring);
fd_log(ctx->batch, "..");

View File

@ -35,6 +35,7 @@
#include "freedreno_log.h"
#include "freedreno_resource.h"
#include "freedreno_state.h"
#include "freedreno_tracepoints.h"
#include "freedreno_query_hw.h"
#include "common/freedreno_guardband.h"
@ -1176,6 +1177,7 @@ fd6_emit_restore(struct fd_batch *batch, struct fd_ringbuffer *ring)
if (!batch->nondraw) {
fd_log(batch, "START RESTORE");
trace_start_state_restore(&batch->trace);
}
fd6_cache_inv(batch, ring);
@ -1293,6 +1295,7 @@ fd6_emit_restore(struct fd_batch *batch, struct fd_ringbuffer *ring)
OUT_RING(ring, 0x00000000);
if (!batch->nondraw) {
trace_end_state_restore(&batch->trace);
fd_log(batch, "END RESTORE");
}
}

View File

@ -37,6 +37,7 @@
#include "freedreno_log.h"
#include "freedreno_state.h"
#include "freedreno_resource.h"
#include "freedreno_tracepoints.h"
#include "fd6_blitter.h"
#include "fd6_gmem.h"
@ -577,7 +578,9 @@ emit_binning_pass(struct fd_batch *batch)
/* emit IB to binning drawcmds: */
fd_log(batch, "GMEM: START BINNING IB");
trace_start_binning_ib(&batch->trace);
fd6_emit_ib(ring, batch->draw);
trace_end_binning_ib(&batch->trace);
fd_log(batch, "GMEM: END BINNING IB");
fd_reset_wfi(batch);
@ -599,7 +602,9 @@ emit_binning_pass(struct fd_batch *batch)
OUT_PKT7(ring, CP_WAIT_FOR_ME, 0);
fd_log(batch, "START VSC OVERFLOW TEST");
trace_start_vsc_overflow_test(&batch->trace);
emit_vsc_overflow_test(batch);
trace_end_vsc_overflow_test(&batch->trace);
fd_log(batch, "END VSC OVERFLOW TEST");
OUT_PKT7(ring, CP_SET_VISIBILITY_OVERRIDE, 1);
@ -658,7 +663,9 @@ fd6_emit_tile_init(struct fd_batch *batch)
if (batch->prologue) {
fd_log(batch, "START PROLOGUE");
trace_start_prologue(&batch->trace);
fd6_emit_ib(ring, batch->prologue);
trace_end_prologue(&batch->trace);
fd_log(batch, "END PROLOGUE");
}
@ -1119,11 +1126,13 @@ fd6_emit_tile_renderprep(struct fd_batch *batch, const struct fd_tile *tile)
return;
fd_log(batch, "TILE: START CLEAR/RESTORE");
trace_start_clear_restore(&batch->trace, batch->fast_cleared);
if (batch->fast_cleared || !use_hw_binning(batch)) {
fd6_emit_ib(batch->gmem, batch->tile_setup);
} else {
emit_conditional_ib(batch, tile, batch->tile_setup);
}
trace_end_clear_restore(&batch->trace);
fd_log(batch, "TILE: END CLEAR/RESTORE");
}
@ -1245,11 +1254,13 @@ fd6_emit_tile_gmem2mem(struct fd_batch *batch, const struct fd_tile *tile)
emit_marker6(ring, 7);
fd_log(batch, "TILE: START RESOLVE");
trace_start_resolve(&batch->trace);
if (batch->fast_cleared || !use_hw_binning(batch)) {
fd6_emit_ib(batch->gmem, batch->tile_fini);
} else {
emit_conditional_ib(batch, tile, batch->tile_fini);
}
trace_end_resolve(&batch->trace);
fd_log(batch, "TILE: END RESOLVE");
}
@ -1278,6 +1289,11 @@ emit_sysmem_clears(struct fd_batch *batch, struct fd_ringbuffer *ring)
uint32_t buffers = batch->fast_cleared;
if (!buffers)
return;
trace_start_clear_restore(&batch->trace, buffers);
if (buffers & PIPE_CLEAR_COLOR) {
for (int i = 0; i < pfb->nr_cbufs; i++) {
union pipe_color_union *color = &batch->clear_color[i];
@ -1321,6 +1337,8 @@ emit_sysmem_clears(struct fd_batch *batch, struct fd_ringbuffer *ring)
}
fd6_event_write(batch, ring, PC_CCU_FLUSH_COLOR_TS, true);
trace_end_clear_restore(&batch->trace);
}
static void
@ -1356,9 +1374,11 @@ fd6_emit_sysmem_prep(struct fd_batch *batch)
if (batch->prologue) {
if (!batch->nondraw) {
fd_log(batch, "START PROLOGUE");
trace_start_prologue(&batch->trace);
}
fd6_emit_ib(ring, batch->prologue);
if (!batch->nondraw) {
trace_end_prologue(&batch->trace);
fd_log(batch, "END PROLOGUE");
}
}

View File

@ -111,6 +111,9 @@ batch_init(struct fd_batch *batch)
util_dynarray_init(&batch->samples, NULL);
list_inithead(&batch->log_chunks);
u_trace_init(&batch->trace, &ctx->trace_context);
batch->last_timestamp_cmd = NULL;
}
struct fd_batch *
@ -222,6 +225,8 @@ batch_fini(struct fd_batch *batch)
util_dynarray_fini(&batch->samples);
assert(list_is_empty(&batch->log_chunks));
u_trace_fini(&batch->trace);
}
static void

View File

@ -29,6 +29,7 @@
#include "util/u_inlines.h"
#include "util/u_queue.h"
#include "util/u_trace.h"
#include "util/list.h"
#include "util/simple_mtx.h"
@ -52,6 +53,11 @@ struct fd_batch {
unsigned seqno;
unsigned idx; /* index into cache->batches[] */
struct u_trace trace;
/* To detect cases where we can skip cmdstream to record timestamp: */
uint32_t *last_timestamp_cmd;
int in_fence_fd;
bool needs_out_fence_fd;
struct pipe_fence_handle *fence;

View File

@ -115,6 +115,9 @@ out:
if (flags & PIPE_FLUSH_END_OF_FRAME)
fd_log_eof(ctx);
u_trace_context_process(&ctx->trace_context,
!!(flags & PIPE_FLUSH_END_OF_FRAME));
}
static void
@ -344,6 +347,8 @@ fd_context_destroy(struct pipe_context *pctx)
simple_mtx_destroy(&ctx->gmem_lock);
u_trace_context_fini(&ctx->trace_context);
if (fd_mesa_debug & (FD_DBG_BSTAT | FD_DBG_MSGS)) {
printf("batch_total=%u, batch_sysmem=%u, batch_gmem=%u, batch_nondraw=%u, batch_restore=%u\n",
(uint32_t)ctx->stats.batch_total, (uint32_t)ctx->stats.batch_sysmem,
@ -397,6 +402,47 @@ fd_get_device_reset_status(struct pipe_context *pctx)
return status;
}
static void
fd_trace_record_ts(struct u_trace *ut, struct pipe_resource *timestamps,
unsigned idx)
{
struct fd_batch *batch = container_of(ut, batch, trace);
struct fd_ringbuffer *ring = batch->nondraw ? batch->draw : batch->gmem;
if (ring->cur == batch->last_timestamp_cmd) {
uint64_t *ts = fd_bo_map(fd_resource(timestamps)->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->last_timestamp_cmd = ring->cur;
}
static uint64_t
fd_trace_read_ts(struct u_trace_context *utctx,
struct pipe_resource *timestamps, unsigned idx)
{
struct fd_context *ctx = container_of(utctx, ctx, trace_context);
struct fd_bo *ts_bo = fd_resource(timestamps)->bo;
/* Only need to stall on results for the first entry: */
if (idx == 0) {
int ret = fd_bo_cpu_prep(ts_bo, ctx->pipe, DRM_FREEDRENO_PREP_READ);
if (ret)
return U_TRACE_NO_TIMESTAMP;
}
uint64_t *ts = fd_bo_map(ts_bo);
/* Don't translate the no-timestamp marker: */
if (ts[idx] == U_TRACE_NO_TIMESTAMP)
return U_TRACE_NO_TIMESTAMP;
return ctx->ts_to_ns(ts[idx]);
}
/* 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
@ -561,6 +607,9 @@ fd_context_init(struct fd_context *ctx, struct pipe_screen *pscreen,
ctx->log_out = stdout;
u_trace_context_init(&ctx->trace_context, pctx,
fd_trace_record_ts, fd_trace_read_ts);
if ((fd_mesa_debug & FD_DBG_LOG) &&
!(ctx->record_timestamp && ctx->ts_to_ns)) {
printf("logging not supported!\n");

View File

@ -34,6 +34,7 @@
#include "util/list.h"
#include "util/slab.h"
#include "util/u_string.h"
#include "util/u_trace.h"
#include "freedreno_screen.h"
#include "freedreno_gmem.h"
@ -393,6 +394,8 @@ struct fd_context {
struct pipe_debug_callback debug;
struct u_trace_context trace_context;
/* Called on rebind_resource() for any per-gen cleanup required: */
void (*rebind_resource)(struct fd_context *ctx, struct fd_resource *rsc);

View File

@ -32,6 +32,7 @@
#include "util/u_memory.h"
#include "util/u_inlines.h"
#include "util/format/u_format.h"
#include "u_tracepoints.h"
#include "freedreno_gmem.h"
#include "freedreno_context.h"
@ -39,6 +40,7 @@
#include "freedreno_log.h"
#include "freedreno_resource.h"
#include "freedreno_query_hw.h"
#include "freedreno_tracepoints.h"
#include "freedreno_util.h"
/*
@ -589,6 +591,8 @@ render_tiles(struct fd_batch *batch, struct fd_gmem_stateobj *gmem)
fd_log(batch, "bin_h=%d, yoff=%d, bin_w=%d, xoff=%d",
tile->bin_h, tile->yoff, tile->bin_w, tile->xoff);
trace_start_tile(&batch->trace, tile->bin_h,
tile->yoff, tile->bin_w, tile->xoff);
ctx->emit_tile_prep(batch, tile);
@ -603,12 +607,13 @@ render_tiles(struct fd_batch *batch, struct fd_gmem_stateobj *gmem)
/* emit IB to drawcmds: */
fd_log(batch, "TILE[%d]: START DRAW IB", i);
trace_start_draw_ib(&batch->trace);
if (ctx->emit_tile) {
ctx->emit_tile(batch, tile);
} else {
ctx->screen->emit_ib(batch->gmem, batch->draw);
}
trace_end_draw_ib(&batch->trace);
fd_log(batch, "TILE[%d]: END DRAW IB", i);
fd_reset_wfi(batch);
@ -634,11 +639,13 @@ render_sysmem(struct fd_batch *batch)
if (!batch->nondraw) {
fd_log(batch, "SYSMEM: START DRAW IB");
trace_start_draw_ib(&batch->trace);
}
/* emit IB to drawcmds: */
ctx->screen->emit_ib(batch->gmem, batch->draw);
if (!batch->nondraw) {
trace_end_draw_ib(&batch->trace);
fd_log(batch, "SYSMEM: END DRAW IB");
}
@ -672,6 +679,12 @@ fd_gmem_render_tiles(struct fd_batch *batch)
struct pipe_framebuffer_state *pfb = &batch->framebuffer;
bool sysmem = false;
if (!batch->nondraw) {
trace_flush_batch(&batch->trace, batch, batch->cleared,
batch->gmem_reason, batch->num_draws);
trace_framebuffer_state(&batch->trace, pfb);
}
if (ctx->emit_sysmem_prep && !batch->nondraw) {
if (batch->cleared || batch->gmem_reason ||
((batch->num_draws > 5) && !batch->blit) ||
@ -731,6 +744,7 @@ fd_gmem_render_tiles(struct fd_batch *batch)
util_format_short_name(pipe_surface_format(pfb->cbufs[0])),
util_format_short_name(pipe_surface_format(pfb->zsbuf)),
batch->num_draws);
trace_render_sysmem(&batch->trace);
if (ctx->query_prepare)
ctx->query_prepare(batch, 1);
render_sysmem(batch);
@ -742,6 +756,8 @@ fd_gmem_render_tiles(struct fd_batch *batch)
batch, pfb->width, pfb->height, gmem->nbins_x, gmem->nbins_y,
util_format_short_name(pipe_surface_format(pfb->cbufs[0])),
util_format_short_name(pipe_surface_format(pfb->zsbuf)));
trace_render_gmem(&batch->trace, gmem->nbins_x, gmem->nbins_y,
gmem->bin_w, gmem->bin_h);
if (ctx->query_prepare)
ctx->query_prepare(batch, gmem->nbins_x * gmem->nbins_y);
render_tiles(batch, gmem);
@ -755,6 +771,8 @@ fd_gmem_render_tiles(struct fd_batch *batch)
}
flush_ring(batch);
u_trace_flush(&batch->trace);
}
/* Determine a worst-case estimate (ie. assuming we don't eliminate an

View File

@ -0,0 +1,114 @@
#
# 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.
#
import argparse
import sys
#
# TODO can we do this with less boilerplate?
#
parser = argparse.ArgumentParser()
parser.add_argument('-p', '--import-path', required=True)
parser.add_argument('-C', '--src', required=True)
parser.add_argument('-H', '--hdr', required=True)
args = parser.parse_args()
sys.path.insert(0, args.import_path)
from u_trace import Header
from u_trace import Tracepoint
from u_trace import utrace_generate
#
# Tracepoint definitions:
#
Header('util/u_dump.h')
Header('freedreno_batch.h')
Tracepoint('start_state_restore')
Tracepoint('end_state_restore')
Tracepoint('flush_batch',
args=[['struct fd_batch *', 'batch'],
['uint16_t', 'cleared'],
['uint16_t', 'gmem_reason'],
['uint16_t', 'num_draws']],
tp_print=['%p: cleared=%x, gmem_reason=%x, num_draws=%u', '__entry->batch',
'__entry->cleared', '__entry->gmem_reason', '__entry->num_draws'],
)
Tracepoint('render_gmem',
args=[['uint16_t', 'nbins_x'],
['uint16_t', 'nbins_y'],
['uint16_t', 'bin_w'],
['uint16_t', 'bin_h']],
tp_print=['%ux%u bins of %ux%u',
'__entry->nbins_x', '__entry->nbins_y', '__entry->bin_w', '__entry->bin_h'],
)
Tracepoint('render_sysmem')
Tracepoint('start_binning_ib')
Tracepoint('end_binning_ib')
Tracepoint('start_vsc_overflow_test')
Tracepoint('end_vsc_overflow_test')
Tracepoint('start_prologue')
Tracepoint('end_prologue')
# For GMEM pass, where this could either be a clear or resolve
Tracepoint('start_clear_restore',
args=[['uint16_t', 'fast_cleared']],
tp_print=['fast_cleared: 0x%x', '__entry->fast_cleared']
)
Tracepoint('end_clear_restore')
Tracepoint('start_resolve')
Tracepoint('end_resolve')
Tracepoint('start_tile',
args=[['uint16_t', 'bin_h'],
['uint16_t', 'yoff'],
['uint16_t', 'bin_w'],
['uint16_t', 'xoff']],
tp_print=['bin_h=%d, yoff=%d, bin_w=%d, xoff=%d',
'__entry->bin_h', '__entry->yoff', '__entry->bin_w', '__entry->xoff'],
)
Tracepoint('start_draw_ib')
Tracepoint('end_draw_ib')
Tracepoint('start_blit',
args=[['enum pipe_texture_target', 'src_target'],
['enum pipe_texture_target', 'dst_target']],
tp_print=['%s -> %s', 'util_str_tex_target(__entry->src_target, true)',
'util_str_tex_target(__entry->dst_target, true)'],
)
Tracepoint('end_blit')
Tracepoint('start_compute')
Tracepoint('end_compute')
utrace_generate(cpath=args.src, hpath=args.hdr)

View File

@ -217,6 +217,19 @@ files_libfreedreno = files(
'ir3/ir3_gallium.h',
)
files_libfreedreno += custom_target(
'freedreno_tracepoints.[ch]',
input: 'freedreno_tracepoints.py',
output: ['freedreno_tracepoints.c', 'freedreno_tracepoints.h'],
command: [
prog_python, '@INPUT@',
'-p', join_paths(meson.source_root(), 'src/gallium/auxiliary/util/'),
'-C', '@OUTPUT0@',
'-H', '@OUTPUT1@',
],
depend_files: u_trace_py,
)
freedreno_includes = [
inc_mesa, inc_mapi,
inc_src, inc_include, inc_gallium, inc_gallium_aux,
@ -244,7 +257,8 @@ libfreedreno = static_library(
dep_libdrm,
idep_mesautil,
idep_nir_headers,
idep_libfreedreno_common
idep_libfreedreno_common,
idep_u_tracepoints,
],
)