* [PATCH v3 0/2] perf trace: Correct cpumask formatting and add --bitmask-list @ 2026-07-19 0:15 Aaron Tomlin 2026-07-19 0:15 ` [PATCH v3 1/2] perf trace: Correct default cpumask formatting to hexadecimal Aaron Tomlin 2026-07-19 0:15 ` [PATCH v3 2/2] perf trace: Add --bitmask-list command-line option Aaron Tomlin 0 siblings, 2 replies; 4+ messages in thread From: Aaron Tomlin @ 2026-07-19 0:15 UTC (permalink / raw) To: peterz, mingo, acme, namhyung Cc: mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter, james.clark, howardchu95, atomlin, neelx, chjohnst, sean, linux-perf-users, linux-kernel This series corrects cpumask formatting inside 'perf trace' and introduces a new command-line option to display these masks as human-readable CPU lists. Currently, when parsing tracepoints containing 'cpumask_t' fields (which are represented as dynamic non-array fields in libtraceevent), 'perf trace' incorrectly interprets and prints the raw length and offset descriptor as a decimal integer (i.e., "cpumask: 524320") rather than formatting the actual mask data. The first patch addresses this anomaly by introducing helper functions to correctly parse and extract raw bits from dynamic fields that do not have the TEP_FIELD_IS_ARRAY flag set. Once the raw bytes are resolved, 'perf trace' displays them as a zero-padded hexadecimal string by default. The second patch introduces a '--bitmask-list' option. When specified, formatting is delegated to bitmap_scnprintf(), allowing the resolved cpumask to be rendered as a condensed, human-readable list of CPUs (e.g., "0,2-5,7"). Changes since v2: - Provided an example output of the newly introduced '--bitmask-list' option (Namhyung Kim) - Updated the documentation to include the new option (Namhyung Kim) - Linked to v2: https://lore.kernel.org/lkml/20260717013544.257768-1-atomlin@atomlin.com/ Changes since v1: - Refactored cpumask parsing by moving the dynamic bitmask reconstruction logic into a new helper function, format_field__get_cpumask() - Made bitmask parsing cross-platform, word-size, and endianness-safe - Added a new helper function, bitmap_byte() to extract bytes from the host-native bitmask in a host-endianness-independent manner, simplifying hexadecimal cpumask formatting - Cleaned up trace__fprintf_tp_fields() to remove complex inline parsing logic - Linked to v1: https://lore.kernel.org/lkml/20260714162947.214270-1-atomlin@atomlin.com/ Aaron Tomlin (2): perf trace: Correct default cpumask formatting to hexadecimal perf trace: Add --bitmask-list command-line option tools/perf/Documentation/perf-trace.txt | 4 ++ tools/perf/builtin-trace.c | 75 ++++++++++++++++++--- tools/perf/util/evsel.c | 90 +++++++++++++++++++++++++ tools/perf/util/evsel.h | 6 ++ 4 files changed, 166 insertions(+), 9 deletions(-) -- 2.54.0 ^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v3 1/2] perf trace: Correct default cpumask formatting to hexadecimal 2026-07-19 0:15 [PATCH v3 0/2] perf trace: Correct cpumask formatting and add --bitmask-list Aaron Tomlin @ 2026-07-19 0:15 ` Aaron Tomlin 2026-07-20 5:02 ` Namhyung Kim 2026-07-19 0:15 ` [PATCH v3 2/2] perf trace: Add --bitmask-list command-line option Aaron Tomlin 1 sibling, 1 reply; 4+ messages in thread From: Aaron Tomlin @ 2026-07-19 0:15 UTC (permalink / raw) To: peterz, mingo, acme, namhyung Cc: mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter, james.clark, howardchu95, atomlin, neelx, chjohnst, sean, linux-perf-users, linux-kernel Currently, dynamic non-array fields such as 'cpumask_t' are mishandled in 'perf trace', causing the raw length and offset descriptors to be interpreted and displayed as a literal integer (e.g., "cpumask: 524320" instead of the actual mask data). Correct the parsing of dynamic fields that do not have the TEP_FIELD_IS_ARRAY flag set by introducing helper functions format_field__get_raw_data() and format_field__get_cpumask(). Using these helpers, resolve the pointer to the raw bits within the payload and format the cpumask as a zero-padded hexadecimal string by default. Fixes: c5e006cdbd27 ("perf trace: Support tracepoint dynamic char arrays") Signed-off-by: Aaron Tomlin <atomlin@atomlin.com> --- tools/perf/builtin-trace.c | 70 +++++++++++++++++++++++++---- tools/perf/util/evsel.c | 90 ++++++++++++++++++++++++++++++++++++++ tools/perf/util/evsel.h | 6 +++ 3 files changed, 157 insertions(+), 9 deletions(-) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index ba0f8749fc7d..f8b8431f9543 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -3207,6 +3207,21 @@ static void bpf_output__fprintf(struct trace *trace, ++trace->nr_events_printed; } +static unsigned char bitmap_byte(const unsigned long *mask, int byte_idx) +{ + unsigned char b_val = 0; + int bit_in_byte; + + for (bit_in_byte = 0; bit_in_byte < 8; bit_in_byte++) { + int b_idx = byte_idx * 8 + bit_in_byte; + int host_w_idx = b_idx / BITS_PER_LONG; + int host_bit_in_word = b_idx % BITS_PER_LONG; + if (mask[host_w_idx] & (1UL << host_bit_in_word)) + b_val |= (1 << bit_in_byte); + } + return b_val; +} + static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample *sample, struct thread *thread, void *augmented_args, int augmented_args_size) { @@ -3238,17 +3253,54 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample * syscall_arg.len = 0; syscall_arg.fmt = arg; if (field->flags & TEP_FIELD_IS_ARRAY) { - int offset = field->offset; - - if (field->flags & TEP_FIELD_IS_DYNAMIC) { - offset = format_field__intval(field, sample, evsel->needs_swap); - syscall_arg.len = offset >> 16; - offset &= 0xffff; - if (tep_field_is_relative(field->flags)) - offset += field->offset + field->size; + void *ptr = format_field__get_raw_data(field, sample, + evsel->needs_swap, + &syscall_arg.len); + + if (!ptr) { + pr_err("Problem processing %s field, skipping...\n", field->name); + continue; + } + val = (uintptr_t)ptr; + } else if ((field->flags & TEP_FIELD_IS_DYNAMIC) && + strstr(field->type, "cpumask")) { + unsigned long *mask = format_field__get_cpumask(field, sample, + evsel->needs_swap, + &syscall_arg.len); + + if (!mask) { + pr_err("Problem processing %s field, skipping...\n", field->name); + continue; } - val = (uintptr_t)(sample->raw_data + offset); + printed += scnprintf(bf + printed, size - printed, "%s", printed ? ", " : ""); + if (trace->show_arg_names) + printed += scnprintf(bf + printed, size - printed, "%s: ", field->name); + + if (syscall_arg.len == 0) { + printed += scnprintf(bf + printed, size - printed, "0"); + } else { + int i; + bool skip_zero = true; + + printed += scnprintf(bf + printed, size - printed, "0x"); + /* Print bytes from most significant to least significant */ + for (i = syscall_arg.len - 1; i >= 0; i--) { + unsigned char b_val = bitmap_byte(mask, i); + + if (skip_zero && b_val == 0 && i > 0) + continue; + + if (skip_zero) { + printed += scnprintf(bf + printed, size - printed, "%x", b_val); + skip_zero = false; + } else { + printed += scnprintf(bf + printed, size - printed, "%02x", b_val); + } + } + } + free(mask); + continue; } else val = format_field__intval(field, sample, evsel->needs_swap); /* diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ea9fa04429f0..912d77044141 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -16,9 +16,11 @@ #include <errno.h> #include <inttypes.h> #include <stdlib.h> +#include <string.h> #include <dirent.h> #include <linux/bitops.h> +#include <linux/bitmap.h> #include <linux/compiler.h> #include <linux/ctype.h> #include <linux/err.h> @@ -3933,6 +3935,94 @@ void *perf_sample__rawptr(struct perf_sample *sample, const char *name) return sample->raw_data + offset; } +void *format_field__get_raw_data(struct tep_format_field *field, struct + perf_sample *sample, bool needs_swap, + u16 *len_out) +{ + int offset = field->offset; + int size = field->size; + + if (field->flags & TEP_FIELD_IS_DYNAMIC) { + unsigned int dynamic_data; + + if (out_of_bounds(field, field->offset, field->size, sample->raw_size)) + return NULL; + + dynamic_data = format_field__intval(field, sample, needs_swap); + + offset = dynamic_data & 0xffff; + size = (dynamic_data >> 16) & 0xffff; + + if (tep_field_is_relative(field->flags)) + offset += field->offset + field->size; + } + + if (out_of_bounds(field, offset, size, sample->raw_size)) + return NULL; + + *len_out = size; + return sample->raw_data + offset; +} + +unsigned long *format_field__get_cpumask(struct tep_format_field *field, + struct perf_sample *sample, + bool needs_swap, u16 *len_out) +{ + u16 len; + void *ptr = format_field__get_raw_data(field, sample, needs_swap, &len); + unsigned long *mask; + struct perf_env *env; + bool target_is_64; + int target_word_size; + int nr_words; + int bit_idx; + int nbits; + + if (!ptr) + return NULL; + + nbits = len * 8; + mask = bitmap_zalloc(nbits ?: 1); + if (!mask) + return NULL; + + env = evsel__env(sample->evsel); + target_is_64 = env ? perf_env__kernel_is_64_bit(env) : (sizeof(void *) == 8); + target_word_size = target_is_64 ? 8 : 4; + nr_words = len / target_word_size; + + for (bit_idx = 0; bit_idx < nbits; bit_idx++) { + int w_idx = bit_idx / (target_word_size * 8); + int bit_in_word = bit_idx % (target_word_size * 8); + bool set = false; + + if (w_idx < nr_words) { + if (target_is_64) { + u64 word; + memcpy(&word, (unsigned char *)ptr + w_idx * 8, 8); + if (needs_swap) + word = bswap_64(word); + set = (word & (1ULL << bit_in_word)) != 0; + } else { + u32 word32; + memcpy(&word32, (unsigned char *)ptr + w_idx * 4, 4); + if (needs_swap) + word32 = bswap_32(word32); + set = (word32 & (1U << bit_in_word)) != 0; + } + } + + if (set) { + int host_w_idx = bit_idx / BITS_PER_LONG; + int host_bit_in_word = bit_idx % BITS_PER_LONG; + mask[host_w_idx] |= (1UL << host_bit_in_word); + } + } + + *len_out = len; + return mask; +} + u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sample, bool needs_swap) { diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 163fc2b6a7ea..02129a022ea3 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -400,6 +400,12 @@ static inline char *perf_sample__strval(struct perf_sample *sample, const char * struct tep_format_field; +void *format_field__get_raw_data(struct tep_format_field *field, + struct perf_sample *sample, + bool needs_swap, u16 *len_out); +unsigned long *format_field__get_cpumask(struct tep_format_field *field, + struct perf_sample *sample, + bool needs_swap, u16 *len_out); u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sample, bool needs_swap); #ifdef HAVE_LIBTRACEEVENT -- 2.54.0 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v3 1/2] perf trace: Correct default cpumask formatting to hexadecimal 2026-07-19 0:15 ` [PATCH v3 1/2] perf trace: Correct default cpumask formatting to hexadecimal Aaron Tomlin @ 2026-07-20 5:02 ` Namhyung Kim 0 siblings, 0 replies; 4+ messages in thread From: Namhyung Kim @ 2026-07-20 5:02 UTC (permalink / raw) To: Aaron Tomlin Cc: peterz, mingo, acme, mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter, james.clark, howardchu95, neelx, chjohnst, sean, linux-perf-users, linux-kernel Hello, On Sat, Jul 18, 2026 at 08:15:09PM -0400, Aaron Tomlin wrote: > Currently, dynamic non-array fields such as 'cpumask_t' are mishandled in > 'perf trace', causing the raw length and offset descriptors to be interpreted > and displayed as a literal integer (e.g., "cpumask: 524320" instead of the > actual mask data). > > Correct the parsing of dynamic fields that do not have the > TEP_FIELD_IS_ARRAY flag set by introducing helper functions > format_field__get_raw_data() and format_field__get_cpumask(). > Using these helpers, resolve the pointer to the raw bits within the > payload and format the cpumask as a zero-padded hexadecimal string by default. > > Fixes: c5e006cdbd27 ("perf trace: Support tracepoint dynamic char arrays") > Signed-off-by: Aaron Tomlin <atomlin@atomlin.com> > --- > tools/perf/builtin-trace.c | 70 +++++++++++++++++++++++++---- > tools/perf/util/evsel.c | 90 ++++++++++++++++++++++++++++++++++++++ > tools/perf/util/evsel.h | 6 +++ > 3 files changed, 157 insertions(+), 9 deletions(-) > > diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c > index ba0f8749fc7d..f8b8431f9543 100644 > --- a/tools/perf/builtin-trace.c > +++ b/tools/perf/builtin-trace.c > @@ -3207,6 +3207,21 @@ static void bpf_output__fprintf(struct trace *trace, > ++trace->nr_events_printed; > } > > +static unsigned char bitmap_byte(const unsigned long *mask, int byte_idx) > +{ > + unsigned char b_val = 0; > + int bit_in_byte; > + > + for (bit_in_byte = 0; bit_in_byte < 8; bit_in_byte++) { > + int b_idx = byte_idx * 8 + bit_in_byte; > + int host_w_idx = b_idx / BITS_PER_LONG; > + int host_bit_in_word = b_idx % BITS_PER_LONG; Better to add a blank line. > + if (mask[host_w_idx] & (1UL << host_bit_in_word)) > + b_val |= (1 << bit_in_byte); > + } > + return b_val; > +} > + > static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample *sample, > struct thread *thread, void *augmented_args, int augmented_args_size) > { > @@ -3238,17 +3253,54 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample * > syscall_arg.len = 0; > syscall_arg.fmt = arg; > if (field->flags & TEP_FIELD_IS_ARRAY) { > - int offset = field->offset; > - > - if (field->flags & TEP_FIELD_IS_DYNAMIC) { > - offset = format_field__intval(field, sample, evsel->needs_swap); > - syscall_arg.len = offset >> 16; > - offset &= 0xffff; > - if (tep_field_is_relative(field->flags)) > - offset += field->offset + field->size; > + void *ptr = format_field__get_raw_data(field, sample, > + evsel->needs_swap, > + &syscall_arg.len); > + > + if (!ptr) { > + pr_err("Problem processing %s field, skipping...\n", field->name); > + continue; > + } > + val = (uintptr_t)ptr; > + } else if ((field->flags & TEP_FIELD_IS_DYNAMIC) && > + strstr(field->type, "cpumask")) { > + unsigned long *mask = format_field__get_cpumask(field, sample, > + evsel->needs_swap, > + &syscall_arg.len); > + > + if (!mask) { > + pr_err("Problem processing %s field, skipping...\n", field->name); > + continue; > } > > - val = (uintptr_t)(sample->raw_data + offset); > + printed += scnprintf(bf + printed, size - printed, "%s", printed ? ", " : ""); > + if (trace->show_arg_names) > + printed += scnprintf(bf + printed, size - printed, "%s: ", field->name); > + > + if (syscall_arg.len == 0) { > + printed += scnprintf(bf + printed, size - printed, "0"); > + } else { > + int i; > + bool skip_zero = true; > + > + printed += scnprintf(bf + printed, size - printed, "0x"); > + /* Print bytes from most significant to least significant */ > + for (i = syscall_arg.len - 1; i >= 0; i--) { > + unsigned char b_val = bitmap_byte(mask, i); > + > + if (skip_zero && b_val == 0 && i > 0) > + continue; > + > + if (skip_zero) { > + printed += scnprintf(bf + printed, size - printed, "%x", b_val); > + skip_zero = false; > + } else { > + printed += scnprintf(bf + printed, size - printed, "%02x", b_val); > + } > + } > + } > + free(mask); > + continue; > } else > val = format_field__intval(field, sample, evsel->needs_swap); > /* > diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c > index ea9fa04429f0..912d77044141 100644 > --- a/tools/perf/util/evsel.c > +++ b/tools/perf/util/evsel.c > @@ -16,9 +16,11 @@ > #include <errno.h> > #include <inttypes.h> > #include <stdlib.h> > +#include <string.h> > > #include <dirent.h> > #include <linux/bitops.h> > +#include <linux/bitmap.h> > #include <linux/compiler.h> > #include <linux/ctype.h> > #include <linux/err.h> > @@ -3933,6 +3935,94 @@ void *perf_sample__rawptr(struct perf_sample *sample, const char *name) > return sample->raw_data + offset; > } > > +void *format_field__get_raw_data(struct tep_format_field *field, struct > + perf_sample *sample, bool needs_swap, > + u16 *len_out) > +{ > + int offset = field->offset; > + int size = field->size; > + > + if (field->flags & TEP_FIELD_IS_DYNAMIC) { > + unsigned int dynamic_data; > + > + if (out_of_bounds(field, field->offset, field->size, sample->raw_size)) > + return NULL; > + > + dynamic_data = format_field__intval(field, sample, needs_swap); > + > + offset = dynamic_data & 0xffff; > + size = (dynamic_data >> 16) & 0xffff; > + > + if (tep_field_is_relative(field->flags)) > + offset += field->offset + field->size; > + } > + > + if (out_of_bounds(field, offset, size, sample->raw_size)) > + return NULL; > + > + *len_out = size; > + return sample->raw_data + offset; > +} > + > +unsigned long *format_field__get_cpumask(struct tep_format_field *field, > + struct perf_sample *sample, > + bool needs_swap, u16 *len_out) > +{ > + u16 len; > + void *ptr = format_field__get_raw_data(field, sample, needs_swap, &len); > + unsigned long *mask; > + struct perf_env *env; > + bool target_is_64; > + int target_word_size; > + int nr_words; > + int bit_idx; > + int nbits; > + > + if (!ptr) > + return NULL; > + > + nbits = len * 8; > + mask = bitmap_zalloc(nbits ?: 1); > + if (!mask) > + return NULL; > + > + env = evsel__env(sample->evsel); > + target_is_64 = env ? perf_env__kernel_is_64_bit(env) : (sizeof(void *) == 8); > + target_word_size = target_is_64 ? 8 : 4; > + nr_words = len / target_word_size; > + > + for (bit_idx = 0; bit_idx < nbits; bit_idx++) { > + int w_idx = bit_idx / (target_word_size * 8); > + int bit_in_word = bit_idx % (target_word_size * 8); > + bool set = false; > + > + if (w_idx < nr_words) { Nit: Can you change it to something like below to reduce indentation? if (w_idx >= nr_words) break; Thanks, Namhyung > + if (target_is_64) { > + u64 word; > + memcpy(&word, (unsigned char *)ptr + w_idx * 8, 8); > + if (needs_swap) > + word = bswap_64(word); > + set = (word & (1ULL << bit_in_word)) != 0; > + } else { > + u32 word32; > + memcpy(&word32, (unsigned char *)ptr + w_idx * 4, 4); > + if (needs_swap) > + word32 = bswap_32(word32); > + set = (word32 & (1U << bit_in_word)) != 0; > + } > + } > + > + if (set) { > + int host_w_idx = bit_idx / BITS_PER_LONG; > + int host_bit_in_word = bit_idx % BITS_PER_LONG; > + mask[host_w_idx] |= (1UL << host_bit_in_word); > + } > + } > + > + *len_out = len; > + return mask; > +} > + > u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sample, > bool needs_swap) > { > diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h > index 163fc2b6a7ea..02129a022ea3 100644 > --- a/tools/perf/util/evsel.h > +++ b/tools/perf/util/evsel.h > @@ -400,6 +400,12 @@ static inline char *perf_sample__strval(struct perf_sample *sample, const char * > > struct tep_format_field; > > +void *format_field__get_raw_data(struct tep_format_field *field, > + struct perf_sample *sample, > + bool needs_swap, u16 *len_out); > +unsigned long *format_field__get_cpumask(struct tep_format_field *field, > + struct perf_sample *sample, > + bool needs_swap, u16 *len_out); > u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sample, bool needs_swap); > > #ifdef HAVE_LIBTRACEEVENT > -- > 2.54.0 > ^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v3 2/2] perf trace: Add --bitmask-list command-line option 2026-07-19 0:15 [PATCH v3 0/2] perf trace: Correct cpumask formatting and add --bitmask-list Aaron Tomlin 2026-07-19 0:15 ` [PATCH v3 1/2] perf trace: Correct default cpumask formatting to hexadecimal Aaron Tomlin @ 2026-07-19 0:15 ` Aaron Tomlin 1 sibling, 0 replies; 4+ messages in thread From: Aaron Tomlin @ 2026-07-19 0:15 UTC (permalink / raw) To: peterz, mingo, acme, namhyung Cc: mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter, james.clark, howardchu95, atomlin, neelx, chjohnst, sean, linux-perf-users, linux-kernel Introduce a new '--bitmask-list' command-line option for 'perf trace'. When this option is specified, the formatting of cpumasks is delegated to bitmap_scnprintf(), enabling cpumasks to be displayed as a condensed, human-readable list (e.g., "0,2-5,7") instead of the default hexadecimal representation. An example is provided below: ❯ sudo ./perf trace --show-cpu --bitmask-list --event ipi:ipi_send_cpumask --max-event 5 0.000 [000] Xorg/1434 ipi:ipi_send_cpumask(cpumask: 2-3,6, callsite: 0xffffffff9994f8e4, callback: 0xffffffff9994fdd0) 694.527 [002] chrome/2894 ipi:ipi_send_cpumask(cpumask: 1,3-5, callsite: 0xffffffff9994f8e4, callback: 0xffffffff9994fdd0) 2666.608 [003] Chrome_ChildIO/2948 ipi:ipi_send_cpumask(cpumask: 4,7, callsite: 0xffffffff9994f8e4, callback: 0xffffffff9994fdd0) 2673.638 [000] Chrome_IOThrea/2920 ipi:ipi_send_cpumask(cpumask: 2-5, callsite: 0xffffffff9994f8e4, callback: 0xffffffff9994fdd0) 2714.228 [005] chrome/3375 ipi:ipi_send_cpumask(cpumask: 0-4,6-7, callsite: 0xffffffff9994f8e4, callback: 0xffffffff9994fdd0) Signed-off-by: Aaron Tomlin <atomlin@atomlin.com> --- tools/perf/Documentation/perf-trace.txt | 4 ++++ tools/perf/builtin-trace.c | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index d0b6c771a1b9..d20b43ea3d37 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt @@ -247,6 +247,10 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. pretty-printing serves as a fallback to hand-crafted pretty printers, as the latter can better pretty-print integer flags and struct pointers. +--bitmask-list:: + Show bitmasks as a human-readable, condensed list (e.g. "0,2-5,7") + instead of the default hexadecimal representation. + --bpf-summary:: Collect system call statistics in BPF. This is only for live mode and works well with -s/--summary option where no argument information is diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index f8b8431f9543..0142a16830de 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -226,6 +226,7 @@ struct trace { bool force; bool vfs_getname; bool force_btf; + bool bitmask_list; bool summary_bpf; int trace_pgfaults; char *perfconfig_events; @@ -3279,6 +3280,9 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample * if (syscall_arg.len == 0) { printed += scnprintf(bf + printed, size - printed, "0"); + } else if (trace->bitmask_list) { + printed += bitmap_scnprintf(mask, syscall_arg.len * 8, + bf + printed, size - printed); } else { int i; bool skip_zero = true; @@ -5589,6 +5593,7 @@ int cmd_trace(int argc, const char **argv) "start"), OPT_BOOLEAN(0, "force-btf", &trace.force_btf, "Prefer btf_dump general pretty printer" "to customized ones"), + OPT_BOOLEAN(0, "bitmask-list", &trace.bitmask_list, "Show bitmask as a human-readable list"), OPT_BOOLEAN(0, "bpf-summary", &trace.summary_bpf, "Summary syscall stats in BPF"), OPT_INTEGER(0, "max-summary", &trace.max_summary, "Max number of entries in the summary."), -- 2.54.0 ^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-07-20 5:02 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-19 0:15 [PATCH v3 0/2] perf trace: Correct cpumask formatting and add --bitmask-list Aaron Tomlin 2026-07-19 0:15 ` [PATCH v3 1/2] perf trace: Correct default cpumask formatting to hexadecimal Aaron Tomlin 2026-07-20 5:02 ` Namhyung Kim 2026-07-19 0:15 ` [PATCH v3 2/2] perf trace: Add --bitmask-list command-line option Aaron Tomlin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox