pan/pps: Output counters per block

Instead of summing counters from shader cores, and outputting only
the counters from the first l2 slice, use the memory layout provided
from the kmod to output individual counters for each (category, block,
counter) combination.

Co-Authored-by: Lukas Zapolskas <lukas.zapolskas@arm.com>
This commit is contained in:
Christoph Pillmayer 2026-03-20 11:03:17 +01:00
parent 51992c8556
commit 2e6a34bf0e

View file

@ -1,5 +1,6 @@
/*
* Copyright © 2021 Collabora, Ltd.
* Copyright © 2026 Arm, Ltd.
* SPDX-License-Identifier: MIT
*/
@ -86,39 +87,96 @@ PanfrostPerf::get_subinstance() {
return perf;
}
std::string
format_suffix(const char *fmt, uint8_t idx)
{
assert(strlen(fmt) < 200 && "fmt unreasonably long");
char buf[256];
std::snprintf(buf, sizeof(buf), fmt, idx);
return std::string(buf);
}
const char *
get_block_suffix(uint8_t category)
{
assert(category <= PAN_PERF_COUNTER_CAT_MAX);
switch (category) {
case PAN_PERF_COUNTER_CAT_MEMSYS:
return " (slice %u)";
case PAN_PERF_COUNTER_CAT_SHADER:
return " (core %u)";
default:
return nullptr;
}
return nullptr;
}
Counter::Units
convert_pan_units(enum pan_perf_counter_units unit)
{
switch (unit) {
case PAN_PERF_COUNTER_UNITS_PRIMITIVES:
return Counter::Units::Primitive;
case PAN_PERF_COUNTER_UNITS_INSTRUCTIONS:
return Counter::Units::Instruction;
case PAN_PERF_COUNTER_UNITS_BYTES:
return Counter::Units::Byte;
case PAN_PERF_COUNTER_UNITS_PIXELS:
return Counter::Units::Pixel;
default:
return Counter::Units::None;
}
}
std::pair<std::vector<CounterGroup>, std::vector<Counter>>
PanfrostPerf::create_available_counters() const
{
std::pair<std::vector<CounterGroup>, std::vector<Counter>> ret;
auto &[groups, counters] = ret;
size_t cid = 0;
uint32_t global_counter_id = 0;
const struct pan_perf_category *category = NULL;
for (uint32_t cat_idx = 0; cat_idx < perf->cfg->n_categories; ++cat_idx) {
assert(cat_idx < PAN_PERF_COUNTER_CAT_MAX);
category = &perf->cfg->categories[cat_idx];
for (uint32_t gid = 0; gid < perf->cfg->n_categories; ++gid) {
const auto &category = perf->cfg->categories[gid];
CounterGroup group = {};
group.id = gid;
group.name = category.name;
group.id = cat_idx;
group.name = category->name;
for (size_t id = 0; cid < category.n_counters; ++cid) {
Counter counter = {};
counter.id = cid;
counter.group = gid;
uint32_t n_blocks = perf->mem_layout.category[cat_idx].n_blocks;
for (uint32_t counter_idx = 0; counter_idx < category->n_counters;
++counter_idx) {
const struct pan_perf_counter *cinfo =
&category->counters[counter_idx];
counter.name = category.counters[id].name;
for (uint32_t block_idx = 0; block_idx < n_blocks; ++block_idx) {
const char *suffix = get_block_suffix(cat_idx);
const std::string name =
cinfo->name + (suffix ? format_suffix(suffix, block_idx) : "");
counter.set_getter([=](const Counter &c, const Driver &d) {
auto &pan_driver = PanfrostDriver::into(d);
struct pan_perf *perf = static_cast<struct pan_perf *>(
Counter counter = {};
counter.id = global_counter_id++;
counter.name = name;
counter.group = group.id;
counter.units = convert_pan_units(cinfo->units);
counter.set_getter([=](const Counter &c, const Driver &d) {
auto &pan_driver = PanfrostDriver::into(d);
struct pan_perf *perf = static_cast<struct pan_perf *>(
pan_driver.perf->get_subinstance());
const auto counter =
&perf->cfg->categories[gid].counters[id];
return int64_t(pan_perf_counter_read(counter, perf));
});
return pan_perf_counter_read_raw(
perf, (enum pan_perf_counter_categories)cat_idx, block_idx,
cinfo->offset);
});
group.counters.push_back(cid++);
counters.emplace_back(counter);
group.counters.push_back(counter.id);
counters.emplace_back(counter);
}
}
groups.push_back(group);