From b8889f5eaaf9de0d09cb1ddbf8f0701d04b6f452 Mon Sep 17 00:00:00 2001 From: Duncan Brawley Date: Mon, 5 Jan 2026 11:25:42 +0000 Subject: [PATCH] pvr: add basic support for shader statistics framework Mesa now has a statistics framework. This adds support for emitting additional statistics about PowerVR shaders for the Rogue architecture. Add support for emitting the following statistics: Code size, scratch size, spill count, temp count, loop count, number of inst groups, number of main inst groups, number of bitwise inst groups and number of control inst groups. Add support for new PCO_DEBUG_PRINT option "stats" to emit shader stats. Signed-off-by: Duncan Brawley Reviewed-by: Simon Perretta Part-of: --- docs/envvars.rst | 2 + src/imagination/pco/pco.c | 62 ++++++++++++++++++++++++++++++ src/imagination/pco/pco.h | 1 + src/imagination/pco/pco_binary.c | 3 ++ src/imagination/pco/pco_data.h | 2 + src/imagination/pco/pco_debug.c | 1 + src/imagination/pco/pco_internal.h | 19 +++++++++ src/imagination/pco/pco_print.c | 26 ++++++++++++- src/util/shader_stats.xml | 14 +++++++ 9 files changed, 129 insertions(+), 1 deletion(-) diff --git a/docs/envvars.rst b/docs/envvars.rst index 39e3c1be2aa..d69cd71cb34 100644 --- a/docs/envvars.rst +++ b/docs/envvars.rst @@ -2168,6 +2168,8 @@ PowerVR driver environment variables Print verbose IR. ``ra`` Print register alloc info. + ``stats`` + Print shader stats. .. envvar:: PCO_COLOR diff --git a/src/imagination/pco/pco.c b/src/imagination/pco/pco.c index d39453cf48a..42c76bd9db3 100644 --- a/src/imagination/pco/pco.c +++ b/src/imagination/pco/pco.c @@ -19,6 +19,7 @@ #include "util/list.h" #include "util/macros.h" #include "util/ralloc.h" +#include "util/shader_stats.h" #include #include @@ -316,3 +317,64 @@ pco_precomp_data pco_get_precomp_data(pco_shader *shader) .size_dwords = size_dwords, }; } + +/** + * \brief Returns statistics for a shader. + * + * \param[in] shader PCO shader. + * \return The shader statistics. + */ +struct pvr_stats pco_get_pvr_stats(pco_shader *shader) +{ + assert(shader->is_grouped); + + unsigned shader_size = pco_shader_binary_size(shader); + assert(shader_size > 0); + + unsigned loop_count = 0; + unsigned igrp_count = 0; + + unsigned main_count = 0; + unsigned bitwise_count = 0; + unsigned control_count = 0; + + pco_foreach_func_in_shader (func, shader) { + pco_foreach_loop_in_func (loop, func) { + loop_count++; + } + pco_foreach_igrp_in_func (igrp, func) { + igrp_count++; + switch (igrp->hdr.alutype) { + case PCO_ALUTYPE_MAIN: + main_count++; + break; + + case PCO_ALUTYPE_BITWISE: + bitwise_count++; + break; + + case PCO_ALUTYPE_CONTROL: + control_count++; + break; + + default: + UNREACHABLE("Invalid pco_alutype"); + } + } + } + + return (struct pvr_stats){ + .isa = PVR_STAT_ROGUE, + .rogue = (struct rogue_stats) { + .code_size = shader_size, + .scratch_size = shader->data.common.scratch, + .spill_count = shader->data.common.spilled_temps, + .temp_count = shader->data.common.temps, + .loop_count = loop_count, + .inst_group_count = igrp_count, + .main_inst_group_count = main_count, + .bitwise_inst_group_count = bitwise_count, + .control_inst_group_count = control_count, + }, + }; +} diff --git a/src/imagination/pco/pco.h b/src/imagination/pco/pco.h index 03e4b02103f..4b528e1b121 100644 --- a/src/imagination/pco/pco.h +++ b/src/imagination/pco/pco.h @@ -55,6 +55,7 @@ const void *pco_shader_binary_data(pco_shader *shader); void pco_validate_shader(pco_shader *shader, const char *when); +void pco_print_shader_stats(pco_shader *shader, FILE *fp); void pco_print_shader(pco_shader *shader, FILE *fp, const char *when); void pco_print_binary(pco_shader *shader, FILE *fp, const char *when); diff --git a/src/imagination/pco/pco_binary.c b/src/imagination/pco/pco_binary.c index ce78465cf0b..7c9aaf0fb35 100644 --- a/src/imagination/pco/pco_binary.c +++ b/src/imagination/pco/pco_binary.c @@ -127,6 +127,9 @@ void pco_encode_ir(pco_ctx *ctx, pco_shader *shader) if (pco_should_print_binary(shader)) pco_print_binary(shader, stdout, "after encoding"); + + if (pco_should_print_stats(shader)) + pco_print_shader_stats(shader, stdout); } /** diff --git a/src/imagination/pco/pco_data.h b/src/imagination/pco/pco_data.h index 4231e1e2e45..36c166f036e 100644 --- a/src/imagination/pco/pco_data.h +++ b/src/imagination/pco/pco_data.h @@ -256,4 +256,6 @@ typedef struct PACKED _pco_precomp_data { static_assert(sizeof(pco_precomp_data) == 8, "sizeof(pco_precomp_data) != 8"); pco_precomp_data pco_get_precomp_data(pco_shader *shader); + +struct pvr_stats pco_get_pvr_stats(pco_shader *shader); #endif /* PCO_DATA_H */ diff --git a/src/imagination/pco/pco_debug.c b/src/imagination/pco/pco_debug.c index 881ed0c60b5..54f5c254e35 100644 --- a/src/imagination/pco/pco_debug.c +++ b/src/imagination/pco/pco_debug.c @@ -42,6 +42,7 @@ static const struct debug_named_value pco_debug_print_options[] = { { "binary", PCO_DEBUG_PRINT_BINARY, "Print the resulting binary." }, { "verbose", PCO_DEBUG_PRINT_VERBOSE, "Print verbose IR." }, { "ra", PCO_DEBUG_PRINT_RA, "Print register alloc info." }, + { "stats", PCO_DEBUG_PRINT_STATS, "Print shader stats." }, DEBUG_NAMED_VALUE_END, }; diff --git a/src/imagination/pco/pco_internal.h b/src/imagination/pco/pco_internal.h index 50d42566e49..fb900c3bb14 100644 --- a/src/imagination/pco/pco_internal.h +++ b/src/imagination/pco/pco_internal.h @@ -75,6 +75,7 @@ enum pco_debug_print { PCO_DEBUG_PRINT_BINARY = BITFIELD64_BIT(6), PCO_DEBUG_PRINT_VERBOSE = BITFIELD64_BIT(7), PCO_DEBUG_PRINT_RA = BITFIELD64_BIT(8), + PCO_DEBUG_PRINT_STATS = BITFIELD64_BIT(9), }; extern uint64_t pco_debug_print; @@ -1727,6 +1728,24 @@ static inline bool pco_should_print_binary(pco_shader *shader) return true; } +static inline bool pco_should_print_stats(pco_shader *shader) +{ + if (!PCO_DEBUG_PRINT(STATS)) + return false; + + if (shader->is_internal && !PCO_DEBUG_PRINT(INTERNAL)) + return false; + + if (shader->stage == MESA_SHADER_VERTEX && !PCO_DEBUG_PRINT(VS)) + return false; + else if (shader->stage == MESA_SHADER_FRAGMENT && !PCO_DEBUG_PRINT(FS)) + return false; + else if (shader->stage == MESA_SHADER_COMPUTE && !PCO_DEBUG_PRINT(CS)) + return false; + + return true; +} + /* Interface with NIR. */ typedef union PACKED _pco_smp_flags { struct PACKED { diff --git a/src/imagination/pco/pco_print.c b/src/imagination/pco/pco_print.c index 3d17fcb0bf2..17ad1996f88 100644 --- a/src/imagination/pco/pco_print.c +++ b/src/imagination/pco/pco_print.c @@ -17,6 +17,7 @@ #include "util/bitscan.h" #include "util/list.h" #include "util/macros.h" +#include "util/shader_stats.h" #include "util/u_hexdump.h" #include @@ -1239,7 +1240,30 @@ static void _pco_print_shader_info(pco_print_state *state, pco_shader *shader) pco_printfi(state, "name: \"%s\"\n", shader->name); pco_printfi(state, "stage: %s\n", mesa_shader_stage_name(shader->stage)); pco_printfi(state, "internal: %s\n", true_false_str(shader->is_internal)); - /* TODO: more info/stats, e.g. temps/other regs used, etc.? */ +} + +/** + * \brief Print PCO shader stats. + * + * \param[in] shader PCO state. + * \param[in] fp Print target file pointer. + */ +void pco_print_shader_stats(pco_shader *shader, FILE *fp) +{ + pco_print_state state = { + .fp = fp, + .shader = shader, + .indent = 0, + .is_grouped = shader->is_grouped, + .verbose = PCO_DEBUG_PRINT(VERBOSE), + }; + + _pco_print_shader_info(&state, shader); + + struct pvr_stats stats = pco_get_pvr_stats(shader); + pvr_stats_fprintf(fp, + _mesa_shader_stage_to_abbrev(shader->nir->info.stage), + &stats); } /** diff --git a/src/util/shader_stats.xml b/src/util/shader_stats.xml index 7628275bded..7c764520a69 100644 --- a/src/util/shader_stats.xml +++ b/src/util/shader_stats.xml @@ -187,4 +187,18 @@ + + + + Binary size in bytes + Scratch size per instance in bytes + Number of spilled registers per instance + Number of allocated temp registers + Number of not unrolled loops in the shader + Total number of instruction groups + Number of main instruction groups + Number of bitwise instruction groups + Number of control instruction groups + +