From c642bc8c276e58f4c6d64ad4230a2a1c57366b54 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 1 May 2026 08:12:44 -0700 Subject: [PATCH] freedreno/a6xx: Use counter allocation helper If the kernel supports PERFCNTR_CONFIG for counter reservation, we can expose perfcntrs by default. Signed-off-by: Rob Clark --- .../drivers/freedreno/a6xx/fd6_query.cc | 55 ++++++++----------- .../drivers/freedreno/freedreno_query_acc.c | 3 + .../drivers/freedreno/freedreno_query_acc.h | 1 + .../drivers/freedreno/freedreno_screen.c | 7 ++- .../drivers/freedreno/freedreno_screen.h | 1 + 5 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_query.cc b/src/gallium/drivers/freedreno/a6xx/fd6_query.cc index 223758fcf12..fa2d79c262c 100644 --- a/src/gallium/drivers/freedreno/a6xx/fd6_query.cc +++ b/src/gallium/drivers/freedreno/a6xx/fd6_query.cc @@ -824,6 +824,7 @@ static const struct fd_acc_sample_provider so_overflow_predicate = { struct fd_batch_query_entry { uint8_t gid; /* group-id */ uint8_t cid; /* countable-id within the group */ + const struct fd_perfcntr_counter *counter; }; struct fd_batch_query_data { @@ -839,33 +840,23 @@ perfcntr_resume(struct fd_acc_query *aq, struct fd_batch *batch) assert_dt struct fd_screen *screen = data->screen; fd_cs cs(batch->draw); - unsigned counters_per_group[screen->num_perfcntr_groups]; - memset(counters_per_group, 0, sizeof(counters_per_group)); - fd_pkt7(cs, CP_WAIT_FOR_IDLE, 0); /* configure performance counters for the requested queries: */ for (unsigned i = 0; i < data->num_query_entries; i++) { struct fd_batch_query_entry *entry = &data->query_entries[i]; const struct fd_perfcntr_group *g = &screen->perfcntr_groups[entry->gid]; - unsigned counter_idx = counters_per_group[entry->gid]++; - - assert(counter_idx < g->num_counters); fd_pkt4(cs, 1).add((fd_reg_pair){ - .reg = g->counters[counter_idx].select_reg, + .reg = entry->counter->select_reg, .value = g->countables[entry->cid].selector, }); } - memset(counters_per_group, 0, sizeof(counters_per_group)); - /* and snapshot the start values */ for (unsigned i = 0; i < data->num_query_entries; i++) { struct fd_batch_query_entry *entry = &data->query_entries[i]; - const struct fd_perfcntr_group *g = &screen->perfcntr_groups[entry->gid]; - unsigned counter_idx = counters_per_group[entry->gid]++; - const struct fd_perfcntr_counter *counter = &g->counters[counter_idx]; + const struct fd_perfcntr_counter *counter = entry->counter; fd_pkt7(cs, CP_REG_TO_MEM, 3) .add(CP_REG_TO_MEM_0(.reg = counter->counter_reg_lo, ._64b = true)) @@ -877,12 +868,8 @@ static void perfcntr_pause(struct fd_acc_query *aq, struct fd_batch *batch) assert_dt { struct fd_batch_query_data *data = (struct fd_batch_query_data *)aq->query_data; - struct fd_screen *screen = data->screen; fd_cs cs(batch->draw); - unsigned counters_per_group[screen->num_perfcntr_groups]; - memset(counters_per_group, 0, sizeof(counters_per_group)); - fd_pkt7(cs, CP_WAIT_FOR_IDLE, 0); /* TODO do we need to bother to turn anything off? */ @@ -890,9 +877,7 @@ perfcntr_pause(struct fd_acc_query *aq, struct fd_batch *batch) assert_dt /* snapshot the end values: */ for (unsigned i = 0; i < data->num_query_entries; i++) { struct fd_batch_query_entry *entry = &data->query_entries[i]; - const struct fd_perfcntr_group *g = &screen->perfcntr_groups[entry->gid]; - unsigned counter_idx = counters_per_group[entry->gid]++; - const struct fd_perfcntr_counter *counter = &g->counters[counter_idx]; + const struct fd_perfcntr_counter *counter = entry->counter; fd_pkt7(cs, CP_REG_TO_MEM, 3) .add(CP_REG_TO_MEM_0(.reg = counter->counter_reg_lo, ._64b = true)) @@ -925,12 +910,24 @@ perfcntr_accumulate_result(struct fd_acc_query *aq, } } +static void +perfcntr_cleanup(void *query_data) +{ + struct fd_batch_query_data *data = (struct fd_batch_query_data *)query_data; + + for (unsigned i = 0; i < data->num_query_entries; i++) { + struct fd_batch_query_entry *entry = &data->query_entries[i]; + fd_perfcntr_release(data->screen->perfcntrs, entry->counter); + } +} + static const struct fd_acc_sample_provider perfcntr = { .query_type = FD_QUERY_FIRST_PERFCNTR, .always = true, .resume = perfcntr_resume, .pause = perfcntr_pause, .result = perfcntr_accumulate_result, + .cleanup = perfcntr_cleanup, }; static struct pipe_query * @@ -949,13 +946,6 @@ fd6_create_batch_query(struct pipe_context *pctx, unsigned num_queries, data->screen = screen; data->num_query_entries = num_queries; - /* validate the requested query_types and ensure we don't try - * to request more query_types of a given group than we have - * counters: - */ - unsigned counters_per_group[screen->num_perfcntr_groups]; - memset(counters_per_group, 0, sizeof(counters_per_group)); - for (unsigned i = 0; i < num_queries; i++) { unsigned idx = query_types[i] - FD_QUERY_FIRST_PERFCNTR; @@ -985,13 +975,15 @@ fd6_create_batch_query(struct pipe_context *pctx, unsigned num_queries, entry->cid++; } - if (counters_per_group[entry->gid] >= - screen->perfcntr_groups[entry->gid].num_counters) { - mesa_loge("too many counters for group %u", entry->gid); + const struct fd_perfcntr_group *g = &screen->perfcntr_groups[entry->gid]; + const struct fd_perfcntr_countable *c = &g->countables[entry->cid]; + + entry->counter = fd_perfcntr_reserve(screen->perfcntrs, g, c); + + if (!entry->counter) { + mesa_loge("Could not reserve counter for %s.%s", g->name, c->name); goto error; } - - counters_per_group[entry->gid]++; } q = fd_acc_create_query2(ctx, 0, 0, &perfcntr); @@ -1004,6 +996,7 @@ fd6_create_batch_query(struct pipe_context *pctx, unsigned num_queries, return (struct pipe_query *)q; error: + perfcntr_cleanup(data); free(data); return NULL; } diff --git a/src/gallium/drivers/freedreno/freedreno_query_acc.c b/src/gallium/drivers/freedreno/freedreno_query_acc.c index 6af0e9697ad..51051c81b97 100644 --- a/src/gallium/drivers/freedreno/freedreno_query_acc.c +++ b/src/gallium/drivers/freedreno/freedreno_query_acc.c @@ -21,6 +21,9 @@ fd_acc_destroy_query(struct fd_context *ctx, struct fd_query *q) assert_dt DBG("%p", q); + if (aq->provider->cleanup) + aq->provider->cleanup(aq->query_data); + pipe_resource_reference(&aq->prsc, NULL); list_del(&aq->node); diff --git a/src/gallium/drivers/freedreno/freedreno_query_acc.h b/src/gallium/drivers/freedreno/freedreno_query_acc.h index f06511e2dd8..cc4daefd32e 100644 --- a/src/gallium/drivers/freedreno/freedreno_query_acc.h +++ b/src/gallium/drivers/freedreno/freedreno_query_acc.h @@ -72,6 +72,7 @@ struct fd_acc_sample_provider { void (*result_resource)(struct fd_acc_query *aq, struct fd_ringbuffer *ring, enum pipe_query_value_type result_type, int index, struct fd_resource *dst, unsigned offset); + void (*cleanup)(void *query_data); /* optional cleanup */ }; struct fd_acc_query { diff --git a/src/gallium/drivers/freedreno/freedreno_screen.c b/src/gallium/drivers/freedreno/freedreno_screen.c index 4b128d437f1..0efd70af3d9 100644 --- a/src/gallium/drivers/freedreno/freedreno_screen.c +++ b/src/gallium/drivers/freedreno/freedreno_screen.c @@ -165,6 +165,8 @@ fd_screen_destroy(struct pipe_screen *pscreen) if (screen->ro) screen->ro->destroy(screen->ro); + fd_perfcntr_state_free(screen->perfcntrs); + fd_bc_fini(&screen->batch_cache); fd_gmem_screen_fini(pscreen); @@ -1057,7 +1059,10 @@ fd_screen_create(int fd, if (screen->primtypes[i]) screen->primtypes_mask |= (1 << i); - if (FD_DBG(PERFC)) { + screen->perfcntrs = fd_perfcntr_state_alloc(screen->dev_id, fd); + + if (FD_DBG(PERFC) || + (screen->perfcntrs && fd_perfcntr_has_reservation(screen->perfcntrs))) { screen->perfcntr_groups = fd_perfcntrs(screen->dev_id, &screen->num_perfcntr_groups); } diff --git a/src/gallium/drivers/freedreno/freedreno_screen.h b/src/gallium/drivers/freedreno/freedreno_screen.h index 137fea1c5b8..4ae53ac0b10 100644 --- a/src/gallium/drivers/freedreno/freedreno_screen.h +++ b/src/gallium/drivers/freedreno/freedreno_screen.h @@ -106,6 +106,7 @@ struct fd_screen { unsigned num_perfcntr_groups; const struct fd_perfcntr_group *perfcntr_groups; + struct fd_perfcntr_state *perfcntrs; /* generated at startup from the perfcntr groups: */ unsigned num_perfcntr_queries;