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 <rob.clark@oss.qualcomm.com>
This commit is contained in:
Rob Clark 2026-05-01 08:12:44 -07:00
parent cb27d2e1b2
commit c642bc8c27
5 changed files with 35 additions and 32 deletions

View file

@ -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;
}

View file

@ -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);

View file

@ -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 {

View file

@ -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);
}

View file

@ -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;