[Mesa-dev] [PATCH v3 8/9] gallium/hud: add support for batch queries
Samuel Pitoiset
samuel.pitoiset at gmail.com
Fri Nov 20 04:06:36 PST 2015
Reviewed-by: Samuel Pitoiset <samuel.pitoiset at gmail.com>
On 11/18/2015 12:49 PM, Nicolai Hähnle wrote:
> v2 + v3: be more defensive about allocations
> ---
> src/gallium/auxiliary/hud/hud_context.c | 24 ++-
> src/gallium/auxiliary/hud/hud_driver_query.c | 270 +++++++++++++++++++++++----
> src/gallium/auxiliary/hud/hud_private.h | 13 +-
> 3 files changed, 261 insertions(+), 46 deletions(-)
>
> diff --git a/src/gallium/auxiliary/hud/hud_context.c b/src/gallium/auxiliary/hud/hud_context.c
> index ffe30b8..bcef701 100644
> --- a/src/gallium/auxiliary/hud/hud_context.c
> +++ b/src/gallium/auxiliary/hud/hud_context.c
> @@ -57,6 +57,7 @@ struct hud_context {
> struct cso_context *cso;
> struct u_upload_mgr *uploader;
>
> + struct hud_batch_query_context *batch_query;
> struct list_head pane_list;
>
> /* states */
> @@ -510,6 +511,8 @@ hud_draw(struct hud_context *hud, struct pipe_resource *tex)
> hud_alloc_vertices(hud, &hud->text, 4 * 512, 4 * sizeof(float));
>
> /* prepare all graphs */
> + hud_batch_query_update(hud->batch_query);
> +
> LIST_FOR_EACH_ENTRY(pane, &hud->pane_list, head) {
> LIST_FOR_EACH_ENTRY(gr, &pane->graph_list, head) {
> gr->query_new_value(gr);
> @@ -903,17 +906,21 @@ hud_parse_env_var(struct hud_context *hud, const char *env)
> }
> else if (strcmp(name, "samples-passed") == 0 &&
> has_occlusion_query(hud->pipe->screen)) {
> - hud_pipe_query_install(pane, hud->pipe, "samples-passed",
> + hud_pipe_query_install(&hud->batch_query, pane, hud->pipe,
> + "samples-passed",
> PIPE_QUERY_OCCLUSION_COUNTER, 0, 0,
> PIPE_DRIVER_QUERY_TYPE_UINT64,
> - PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE);
> + PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE,
> + 0);
> }
> else if (strcmp(name, "primitives-generated") == 0 &&
> has_streamout(hud->pipe->screen)) {
> - hud_pipe_query_install(pane, hud->pipe, "primitives-generated",
> + hud_pipe_query_install(&hud->batch_query, pane, hud->pipe,
> + "primitives-generated",
> PIPE_QUERY_PRIMITIVES_GENERATED, 0, 0,
> PIPE_DRIVER_QUERY_TYPE_UINT64,
> - PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE);
> + PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE,
> + 0);
> }
> else {
> boolean processed = FALSE;
> @@ -938,17 +945,19 @@ hud_parse_env_var(struct hud_context *hud, const char *env)
> if (strcmp(name, pipeline_statistics_names[i]) == 0)
> break;
> if (i < Elements(pipeline_statistics_names)) {
> - hud_pipe_query_install(pane, hud->pipe, name,
> + hud_pipe_query_install(&hud->batch_query, pane, hud->pipe, name,
> PIPE_QUERY_PIPELINE_STATISTICS, i,
> 0, PIPE_DRIVER_QUERY_TYPE_UINT64,
> - PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE);
> + PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE,
> + 0);
> processed = TRUE;
> }
> }
>
> /* driver queries */
> if (!processed) {
> - if (!hud_driver_query_install(pane, hud->pipe, name)){
> + if (!hud_driver_query_install(&hud->batch_query, pane, hud->pipe,
> + name)) {
> fprintf(stderr, "gallium_hud: unknown driver query '%s'\n", name);
> }
> }
> @@ -1287,6 +1296,7 @@ hud_destroy(struct hud_context *hud)
> FREE(pane);
> }
>
> + hud_batch_query_cleanup(&hud->batch_query);
> pipe->delete_fs_state(pipe, hud->fs_color);
> pipe->delete_fs_state(pipe, hud->fs_text);
> pipe->delete_vs_state(pipe, hud->vs);
> diff --git a/src/gallium/auxiliary/hud/hud_driver_query.c b/src/gallium/auxiliary/hud/hud_driver_query.c
> index 3198ab3..d7b1f11 100644
> --- a/src/gallium/auxiliary/hud/hud_driver_query.c
> +++ b/src/gallium/auxiliary/hud/hud_driver_query.c
> @@ -34,13 +34,164 @@
> #include "hud/hud_private.h"
> #include "pipe/p_screen.h"
> #include "os/os_time.h"
> +#include "util/u_math.h"
> #include "util/u_memory.h"
> #include <stdio.h>
>
> +// Must be a power of two
> #define NUM_QUERIES 8
>
> +struct hud_batch_query_context {
> + struct pipe_context *pipe;
> + unsigned num_query_types;
> + unsigned allocated_query_types;
> + unsigned *query_types;
> +
> + boolean failed;
> + struct pipe_query *query[NUM_QUERIES];
> + union pipe_query_result *result[NUM_QUERIES];
> + unsigned head, pending, results;
> +};
> +
> +void
> +hud_batch_query_update(struct hud_batch_query_context *bq)
> +{
> + struct pipe_context *pipe;
> +
> + if (!bq || bq->failed)
> + return;
> +
> + pipe = bq->pipe;
> +
> + if (bq->query[bq->head])
> + pipe->end_query(pipe, bq->query[bq->head]);
> +
> + bq->results = 0;
> +
> + while (bq->pending) {
> + unsigned idx = (bq->head - bq->pending + 1) % NUM_QUERIES;
> + struct pipe_query *query = bq->query[idx];
> +
> + if (!bq->result[idx])
> + bq->result[idx] = MALLOC(sizeof(bq->result[idx]->batch[0]) *
> + bq->num_query_types);
> + if (!bq->result[idx]) {
> + fprintf(stderr, "gallium_hud: out of memory.\n");
> + bq->failed = TRUE;
> + return;
> + }
> +
> + if (!pipe->get_query_result(pipe, query, FALSE, bq->result[idx]))
> + break;
> +
> + ++bq->results;
> + --bq->pending;
> + }
> +
> + bq->head = (bq->head + 1) % NUM_QUERIES;
> +
> + if (bq->pending == NUM_QUERIES) {
> + fprintf(stderr,
> + "gallium_hud: all queries busy after %i frames, dropping data.\n",
> + NUM_QUERIES);
> +
> + assert(bq->query[bq->head]);
> +
> + pipe->destroy_query(bq->pipe, bq->query[bq->head]);
> + bq->query[bq->head] = NULL;
> + }
> +
> + ++bq->pending;
> +
> + if (!bq->query[bq->head]) {
> + bq->query[bq->head] = pipe->create_batch_query(pipe,
> + bq->num_query_types,
> + bq->query_types);
> +
> + if (!bq->query[bq->head]) {
> + fprintf(stderr,
> + "gallium_hud: create_batch_query failed. You may have "
> + "selected too many or incompatible queries.\n");
> + bq->failed = TRUE;
> + return;
> + }
> + }
> +
> + if (!pipe->begin_query(pipe, bq->query[bq->head])) {
> + fprintf(stderr,
> + "gallium_hud: could not begin batch query. You may have "
> + "selected too many or incompatible queries.\n");
> + bq->failed = TRUE;
> + }
> +}
> +
> +static boolean
> +batch_query_add(struct hud_batch_query_context **pbq,
> + struct pipe_context *pipe, unsigned query_type,
> + unsigned *result_index)
> +{
> + struct hud_batch_query_context *bq = *pbq;
> + unsigned i;
> +
> + if (!bq) {
> + bq = CALLOC_STRUCT(hud_batch_query_context);
> + if (!bq)
> + return false;
> + bq->pipe = pipe;
> + *pbq = bq;
> + }
> +
> + for (i = 0; i < bq->num_query_types; ++i) {
> + if (bq->query_types[i] == query_type) {
> + *result_index = i;
> + return true;
> + }
> + }
> +
> + if (bq->num_query_types == bq->allocated_query_types) {
> + unsigned new_alloc = MAX2(16, bq->allocated_query_types * 2);
> + unsigned *new_query_types
> + = REALLOC(bq->query_types,
> + bq->allocated_query_types * sizeof(unsigned),
> + new_alloc * sizeof(unsigned));
> + if (!new_query_types)
> + return false;
> + bq->query_types = new_query_types;
> + bq->allocated_query_types = new_alloc;
> + }
> +
> + bq->query_types[bq->num_query_types] = query_type;
> + *result_index = bq->num_query_types++;
> + return true;
> +}
> +
> +void
> +hud_batch_query_cleanup(struct hud_batch_query_context **pbq)
> +{
> + struct hud_batch_query_context *bq = *pbq;
> + unsigned idx;
> +
> + if (!bq)
> + return;
> +
> + *pbq = NULL;
> +
> + if (bq->query[bq->head] && !bq->failed)
> + bq->pipe->end_query(bq->pipe, bq->query[bq->head]);
> +
> + for (idx = 0; idx < NUM_QUERIES; ++idx) {
> + if (bq->query[idx])
> + bq->pipe->destroy_query(bq->pipe, bq->query[idx]);
> + FREE(bq->result[idx]);
> + }
> +
> + FREE(bq->query_types);
> + FREE(bq);
> +}
> +
> struct query_info {
> struct pipe_context *pipe;
> + struct hud_batch_query_context *batch;
> unsigned query_type;
> unsigned result_index; /* unit depends on query_type */
> enum pipe_driver_query_result_type result_type;
> @@ -55,11 +206,26 @@ struct query_info {
> };
>
> static void
> -query_new_value(struct hud_graph *gr)
> +query_new_value_batch(struct query_info *info)
> +{
> + struct hud_batch_query_context *bq = info->batch;
> + unsigned result_index = info->result_index;
> + unsigned idx = (bq->head - bq->pending) % NUM_QUERIES;
> + unsigned results = bq->results;
> +
> + while (results) {
> + info->results_cumulative += bq->result[idx]->batch[result_index].u64;
> + ++info->num_results;
> +
> + --results;
> + idx = (idx - 1) % NUM_QUERIES;
> + }
> +}
> +
> +static void
> +query_new_value_normal(struct query_info *info)
> {
> - struct query_info *info = gr->query_data;
> struct pipe_context *pipe = info->pipe;
> - uint64_t now = os_time_get();
>
> if (info->last_time) {
> if (info->query[info->head])
> @@ -106,30 +272,9 @@ query_new_value(struct hud_graph *gr)
> break;
> }
> }
> -
> - if (info->num_results && info->last_time + gr->pane->period <= now) {
> - uint64_t value;
> -
> - switch (info->result_type) {
> - default:
> - case PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE:
> - value = info->results_cumulative / info->num_results;
> - break;
> - case PIPE_DRIVER_QUERY_RESULT_TYPE_CUMULATIVE:
> - value = info->results_cumulative;
> - break;
> - }
> -
> - hud_graph_add_value(gr, value);
> -
> - info->last_time = now;
> - info->results_cumulative = 0;
> - info->num_results = 0;
> - }
> }
> else {
> /* initialize */
> - info->last_time = now;
> info->query[info->head] = pipe->create_query(pipe, info->query_type, 0);
> }
>
> @@ -138,11 +283,49 @@ query_new_value(struct hud_graph *gr)
> }
>
> static void
> +query_new_value(struct hud_graph *gr)
> +{
> + struct query_info *info = gr->query_data;
> + uint64_t now = os_time_get();
> +
> + if (info->batch) {
> + query_new_value_batch(info);
> + } else {
> + query_new_value_normal(info);
> + }
> +
> + if (!info->last_time) {
> + info->last_time = now;
> + return;
> + }
> +
> + if (info->num_results && info->last_time + gr->pane->period <= now) {
> + uint64_t value;
> +
> + switch (info->result_type) {
> + default:
> + case PIPE_DRIVER_QUERY_RESULT_TYPE_AVERAGE:
> + value = info->results_cumulative / info->num_results;
> + break;
> + case PIPE_DRIVER_QUERY_RESULT_TYPE_CUMULATIVE:
> + value = info->results_cumulative;
> + break;
> + }
> +
> + hud_graph_add_value(gr, value);
> +
> + info->last_time = now;
> + info->results_cumulative = 0;
> + info->num_results = 0;
> + }
> +}
> +
> +static void
> free_query_info(void *ptr)
> {
> struct query_info *info = ptr;
>
> - if (info->last_time) {
> + if (!info->batch && info->last_time) {
> struct pipe_context *pipe = info->pipe;
> int i;
>
> @@ -158,11 +341,13 @@ free_query_info(void *ptr)
> }
>
> void
> -hud_pipe_query_install(struct hud_pane *pane, struct pipe_context *pipe,
> +hud_pipe_query_install(struct hud_batch_query_context **pbq,
> + struct hud_pane *pane, struct pipe_context *pipe,
> const char *name, unsigned query_type,
> unsigned result_index,
> uint64_t max_value, enum pipe_driver_query_type type,
> - enum pipe_driver_query_result_type result_type)
> + enum pipe_driver_query_result_type result_type,
> + unsigned flags)
> {
> struct hud_graph *gr;
> struct query_info *info;
> @@ -174,28 +359,40 @@ hud_pipe_query_install(struct hud_pane *pane, struct pipe_context *pipe,
> strncpy(gr->name, name, sizeof(gr->name));
> gr->name[sizeof(gr->name) - 1] = '\0';
> gr->query_data = CALLOC_STRUCT(query_info);
> - if (!gr->query_data) {
> - FREE(gr);
> - return;
> - }
> + if (!gr->query_data)
> + goto fail_gr;
>
> gr->query_new_value = query_new_value;
> gr->free_query_data = free_query_info;
>
> info = gr->query_data;
> info->pipe = pipe;
> - info->query_type = query_type;
> - info->result_index = result_index;
> info->result_type = result_type;
>
> + if (flags & PIPE_DRIVER_QUERY_FLAG_BATCH) {
> + if (!batch_query_add(pbq, pipe, query_type, &info->result_index))
> + goto fail_info;
> + info->batch = *pbq;
> + } else {
> + info->query_type = query_type;
> + info->result_index = result_index;
> + }
> +
> hud_pane_add_graph(pane, gr);
> if (pane->max_value < max_value)
> hud_pane_set_max_value(pane, max_value);
> pane->type = type;
> + return;
> +
> +fail_info:
> + FREE(info);
> +fail_gr:
> + FREE(gr);
> }
>
> boolean
> -hud_driver_query_install(struct hud_pane *pane, struct pipe_context *pipe,
> +hud_driver_query_install(struct hud_batch_query_context **pbq,
> + struct hud_pane *pane, struct pipe_context *pipe,
> const char *name)
> {
> struct pipe_screen *screen = pipe->screen;
> @@ -219,8 +416,9 @@ hud_driver_query_install(struct hud_pane *pane, struct pipe_context *pipe,
> if (!found)
> return FALSE;
>
> - hud_pipe_query_install(pane, pipe, query.name, query.query_type, 0,
> - query.max_value.u64, query.type, query.result_type);
> + hud_pipe_query_install(pbq, pane, pipe, query.name, query.query_type, 0,
> + query.max_value.u64, query.type, query.result_type,
> + query.flags);
>
> return TRUE;
> }
> diff --git a/src/gallium/auxiliary/hud/hud_private.h b/src/gallium/auxiliary/hud/hud_private.h
> index 01caf7b..4a788bb 100644
> --- a/src/gallium/auxiliary/hud/hud_private.h
> +++ b/src/gallium/auxiliary/hud/hud_private.h
> @@ -80,19 +80,26 @@ void hud_pane_set_max_value(struct hud_pane *pane, uint64_t value);
> void hud_graph_add_value(struct hud_graph *gr, uint64_t value);
>
> /* graphs/queries */
> +struct hud_batch_query_context;
> +
> #define ALL_CPUS ~0 /* optionally set as cpu_index */
>
> int hud_get_num_cpus(void);
>
> void hud_fps_graph_install(struct hud_pane *pane);
> void hud_cpu_graph_install(struct hud_pane *pane, unsigned cpu_index);
> -void hud_pipe_query_install(struct hud_pane *pane, struct pipe_context *pipe,
> +void hud_pipe_query_install(struct hud_batch_query_context **pbq,
> + struct hud_pane *pane, struct pipe_context *pipe,
> const char *name, unsigned query_type,
> unsigned result_index,
> uint64_t max_value,
> enum pipe_driver_query_type type,
> - enum pipe_driver_query_result_type result_type);
> -boolean hud_driver_query_install(struct hud_pane *pane,
> + enum pipe_driver_query_result_type result_type,
> + unsigned flags);
> +boolean hud_driver_query_install(struct hud_batch_query_context **pbq,
> + struct hud_pane *pane,
> struct pipe_context *pipe, const char *name);
> +void hud_batch_query_update(struct hud_batch_query_context *bq);
> +void hud_batch_query_cleanup(struct hud_batch_query_context **pbq);
>
> #endif
>
--
-Samuel
More information about the mesa-dev
mailing list