From 1bca1815805a41dd5b01dcc9620eeb5be0e96130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Molinari?= Date: Fri, 16 Jan 2026 16:30:08 +0100 Subject: [PATCH] pan/trace: Add wrappers for Mesa CPU scope traces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the PAN_TRACE_SCOPE() and PAN_TRACE_FUNC() wrappers based on MESA_TRACE_SCOPE_IF() in order to associate a category to each trace and let users select the set of tracing categories to enable at run-time through the PAN_CPU_TRACE environment variable. This makes Panfrost tracing an opt-in and avoids to CPU cost of tracing by default. There are 3 categories for now: - "lib" for the shared utilities - "gl" for the Gallium driver - "vk" for the Vulkan driver Each of these categories are divided into subcategories so that subsystems can easily be traced ("gl.csf" or "lib.kmod" for instance). Signed-off-by: Loïc Molinari Reviewed-by: Ashley Smith Reviewed-by: Boris Brezillon Part-of: --- src/panfrost/lib/meson.build | 1 + src/panfrost/lib/pan_trace.c | 102 +++++++++++++++++++++++++++++++++++ src/panfrost/lib/pan_trace.h | 93 ++++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 src/panfrost/lib/pan_trace.c create mode 100644 src/panfrost/lib/pan_trace.h diff --git a/src/panfrost/lib/meson.build b/src/panfrost/lib/meson.build index 0ee911924f6..956af6ce9b1 100644 --- a/src/panfrost/lib/meson.build +++ b/src/panfrost/lib/meson.build @@ -48,6 +48,7 @@ libpanfrost_lib_files = files( 'pan_tiler.c', 'pan_layout.c', 'pan_scratch.c', + 'pan_trace.c', 'pan_props.c', 'pan_util.c', 'pan_afbc.c', diff --git a/src/panfrost/lib/pan_trace.c b/src/panfrost/lib/pan_trace.c new file mode 100644 index 00000000000..4ce22928b3f --- /dev/null +++ b/src/panfrost/lib/pan_trace.c @@ -0,0 +1,102 @@ +/* + * Copyright © 2026 Amazon.com, Inc. or its affiliates. + * + * SPDX-License-Identifier: MIT + */ + +#include "pan_trace.h" + +#include "util/os_misc.h" + +#define PAN_TRACE_ENV_VAR "PAN_CPU_TRACE" + +#define CATEGORY(str, flag) { str, ARRAY_SIZE(str) - 1, (uint64_t) (flag) } + +/* To be kept in sync with the pan_trace_category enum in pan_trace.h. */ +/* clang-format off */ +static struct { + const char *str; + size_t len; + uint64_t flag; +} categories_table[] = { + /* Library categories. */ + CATEGORY("lib.afbc", PAN_TRACE_LIB_AFBC), + CATEGORY("lib.desc", PAN_TRACE_LIB_DESC), + CATEGORY("lib.kmod", PAN_TRACE_LIB_KMOD), + + CATEGORY("lib", PAN_TRACE_LIB_AFBC | + PAN_TRACE_LIB_DESC | + PAN_TRACE_LIB_KMOD), + + /* Gallium categories. */ + CATEGORY("gl.blit", PAN_TRACE_GL_BLIT), + CATEGORY("gl.bo", PAN_TRACE_GL_BO), + CATEGORY("gl.cmdstream", PAN_TRACE_GL_CMDSTREAM), + CATEGORY("gl.context", PAN_TRACE_GL_CONTEXT), + CATEGORY("gl.csf", PAN_TRACE_GL_CSF), + CATEGORY("gl.disk_cache", PAN_TRACE_GL_DISK_CACHE), + CATEGORY("gl.fb_preload", PAN_TRACE_GL_FB_PRELOAD), + CATEGORY("gl.jm", PAN_TRACE_GL_JM), + CATEGORY("gl.job", PAN_TRACE_GL_JOB), + CATEGORY("gl.mempool", PAN_TRACE_GL_MEMPOOL), + CATEGORY("gl.resource", PAN_TRACE_GL_RESOURCE), + CATEGORY("gl.shader", PAN_TRACE_GL_SHADER), + + CATEGORY("gl", PAN_TRACE_GL_BLIT | + PAN_TRACE_GL_BO | + PAN_TRACE_GL_CMDSTREAM | + PAN_TRACE_GL_CONTEXT | + PAN_TRACE_GL_CSF | + PAN_TRACE_GL_DISK_CACHE | + PAN_TRACE_GL_FB_PRELOAD | + PAN_TRACE_GL_JM | + PAN_TRACE_GL_JOB | + PAN_TRACE_GL_MEMPOOL | + PAN_TRACE_GL_RESOURCE | + PAN_TRACE_GL_SHADER), + + /* Vulkan categories. */ + CATEGORY("vk.csf", PAN_TRACE_VK_CSF), + + CATEGORY("vk", PAN_TRACE_VK_CSF), +}; +/* clang-format on */ + +uint64_t pan_trace_categories = 0; + +static bool +is_separator(char c) +{ + return c == ',' || c == ';' || c == ' '; +} + +void +pan_trace_init(void) +{ + const char *list = os_get_option(PAN_TRACE_ENV_VAR); + const char *str = NULL; + uint64_t categories = 0; + char prev_char = ','; + + if (!list) + return; + + /* Parse list and flag enabled categories. */ + for (int i = 0; prev_char; prev_char = list[i++]) { + if (!is_separator(list[i]) && list[i]) { + if (is_separator(prev_char)) + str = &list[i]; + } else if (!is_separator(prev_char)) { + for (int j = 0; j < ARRAY_SIZE(categories_table); j++) { + size_t len = &list[i] - str; + if (categories_table[j].len == len && + !strncasecmp(categories_table[j].str, str, len)) { + categories |= categories_table[j].flag; + break; + } + } + } + } + + pan_trace_categories = categories; +} diff --git a/src/panfrost/lib/pan_trace.h b/src/panfrost/lib/pan_trace.h new file mode 100644 index 00000000000..abfa169642a --- /dev/null +++ b/src/panfrost/lib/pan_trace.h @@ -0,0 +1,93 @@ +/* + * Copyright © 2026 Amazon.com, Inc. or its affiliates. + * + * SPDX-License-Identifier: MIT + */ + +#ifndef __PAN_TRACE_H +#define __PAN_TRACE_H + +#include "util/perf/cpu_trace.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Panfrost wrappers for Mesa CPU scope traces. + * + * CPU tracing (not to be confused with GPU command stream tracing with + * PAN_MESA_DEBUG=trace) is often enabled in release builds. Since each trace + * pushed down the underlying tracing backend (Perfetto, Gpuvis, sysprof, etc) + * has a slight cost, Panfrost extends the Mesa CPU scope traces by + * associating each trace to a category that must be enabled at run-time. This + * allows to keep adding useful trace points into Panfrost without worrying + * about the implied inherent latency. + * + * There are 3 categories ("lib" for the shared utilities, "gl" for Gallium, + * "vk" for PanVK) divided into subcategories so that subsystems can easily be + * traced. A list of categories can be passed to Panfrost through the + * PAN_CPU_TRACE environment variable like that: + * + * $ PAN_CPU_TRACE=gl,lib program + * + * Passing a category enables traces for all its subcategories. Subcategories + * can be passed instead for finer grained traces like that: + * + * $ PAN_CPU_TRACE=gl.blit,gl.bo,gl.job program + */ + +/* Panfrost trace categories. + * + * To be kept in sync with the categories_table array in pan_trace.c. + */ +/* clang-format off */ +enum pan_trace_category { + /* Library categories. */ + PAN_TRACE_LIB_AFBC = BITFIELD_BIT(1), /* "lib.afbc" */ + PAN_TRACE_LIB_DESC = BITFIELD_BIT(2), /* "lib.desc" */ + PAN_TRACE_LIB_KMOD = BITFIELD_BIT(3), /* "lib.kmod" */ + + /* Gallium categories. */ + PAN_TRACE_GL_BLIT = BITFIELD_BIT(4), /* "gl.blit" */ + PAN_TRACE_GL_BO = BITFIELD_BIT(5), /* "gl.bo" */ + PAN_TRACE_GL_CMDSTREAM = BITFIELD_BIT(6), /* "gl.cmdstream" */ + PAN_TRACE_GL_CONTEXT = BITFIELD_BIT(7), /* "gl.context" */ + PAN_TRACE_GL_CSF = BITFIELD_BIT(8), /* "gl.csf" */ + PAN_TRACE_GL_DISK_CACHE = BITFIELD_BIT(9), /* "gl.disk_cache" */ + PAN_TRACE_GL_FB_PRELOAD = BITFIELD_BIT(10), /* "gl.fb_preload" */ + PAN_TRACE_GL_JM = BITFIELD_BIT(11), /* "gl.jm" */ + PAN_TRACE_GL_JOB = BITFIELD_BIT(12), /* "gl.job" */ + PAN_TRACE_GL_MEMPOOL = BITFIELD_BIT(13), /* "gl.mempool" */ + PAN_TRACE_GL_RESOURCE = BITFIELD_BIT(14), /* "gl.resource" */ + PAN_TRACE_GL_SHADER = BITFIELD_BIT(15), /* "gl.shader" */ + + /* Vulkan categories. */ + PAN_TRACE_VK_CSF = BITFIELD_BIT(16), /* "vk.csf" */ +}; +/* clang-format on */ + +extern uint64_t pan_trace_categories; + +/* Add a Mesa CPU scope trace for a given Panfrost category using printf like + * formatting. + */ +#define PAN_TRACE_SCOPE(category, format, ...) \ + MESA_TRACE_SCOPE_IF(category & pan_trace_categories, format, ##__VA_ARGS__) + +/* Add a Mesa CPU scope trace for a given Panfrost category using current + * function name. + */ +#define PAN_TRACE_FUNC(category) \ + MESA_TRACE_FUNC_IF(category & pan_trace_categories) + +/* Parse the PAN_CPU_TRACE environment variable and initialize CPU tracing. + * The PAN_CPU_TRACE environment variable stores a list of categories (see + * enum pan_trace_category) separated by a comma, a semicolon or a space. + */ +void pan_trace_init(void); + +#ifdef __cplusplus +} /* extern C */ +#endif + +#endif /* __PAN_TRACE_H */