freedreno: add basic query support

Add for now some simple/basic query support (ie. things not actually
requiring the GPU).  Might change around a bit when I actually add
GPU queries, but for now this enables some useful performance info
in the GALLIUM_HUD.  For example:

  GALLIUM_HUD=fps+batches+batches-sysmem+batches-gmem+restores,draw-calls

The driver specific specific queries are:

  + draw-calls
  + batches - number of batches per second, sum of batches-sysmem
    plus batches-gmem
  + batches-gmem - render a set of tiles in GMEM, for each tile
    (optionally) system mem -> gmem (restore), plus N draws,
    plus gmem -> system mem (resolve) per second
  + batches-sysmem - N draws to system memory (GMEM bypass) per
    second
  + restores - number of GMEM batches that required restore per
    second

Ideally for GMEM rendering, you want batches-gmem to equal fps.  If
the app is doing something that triggers multiple passes (ie. requires
extra round trip gmem <-> system memory) then the # of batches per
second will go up relative to fps.

Signed-off-by: Rob Clark <robclark@freedesktop.org>
This commit is contained in:
Rob Clark
2014-01-07 21:39:13 -05:00
parent 725d736f6a
commit 646c16af6e
8 changed files with 275 additions and 1 deletions
@@ -1,5 +1,6 @@
C_SOURCES := \
freedreno_util.c \
freedreno_query.c \
freedreno_fence.c \
freedreno_resource.c \
freedreno_surface.c \
@@ -32,6 +32,7 @@
#include "freedreno_texture.h"
#include "freedreno_state.h"
#include "freedreno_gmem.h"
#include "freedreno_query.h"
#include "freedreno_util.h"
static struct fd_ringbuffer *next_rb(struct fd_context *ctx)
@@ -212,6 +213,7 @@ fd_context_init(struct fd_context *ctx, struct pipe_screen *pscreen,
fd_draw_init(pctx);
fd_resource_context_init(pctx);
fd_query_context_init(pctx);
fd_texture_init(pctx);
fd_state_init(pctx);
@@ -134,7 +134,15 @@ struct fd_context {
FD_GMEM_BLEND_ENABLED = 0x10,
FD_GMEM_LOGICOP_ENABLED = 0x20,
} gmem_reason;
unsigned num_draws;
unsigned num_draws; /* number of draws in current batch */
/* Stats/counters:
*/
struct {
uint64_t prims_emitted;
uint64_t draw_calls;
uint64_t batch_total, batch_sysmem, batch_gmem, batch_restore;
} stats;
/* we can't really sanely deal with wraparound point in ringbuffer
* and because of the way tiling works we can't really flush at
@@ -142,6 +142,10 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
ctx->num_draws++;
ctx->stats.draw_calls++;
ctx->stats.prims_emitted +=
u_reduced_prims_for_vertices(info->mode, info->count);
/* any buffers that haven't been cleared, we need to restore: */
ctx->restore |= buffers & (FD_BUFFER_ALL & ~ctx->cleared);
/* and any buffers used, need to be resolved: */
@@ -260,6 +260,9 @@ render_tiles(struct fd_context *ctx)
ctx->emit_tile_init(ctx);
if (ctx->restore)
ctx->stats.batch_restore++;
for (i = 0; i < (gmem->nbins_x * gmem->nbins_y); i++) {
struct fd_tile *tile = &ctx->tile[i];
@@ -311,11 +314,14 @@ fd_gmem_render_tiles(struct pipe_context *pctx)
fd_ringmarker_mark(ctx->draw_end);
fd_ringmarker_mark(ctx->binning_end);
ctx->stats.batch_total++;
if (sysmem) {
DBG("rendering sysmem (%s/%s)",
util_format_short_name(pipe_surface_format(pfb->cbufs[0])),
util_format_short_name(pipe_surface_format(pfb->zsbuf)));
render_sysmem(ctx);
ctx->stats.batch_sysmem++;
} else {
struct fd_gmem_stateobj *gmem = &ctx->gmem;
calculate_tiles(ctx);
@@ -323,6 +329,7 @@ fd_gmem_render_tiles(struct pipe_context *pctx)
util_format_short_name(pipe_surface_format(pfb->cbufs[0])),
util_format_short_name(pipe_surface_format(pfb->zsbuf)));
render_tiles(ctx);
ctx->stats.batch_gmem++;
}
/* GPU executes starting from tile cmds, which IB back to draw cmds: */
@@ -0,0 +1,213 @@
/* -*- mode: C; c-file-style: "k&r"; ttxab-width 4; indent-tabs-mode: t; -*- */
/*
* Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
*
* 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.
*
* Authors:
* Rob Clark <robclark@freedesktop.org>
*/
#include "pipe/p_state.h"
#include "util/u_string.h"
#include "util/u_memory.h"
#include "util/u_inlines.h"
#include "os/os_time.h"
#include "freedreno_query.h"
#include "freedreno_context.h"
#include "freedreno_util.h"
#define FD_QUERY_DRAW_CALLS (PIPE_QUERY_DRIVER_SPECIFIC + 0)
#define FD_QUERY_BATCH_TOTAL (PIPE_QUERY_DRIVER_SPECIFIC + 1) /* total # of batches (submits) */
#define FD_QUERY_BATCH_SYSMEM (PIPE_QUERY_DRIVER_SPECIFIC + 2) /* batches using system memory (GMEM bypass) */
#define FD_QUERY_BATCH_GMEM (PIPE_QUERY_DRIVER_SPECIFIC + 3) /* batches using GMEM */
#define FD_QUERY_BATCH_RESTORE (PIPE_QUERY_DRIVER_SPECIFIC + 4) /* batches requiring GMEM restore */
/* Currently just simple cpu query's supported.. probably need
* to refactor this a bit when I'm eventually ready to add gpu
* queries:
*/
struct fd_query {
int type;
/* storage for the collected data */
union pipe_query_result data;
bool active;
uint64_t begin_value, end_value;
uint64_t begin_time, end_time;
};
static inline struct fd_query *
fd_query(struct pipe_query *pq)
{
return (struct fd_query *)pq;
}
static struct pipe_query *
fd_create_query(struct pipe_context *pctx, unsigned query_type)
{
struct fd_query *q;
switch (query_type) {
case PIPE_QUERY_PRIMITIVES_GENERATED:
case PIPE_QUERY_PRIMITIVES_EMITTED:
case FD_QUERY_DRAW_CALLS:
case FD_QUERY_BATCH_TOTAL:
case FD_QUERY_BATCH_SYSMEM:
case FD_QUERY_BATCH_GMEM:
case FD_QUERY_BATCH_RESTORE:
break;
default:
return NULL;
}
q = CALLOC_STRUCT(fd_query);
if (!q)
return NULL;
q->type = query_type;
return (struct pipe_query *) q;
}
static void
fd_destroy_query(struct pipe_context *pctx, struct pipe_query *pq)
{
struct fd_query *q = fd_query(pq);
free(q);
}
static uint64_t
read_counter(struct pipe_context *pctx, int type)
{
struct fd_context *ctx = fd_context(pctx);
switch (type) {
case PIPE_QUERY_PRIMITIVES_GENERATED:
/* for now same thing as _PRIMITIVES_EMITTED */
case PIPE_QUERY_PRIMITIVES_EMITTED:
return ctx->stats.prims_emitted;
case FD_QUERY_DRAW_CALLS:
return ctx->stats.draw_calls;
case FD_QUERY_BATCH_TOTAL:
return ctx->stats.batch_total;
case FD_QUERY_BATCH_SYSMEM:
return ctx->stats.batch_sysmem;
case FD_QUERY_BATCH_GMEM:
return ctx->stats.batch_gmem;
case FD_QUERY_BATCH_RESTORE:
return ctx->stats.batch_restore;
}
return 0;
}
static bool
is_rate_query(struct fd_query *q)
{
switch (q->type) {
case FD_QUERY_BATCH_TOTAL:
case FD_QUERY_BATCH_SYSMEM:
case FD_QUERY_BATCH_GMEM:
case FD_QUERY_BATCH_RESTORE:
return true;
default:
return false;
}
}
static void
fd_begin_query(struct pipe_context *pctx, struct pipe_query *pq)
{
struct fd_query *q = fd_query(pq);
q->active = true;
q->begin_value = read_counter(pctx, q->type);
if (is_rate_query(q))
q->begin_time = os_time_get();
}
static void
fd_end_query(struct pipe_context *pctx, struct pipe_query *pq)
{
struct fd_query *q = fd_query(pq);
q->active = false;
q->end_value = read_counter(pctx, q->type);
if (is_rate_query(q))
q->end_time = os_time_get();
}
static boolean
fd_get_query_result(struct pipe_context *pctx, struct pipe_query *pq,
boolean wait, union pipe_query_result *result)
{
struct fd_query *q = fd_query(pq);
if (q->active)
return false;
util_query_clear_result(result, q->type);
result->u64 = q->end_value - q->begin_value;
if (is_rate_query(q)) {
double fps = (result->u64 * 1000000) /
(double)(q->end_time - q->begin_time);
result->u64 = (uint64_t)fps;
}
return true;
}
static int
fd_get_driver_query_info(struct pipe_screen *pscreen,
unsigned index, struct pipe_driver_query_info *info)
{
struct pipe_driver_query_info list[] = {
{"draw-calls", FD_QUERY_DRAW_CALLS, 0},
{"batches", FD_QUERY_BATCH_TOTAL, 0},
{"batches-sysmem", FD_QUERY_BATCH_SYSMEM, 0},
{"batches-gmem", FD_QUERY_BATCH_GMEM, 0},
{"restores", FD_QUERY_BATCH_RESTORE, 0},
};
if (!info)
return ARRAY_SIZE(list);
if (index >= ARRAY_SIZE(list))
return 0;
*info = list[index];
return 1;
}
void
fd_query_screen_init(struct pipe_screen *pscreen)
{
pscreen->get_driver_query_info = fd_get_driver_query_info;
}
void
fd_query_context_init(struct pipe_context *pctx)
{
pctx->create_query = fd_create_query;
pctx->destroy_query = fd_destroy_query;
pctx->begin_query = fd_begin_query;
pctx->end_query = fd_end_query;
pctx->get_query_result = fd_get_query_result;
}
@@ -0,0 +1,37 @@
/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
/*
* Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
*
* 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.
*
* Authors:
* Rob Clark <robclark@freedesktop.org>
*/
#ifndef FREEDRENO_QUERY_H_
#define FREEDRENO_QUERY_H_
#include "pipe/p_context.h"
void fd_query_screen_init(struct pipe_screen *pscreen);
void fd_query_context_init(struct pipe_context *pctx);
#endif /* FREEDRENO_QUERY_H_ */
@@ -47,6 +47,7 @@
#include "freedreno_screen.h"
#include "freedreno_resource.h"
#include "freedreno_fence.h"
#include "freedreno_query.h"
#include "freedreno_util.h"
#include "fd2_screen.h"
@@ -457,6 +458,7 @@ fd_screen_create(struct fd_device *dev)
pscreen->get_shader_param = fd_screen_get_shader_param;
fd_resource_screen_init(pscreen);
fd_query_screen_init(pscreen);
pscreen->get_name = fd_screen_get_name;
pscreen->get_vendor = fd_screen_get_vendor;