[PATCH] perf trace: Support --bitmask-list with --libtraceevent
From: Aaron Tomlin
Date: Fri Oct 02 2026 - 17:31:58 EST
Commit ab74d1fbe061 ("perf trace: Add --bitmask-list command-line option")
introduced the --bitmask-list option to display cpumasks and bitmasks as
condensed, human-readable range lists (e.g. "0,2-5,7") instead of the
default hexadecimal format.
However, that implementation only augmented trace__fprintf_tp_fields().
When --libtraceevent is specified, event formatting is delegated to
event_format__fprintf(), which bypasses trace__fprintf_tp_fields() and
relies directly on libtraceevent.
In libtraceevent, tracepoint bitmask fields defined using __get_bitmask()
are parsed into TEP_PRINT_BITMASK AST nodes and unconditionally formatted
as raw 32-bit hex chunks (e.g. "00000000,00000005"), ignoring the
--bitmask-list command-line option.
While a dedicated configuration API in libtraceevent would be the ideal
long-term solution, that requires a new upstream libtraceevent release
and conditional version checks in perf. To provide immediate support for
existing installations, traverse the event format's print argument AST
in perf trace and rewrite any TEP_PRINT_BITMASK nodes to TEP_PRINT_CPUMASK
when --bitmask-list is enabled. Both types share the identical union
payload (arg->bitmask.field), but TEP_PRINT_CPUMASK instructs
libtraceevent's print engine (print_cpumask_to_seq()) to render the mask
as a condensed range list.
To avoid any per-sample overhead in the event handling fast path, perform
this transformation once during tracepoint setup via
trace__init_tp_bitmask_list() for both live tracing (cmd_trace()) and
recording replay (trace__replay()), leaving trace__event_handler()
untouched. All enum values of enum tep_print_arg_type are explicitly
covered in the switch statement to satisfy -Wswitch-enum under -Werror.
Signed-off-by: Aaron Tomlin <atomlin@xxxxxxxxxxx>
---
tools/perf/builtin-trace.c | 75 ++++++++++++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index c3c7f1f85c53..57249df65fe3 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -4857,6 +4857,77 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
goto out_put_evlist;
}
+#ifdef HAVE_LIBTRACEEVENT
+static void tep_print_arg__set_bitmask_list(struct tep_print_arg *arg)
+{
+ for (; arg; arg = arg->next) {
+ switch (arg->type) {
+ case TEP_PRINT_BITMASK:
+ arg->type = TEP_PRINT_CPUMASK;
+ break;
+ case TEP_PRINT_OP:
+ tep_print_arg__set_bitmask_list(arg->op.left);
+ tep_print_arg__set_bitmask_list(arg->op.right);
+ break;
+ case TEP_PRINT_FUNC:
+ tep_print_arg__set_bitmask_list(arg->func.args);
+ break;
+ case TEP_PRINT_FLAGS:
+ tep_print_arg__set_bitmask_list(arg->flags.field);
+ break;
+ case TEP_PRINT_SYMBOL:
+ tep_print_arg__set_bitmask_list(arg->symbol.field);
+ break;
+ case TEP_PRINT_HEX:
+ tep_print_arg__set_bitmask_list(arg->hex.field);
+ tep_print_arg__set_bitmask_list(arg->hex.size);
+ break;
+ case TEP_PRINT_INT_ARRAY:
+ tep_print_arg__set_bitmask_list(arg->int_array.field);
+ tep_print_arg__set_bitmask_list(arg->int_array.count);
+ tep_print_arg__set_bitmask_list(arg->int_array.el_size);
+ break;
+ case TEP_PRINT_TYPE:
+ tep_print_arg__set_bitmask_list(arg->typecast.item);
+ break;
+ case TEP_PRINT_DYNAMIC_ARRAY:
+ tep_print_arg__set_bitmask_list(arg->dynarray.index);
+ break;
+ case TEP_PRINT_NULL:
+ case TEP_PRINT_ATOM:
+ case TEP_PRINT_FIELD:
+ case TEP_PRINT_STRING:
+ case TEP_PRINT_BSTRING:
+ case TEP_PRINT_DYNAMIC_ARRAY_LEN:
+ case TEP_PRINT_HEX_STR:
+ case TEP_PRINT_CPUMASK:
+ default:
+ break;
+ }
+ }
+}
+
+static void trace__init_tp_bitmask_list(struct trace *trace, struct evlist *evlist)
+{
+ struct evsel *evsel;
+
+ if (!trace->libtraceevent_print || !trace->bitmask_list)
+ return;
+
+ evlist__for_each_entry(evlist, evsel) {
+ struct tep_event *tp_format = evsel__tp_format(evsel);
+
+ if (tp_format)
+ tep_print_arg__set_bitmask_list(tp_format->print_fmt.args);
+ }
+}
+#else
+static void trace__init_tp_bitmask_list(struct trace *trace __maybe_unused,
+ struct evlist *evlist __maybe_unused)
+{
+}
+#endif
+
static int trace__replay(struct trace *trace)
{
const struct evsel_str_handler handlers[] = {
@@ -4908,6 +4979,8 @@ static int trace__replay(struct trace *trace)
if (err)
goto out;
+ trace__init_tp_bitmask_list(trace, session->evlist);
+
evsel = evlist__find_tracepoint_by_name(session->evlist, "raw_syscalls:sys_enter");
trace->syscalls.events.sys_enter = evsel;
/* older kernels have syscalls tp versus raw_syscalls */
@@ -5814,6 +5887,8 @@ int cmd_trace(int argc, const char **argv)
if (use_btf)
trace__load_vmlinux_btf(&trace);
+
+ trace__init_tp_bitmask_list(&trace, trace.evlist);
}
/*
--
2.55.0