* [RFC/PATCH 1/2] perf check: Add 'system' subcommand @ 2025-09-18 6:39 Namhyung Kim 2025-09-18 6:39 ` [RFC/PATCH 2/2] perf check: Add 'pmu' subcommand Namhyung Kim 2025-09-18 15:48 ` [RFC/PATCH 1/2] perf check: Add 'system' subcommand Ian Rogers 0 siblings, 2 replies; 8+ messages in thread From: Namhyung Kim @ 2025-09-18 6:39 UTC (permalink / raw) To: Arnaldo Carvalho de Melo, Ian Rogers, Kan Liang Cc: Jiri Olsa, Adrian Hunter, Peter Zijlstra, Ingo Molnar, LKML, linux-perf-users The 'perf check system' is to check sysctl settings related to perf. By default it'd print the following output. $ perf check system perf_event_paranoid = 2 # non-root can profile user code only perf_event_max_stack = 127 # maximum callchain length perf_event_mlock_kb = 516 # maximum ring buffer size (including a header page) for non-root nmi_watchdog = 1 # a hardware PMU counter may be used by the kernel kptr_restrict = 0 # kernel pointers are printed as-is The -q option suppresses the description. It can also take command line argument to match specific items. $ perf check system -q nmi nmi_watchdog = 1 Signed-off-by: Namhyung Kim <namhyung@kernel.org> --- tools/perf/Documentation/perf-check.txt | 20 ++++ tools/perf/builtin-check.c | 116 +++++++++++++++++++++++- 2 files changed, 135 insertions(+), 1 deletion(-) diff --git a/tools/perf/Documentation/perf-check.txt b/tools/perf/Documentation/perf-check.txt index ee92042082f73121..34dccc29d90d2fdf 100644 --- a/tools/perf/Documentation/perf-check.txt +++ b/tools/perf/Documentation/perf-check.txt @@ -10,6 +10,7 @@ SYNOPSIS [verse] 'perf check' [<options>] 'perf check' {feature <feature_list>} [<options>] +'perf check' {system <setting_list>} [<options>] DESCRIPTION ----------- @@ -22,6 +23,9 @@ compiled-in/built-in or not. Also, 'perf check feature' returns with exit status 0 if the feature is built-in, otherwise returns with exit status 1. +If the subcommand 'system' is used, then system settins are printed on +the standard output with explanation. + SUBCOMMANDS ----------- @@ -69,6 +73,22 @@ SUBCOMMANDS zlib / HAVE_ZLIB_SUPPORT zstd / HAVE_ZSTD_SUPPORT +system:: + + Print system settings (sysctl) that affect perf behaviors. + + Example Usage: + perf check system + perf check system watchdog + + Supported settings: + perf_event_paranoid + perf_event_max_stack + perf_event_mlock_kb + nmi_watchdog + kptr_restrict + + OPTIONS ------- -q:: diff --git a/tools/perf/builtin-check.c b/tools/perf/builtin-check.c index b1e205871ab17a77..1c7c6bb5da5ccbf2 100644 --- a/tools/perf/builtin-check.c +++ b/tools/perf/builtin-check.c @@ -3,24 +3,30 @@ #include "color.h" #include "util/debug.h" #include "util/header.h" +#include <api/fs/fs.h> #include <tools/config.h> #include <stdbool.h> #include <stdio.h> #include <string.h> #include <subcmd/parse-options.h> -static const char * const check_subcommands[] = { "feature", NULL }; +static const char * const check_subcommands[] = { "feature", "system", NULL }; static struct option check_options[] = { OPT_BOOLEAN('q', "quiet", &quiet, "do not show any warnings or messages"), OPT_END() }; static struct option check_feature_options[] = { OPT_PARENT(check_options) }; +static struct option check_system_options[] = { OPT_PARENT(check_options) }; static const char *check_usage[] = { NULL, NULL }; static const char *check_feature_usage[] = { "perf check feature <feature_list>", NULL }; +static const char *check_system_usage[] = { + "perf check system", + NULL +}; #define FEATURE_STATUS(name_, macro_) { \ .name = name_, \ @@ -166,6 +172,112 @@ static int subcommand_feature(int argc, const char **argv) return !feature_enabled; } +static int read_sysctl_kernel_int(const char *name) +{ + char path[128]; + int value; + + scnprintf(path, sizeof(path), "kernel/%s", name); + if (sysctl__read_int(path, &value)) + return INT_MAX; + + return value; +} + +static const char *system_help_perf_event_paranoid(int value) +{ + if (value == 2) + return "non-root can profile user code only"; + if (value == 1) + return "non-root can profile kernel and user code"; + if (value == 0) + return "non-root can profile system-wide w/o tracepoints data"; + if (value < 0) + return "no restrictions"; + + return "non-root cannot use perf event"; +} + +static const char *system_help_perf_event_max_stack(int value __maybe_unused) +{ + return "maximum callchain length"; +} + +static const char *system_help_perf_event_mlock_kb(int value __maybe_unused) +{ + return "maximum ring buffer size (including a header page) for non-root"; +} + +static const char *system_help_nmi_watchdog(int value) +{ + if (value) + return "a hardware PMU counter may be used by the kernel"; + + return "perf can use full PMU counters"; +} + +static const char *system_help_kptr_restrict(int value) +{ + if (value == 0) + return "kernel pointers are printed as-is"; + if (value == 1) + return "non-root cannot see the kernel pointers"; + if (value == 2) + return "root may not see some kernel pointers"; + + return "unknown value"; +} + +/** + * Usage: 'perf check system <settings>' + * + * Show system settings that affect perf behavior. + */ +static int subcommand_system(int argc, const char **argv) +{ +#define PERF_SYSCTL(name) { #name, system_help_##name } + struct { + const char *name; + const char *(*help)(int value); + } sysctls[] = { + PERF_SYSCTL(perf_event_paranoid), + PERF_SYSCTL(perf_event_max_stack), + PERF_SYSCTL(perf_event_mlock_kb), + PERF_SYSCTL(nmi_watchdog), + PERF_SYSCTL(kptr_restrict), + }; +#undef PERF_SYSCTL + + argc = parse_options(argc, argv, check_system_options, + check_system_usage, 0); + + for (size_t i = 0; i < ARRAY_SIZE(sysctls); i++) { + int value; + + if (argc) { + bool found = false; + + /* only show entries match to command line arguments */ + for (int k = 0; k < argc; k++) { + if (strstr(sysctls[i].name, argv[k])) { + found = true; + break; + } + } + if (!found) + continue; + } + + value = read_sysctl_kernel_int(sysctls[i].name); + printf("%-20s = %d", sysctls[i].name, value); + if (!quiet) + printf("\t# %s", sysctls[i].help(value)); + printf("\n"); + } + + return 0; +} + int cmd_check(int argc, const char **argv) { argc = parse_options_subcommand(argc, argv, check_options, @@ -176,6 +288,8 @@ int cmd_check(int argc, const char **argv) if (strcmp(argv[0], "feature") == 0) return subcommand_feature(argc, argv); + if (strcmp(argv[0], "system") == 0) + return subcommand_system(argc, argv); /* If no subcommand matched above, print usage help */ pr_err("Unknown subcommand: %s\n", argv[0]); -- 2.51.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [RFC/PATCH 2/2] perf check: Add 'pmu' subcommand 2025-09-18 6:39 [RFC/PATCH 1/2] perf check: Add 'system' subcommand Namhyung Kim @ 2025-09-18 6:39 ` Namhyung Kim 2025-09-18 15:33 ` Ian Rogers 2025-09-18 15:48 ` [RFC/PATCH 1/2] perf check: Add 'system' subcommand Ian Rogers 1 sibling, 1 reply; 8+ messages in thread From: Namhyung Kim @ 2025-09-18 6:39 UTC (permalink / raw) To: Arnaldo Carvalho de Melo, Ian Rogers, Kan Liang Cc: Jiri Olsa, Adrian Hunter, Peter Zijlstra, Ingo Molnar, LKML, linux-perf-users The 'perf check pmu' command will show information about PMUs in the system like below: $ perf check pmu | head cpu_atom: type = 10 core PMU: cpus = 16-27 caps: branches = 32 caps: max_precise = 3 caps: pmu_name = alderlake_hybrid cpu_core: type = 4 core PMU: cpus = 0-15 caps: branches = 32 caps: max_precise = 3 caps: pmu_name = alderlake_hybrid The -q option will make it print the name and type of PMUs only. It also takes arguments to show matching PMUs only. $ perf check pmu -q uncore uncore_arb_0: type = 27 uncore_arb_1: type = 28 uncore_cbox_0: type = 15 uncore_cbox_1: type = 16 uncore_cbox_2: type = 17 uncore_cbox_3: type = 18 uncore_cbox_4: type = 19 uncore_cbox_5: type = 20 uncore_cbox_6: type = 21 uncore_cbox_7: type = 22 uncore_cbox_8: type = 23 uncore_cbox_9: type = 24 uncore_cbox_10: type = 25 uncore_cbox_11: type = 26 uncore_clock: type = 29 uncore_imc_free_running_0: type = 32 uncore_imc_free_running_1: type = 33 uncore_imc_0: type = 30 uncore_imc_1: type = 31 Signed-off-by: Namhyung Kim <namhyung@kernel.org> --- tools/perf/Documentation/perf-check.txt | 12 +++++ tools/perf/builtin-check.c | 60 ++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/tools/perf/Documentation/perf-check.txt b/tools/perf/Documentation/perf-check.txt index 34dccc29d90d2fdf..2fa007698c0f0814 100644 --- a/tools/perf/Documentation/perf-check.txt +++ b/tools/perf/Documentation/perf-check.txt @@ -11,6 +11,7 @@ SYNOPSIS 'perf check' [<options>] 'perf check' {feature <feature_list>} [<options>] 'perf check' {system <setting_list>} [<options>] +'perf check' {pmu <name_list>} [<options>] DESCRIPTION ----------- @@ -26,6 +27,9 @@ is built-in, otherwise returns with exit status 1. If the subcommand 'system' is used, then system settins are printed on the standard output with explanation. +If the subcommand 'pmu' is used, then available PMU information is printed +on the standard output with explanation. + SUBCOMMANDS ----------- @@ -88,6 +92,14 @@ SUBCOMMANDS nmi_watchdog kptr_restrict +pmu:: + + Print PMU information available in the system. + + Example Usage: + perf check pmu + perf check pmu <name> + OPTIONS ------- diff --git a/tools/perf/builtin-check.c b/tools/perf/builtin-check.c index 1c7c6bb5da5ccbf2..f3d034a94b1227c7 100644 --- a/tools/perf/builtin-check.c +++ b/tools/perf/builtin-check.c @@ -3,6 +3,8 @@ #include "color.h" #include "util/debug.h" #include "util/header.h" +#include "util/pmu.h" +#include "util/pmus.h" #include <api/fs/fs.h> #include <tools/config.h> #include <stdbool.h> @@ -10,13 +12,14 @@ #include <string.h> #include <subcmd/parse-options.h> -static const char * const check_subcommands[] = { "feature", "system", NULL }; +static const char * const check_subcommands[] = { "feature", "system", "pmu", NULL }; static struct option check_options[] = { OPT_BOOLEAN('q', "quiet", &quiet, "do not show any warnings or messages"), OPT_END() }; static struct option check_feature_options[] = { OPT_PARENT(check_options) }; static struct option check_system_options[] = { OPT_PARENT(check_options) }; +static struct option check_pmu_options[] = { OPT_PARENT(check_options) }; static const char *check_usage[] = { NULL, NULL }; static const char *check_feature_usage[] = { @@ -27,6 +30,10 @@ static const char *check_system_usage[] = { "perf check system", NULL }; +static const char *check_pmu_usage[] = { + "perf check pmu", + NULL +}; #define FEATURE_STATUS(name_, macro_) { \ .name = name_, \ @@ -278,6 +285,55 @@ static int subcommand_system(int argc, const char **argv) return 0; } +/** + * Usage: 'perf check pmu <names>' + * + * Show PMU information. + */ +static int subcommand_pmu(int argc, const char **argv) +{ + struct perf_pmu *pmu = NULL; + struct perf_pmu_caps *caps; + + argc = parse_options(argc, argv, check_pmu_options, check_pmu_usage, 0); + + while ((pmu = perf_pmus__scan(pmu)) != NULL) { + if (argc) { + bool found = false; + + /* only show entries match to command line arguments */ + for (int k = 0; k < argc; k++) { + if (strstr(pmu->name, argv[k])) { + found = true; + break; + } + } + if (!found) + continue; + } + + printf("%s: type = %u\n", pmu->name, pmu->type); + if (quiet) + continue; + + if (pmu->is_core || pmu->is_uncore) { + printf(" %score PMU", pmu->is_uncore ? "un" : ""); + if (!perf_cpu_map__is_empty(pmu->cpus)) { + printf(": %s = ", pmu->is_core ? "cpus" : "cpumask"); + cpu_map__fprintf(pmu->cpus, stdout); + } else { + printf("\n"); + } + } + + perf_pmu__caps_parse(pmu); + list_for_each_entry(caps, &pmu->caps, list) { + printf(" caps: %s = %s\n", caps->name, caps->value); + } + } + return 0; +} + int cmd_check(int argc, const char **argv) { argc = parse_options_subcommand(argc, argv, check_options, @@ -290,6 +346,8 @@ int cmd_check(int argc, const char **argv) return subcommand_feature(argc, argv); if (strcmp(argv[0], "system") == 0) return subcommand_system(argc, argv); + if (strcmp(argv[0], "pmu") == 0) + return subcommand_pmu(argc, argv); /* If no subcommand matched above, print usage help */ pr_err("Unknown subcommand: %s\n", argv[0]); -- 2.51.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [RFC/PATCH 2/2] perf check: Add 'pmu' subcommand 2025-09-18 6:39 ` [RFC/PATCH 2/2] perf check: Add 'pmu' subcommand Namhyung Kim @ 2025-09-18 15:33 ` Ian Rogers 2025-09-19 20:27 ` Namhyung Kim 0 siblings, 1 reply; 8+ messages in thread From: Ian Rogers @ 2025-09-18 15:33 UTC (permalink / raw) To: Namhyung Kim Cc: Arnaldo Carvalho de Melo, Kan Liang, Jiri Olsa, Adrian Hunter, Peter Zijlstra, Ingo Molnar, LKML, linux-perf-users On Wed, Sep 17, 2025 at 11:39 PM Namhyung Kim <namhyung@kernel.org> wrote: > > The 'perf check pmu' command will show information about PMUs in the > system like below: > > $ perf check pmu | head > cpu_atom: type = 10 > core PMU: cpus = 16-27 > caps: branches = 32 > caps: max_precise = 3 > caps: pmu_name = alderlake_hybrid > cpu_core: type = 4 > core PMU: cpus = 0-15 > caps: branches = 32 > caps: max_precise = 3 > caps: pmu_name = alderlake_hybrid > > The -q option will make it print the name and type of PMUs only. It > also takes arguments to show matching PMUs only. > > $ perf check pmu -q uncore > uncore_arb_0: type = 27 > uncore_arb_1: type = 28 > uncore_cbox_0: type = 15 > uncore_cbox_1: type = 16 > uncore_cbox_2: type = 17 > uncore_cbox_3: type = 18 > uncore_cbox_4: type = 19 > uncore_cbox_5: type = 20 > uncore_cbox_6: type = 21 > uncore_cbox_7: type = 22 > uncore_cbox_8: type = 23 > uncore_cbox_9: type = 24 > uncore_cbox_10: type = 25 > uncore_cbox_11: type = 26 > uncore_clock: type = 29 > uncore_imc_free_running_0: type = 32 > uncore_imc_free_running_1: type = 33 > uncore_imc_0: type = 30 > uncore_imc_1: type = 31 > > Signed-off-by: Namhyung Kim <namhyung@kernel.org> > --- > tools/perf/Documentation/perf-check.txt | 12 +++++ > tools/perf/builtin-check.c | 60 ++++++++++++++++++++++++- > 2 files changed, 71 insertions(+), 1 deletion(-) > > diff --git a/tools/perf/Documentation/perf-check.txt b/tools/perf/Documentation/perf-check.txt > index 34dccc29d90d2fdf..2fa007698c0f0814 100644 > --- a/tools/perf/Documentation/perf-check.txt > +++ b/tools/perf/Documentation/perf-check.txt > @@ -11,6 +11,7 @@ SYNOPSIS > 'perf check' [<options>] > 'perf check' {feature <feature_list>} [<options>] > 'perf check' {system <setting_list>} [<options>] > +'perf check' {pmu <name_list>} [<options>] > > DESCRIPTION > ----------- > @@ -26,6 +27,9 @@ is built-in, otherwise returns with exit status 1. > If the subcommand 'system' is used, then system settins are printed on > the standard output with explanation. > > +If the subcommand 'pmu' is used, then available PMU information is printed > +on the standard output with explanation. > + > SUBCOMMANDS > ----------- > > @@ -88,6 +92,14 @@ SUBCOMMANDS > nmi_watchdog > kptr_restrict > > +pmu:: > + > + Print PMU information available in the system. > + > + Example Usage: > + perf check pmu > + perf check pmu <name> > + > > OPTIONS > ------- > diff --git a/tools/perf/builtin-check.c b/tools/perf/builtin-check.c > index 1c7c6bb5da5ccbf2..f3d034a94b1227c7 100644 > --- a/tools/perf/builtin-check.c > +++ b/tools/perf/builtin-check.c > @@ -3,6 +3,8 @@ > #include "color.h" > #include "util/debug.h" > #include "util/header.h" > +#include "util/pmu.h" > +#include "util/pmus.h" > #include <api/fs/fs.h> > #include <tools/config.h> > #include <stdbool.h> > @@ -10,13 +12,14 @@ > #include <string.h> > #include <subcmd/parse-options.h> > > -static const char * const check_subcommands[] = { "feature", "system", NULL }; > +static const char * const check_subcommands[] = { "feature", "system", "pmu", NULL }; > static struct option check_options[] = { > OPT_BOOLEAN('q', "quiet", &quiet, "do not show any warnings or messages"), > OPT_END() > }; > static struct option check_feature_options[] = { OPT_PARENT(check_options) }; > static struct option check_system_options[] = { OPT_PARENT(check_options) }; > +static struct option check_pmu_options[] = { OPT_PARENT(check_options) }; > > static const char *check_usage[] = { NULL, NULL }; > static const char *check_feature_usage[] = { > @@ -27,6 +30,10 @@ static const char *check_system_usage[] = { > "perf check system", > NULL > }; > +static const char *check_pmu_usage[] = { > + "perf check pmu", > + NULL > +}; > > #define FEATURE_STATUS(name_, macro_) { \ > .name = name_, \ > @@ -278,6 +285,55 @@ static int subcommand_system(int argc, const char **argv) > return 0; > } > > +/** > + * Usage: 'perf check pmu <names>' > + * > + * Show PMU information. > + */ > +static int subcommand_pmu(int argc, const char **argv) > +{ > + struct perf_pmu *pmu = NULL; > + struct perf_pmu_caps *caps; > + > + argc = parse_options(argc, argv, check_pmu_options, check_pmu_usage, 0); > + > + while ((pmu = perf_pmus__scan(pmu)) != NULL) { > + if (argc) { > + bool found = false; > + > + /* only show entries match to command line arguments */ > + for (int k = 0; k < argc; k++) { > + if (strstr(pmu->name, argv[k])) { To avoid divergence from parse-events it may be better to use perf_pmu__wildcard_match? There is also perf_pmus__scan_matching_wildcard. > + found = true; > + break; > + } > + } > + if (!found) > + continue; > + } > + > + printf("%s: type = %u\n", pmu->name, pmu->type); > + if (quiet) > + continue; > + > + if (pmu->is_core || pmu->is_uncore) { > + printf(" %score PMU", pmu->is_uncore ? "un" : ""); > + if (!perf_cpu_map__is_empty(pmu->cpus)) { > + printf(": %s = ", pmu->is_core ? "cpus" : "cpumask"); The cpus file is only generally present on hybrid systems. I don't think this needs to be core/uncore dependent - the only thing I've ever seen fail that test are some ARM uncore PMUs. I'd always dump this as cpumask, when !core and !uncore then the default all online CPUs cpumask is important information as that probably isn't the cpumask you want with an uncore PMU. > + cpu_map__fprintf(pmu->cpus, stdout); > + } else { > + printf("\n"); > + } > + } > + > + perf_pmu__caps_parse(pmu); > + list_for_each_entry(caps, &pmu->caps, list) { > + printf(" caps: %s = %s\n", caps->name, caps->value); > + } > + } > + return 0; If not found return an error? Thanks, Ian > +} > + > int cmd_check(int argc, const char **argv) > { > argc = parse_options_subcommand(argc, argv, check_options, > @@ -290,6 +346,8 @@ int cmd_check(int argc, const char **argv) > return subcommand_feature(argc, argv); > if (strcmp(argv[0], "system") == 0) > return subcommand_system(argc, argv); > + if (strcmp(argv[0], "pmu") == 0) > + return subcommand_pmu(argc, argv); > > /* If no subcommand matched above, print usage help */ > pr_err("Unknown subcommand: %s\n", argv[0]); > -- > 2.51.0 > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC/PATCH 2/2] perf check: Add 'pmu' subcommand 2025-09-18 15:33 ` Ian Rogers @ 2025-09-19 20:27 ` Namhyung Kim 2025-09-20 14:04 ` Ian Rogers 0 siblings, 1 reply; 8+ messages in thread From: Namhyung Kim @ 2025-09-19 20:27 UTC (permalink / raw) To: Ian Rogers Cc: Arnaldo Carvalho de Melo, Kan Liang, Jiri Olsa, Adrian Hunter, Peter Zijlstra, Ingo Molnar, LKML, linux-perf-users On Thu, Sep 18, 2025 at 08:33:30AM -0700, Ian Rogers wrote: > On Wed, Sep 17, 2025 at 11:39 PM Namhyung Kim <namhyung@kernel.org> wrote: > > > > The 'perf check pmu' command will show information about PMUs in the > > system like below: > > > > $ perf check pmu | head > > cpu_atom: type = 10 > > core PMU: cpus = 16-27 > > caps: branches = 32 > > caps: max_precise = 3 > > caps: pmu_name = alderlake_hybrid > > cpu_core: type = 4 > > core PMU: cpus = 0-15 > > caps: branches = 32 > > caps: max_precise = 3 > > caps: pmu_name = alderlake_hybrid > > > > The -q option will make it print the name and type of PMUs only. It > > also takes arguments to show matching PMUs only. > > > > $ perf check pmu -q uncore > > uncore_arb_0: type = 27 > > uncore_arb_1: type = 28 > > uncore_cbox_0: type = 15 > > uncore_cbox_1: type = 16 > > uncore_cbox_2: type = 17 > > uncore_cbox_3: type = 18 > > uncore_cbox_4: type = 19 > > uncore_cbox_5: type = 20 > > uncore_cbox_6: type = 21 > > uncore_cbox_7: type = 22 > > uncore_cbox_8: type = 23 > > uncore_cbox_9: type = 24 > > uncore_cbox_10: type = 25 > > uncore_cbox_11: type = 26 > > uncore_clock: type = 29 > > uncore_imc_free_running_0: type = 32 > > uncore_imc_free_running_1: type = 33 > > uncore_imc_0: type = 30 > > uncore_imc_1: type = 31 > > > > Signed-off-by: Namhyung Kim <namhyung@kernel.org> > > --- > > tools/perf/Documentation/perf-check.txt | 12 +++++ > > tools/perf/builtin-check.c | 60 ++++++++++++++++++++++++- > > 2 files changed, 71 insertions(+), 1 deletion(-) > > > > diff --git a/tools/perf/Documentation/perf-check.txt b/tools/perf/Documentation/perf-check.txt > > index 34dccc29d90d2fdf..2fa007698c0f0814 100644 > > --- a/tools/perf/Documentation/perf-check.txt > > +++ b/tools/perf/Documentation/perf-check.txt > > @@ -11,6 +11,7 @@ SYNOPSIS > > 'perf check' [<options>] > > 'perf check' {feature <feature_list>} [<options>] > > 'perf check' {system <setting_list>} [<options>] > > +'perf check' {pmu <name_list>} [<options>] > > > > DESCRIPTION > > ----------- > > @@ -26,6 +27,9 @@ is built-in, otherwise returns with exit status 1. > > If the subcommand 'system' is used, then system settins are printed on > > the standard output with explanation. > > > > +If the subcommand 'pmu' is used, then available PMU information is printed > > +on the standard output with explanation. > > + > > SUBCOMMANDS > > ----------- > > > > @@ -88,6 +92,14 @@ SUBCOMMANDS > > nmi_watchdog > > kptr_restrict > > > > +pmu:: > > + > > + Print PMU information available in the system. > > + > > + Example Usage: > > + perf check pmu > > + perf check pmu <name> > > + > > > > OPTIONS > > ------- > > diff --git a/tools/perf/builtin-check.c b/tools/perf/builtin-check.c > > index 1c7c6bb5da5ccbf2..f3d034a94b1227c7 100644 > > --- a/tools/perf/builtin-check.c > > +++ b/tools/perf/builtin-check.c > > @@ -3,6 +3,8 @@ > > #include "color.h" > > #include "util/debug.h" > > #include "util/header.h" > > +#include "util/pmu.h" > > +#include "util/pmus.h" > > #include <api/fs/fs.h> > > #include <tools/config.h> > > #include <stdbool.h> > > @@ -10,13 +12,14 @@ > > #include <string.h> > > #include <subcmd/parse-options.h> > > > > -static const char * const check_subcommands[] = { "feature", "system", NULL }; > > +static const char * const check_subcommands[] = { "feature", "system", "pmu", NULL }; > > static struct option check_options[] = { > > OPT_BOOLEAN('q', "quiet", &quiet, "do not show any warnings or messages"), > > OPT_END() > > }; > > static struct option check_feature_options[] = { OPT_PARENT(check_options) }; > > static struct option check_system_options[] = { OPT_PARENT(check_options) }; > > +static struct option check_pmu_options[] = { OPT_PARENT(check_options) }; > > > > static const char *check_usage[] = { NULL, NULL }; > > static const char *check_feature_usage[] = { > > @@ -27,6 +30,10 @@ static const char *check_system_usage[] = { > > "perf check system", > > NULL > > }; > > +static const char *check_pmu_usage[] = { > > + "perf check pmu", > > + NULL > > +}; > > > > #define FEATURE_STATUS(name_, macro_) { \ > > .name = name_, \ > > @@ -278,6 +285,55 @@ static int subcommand_system(int argc, const char **argv) > > return 0; > > } > > > > +/** > > + * Usage: 'perf check pmu <names>' > > + * > > + * Show PMU information. > > + */ > > +static int subcommand_pmu(int argc, const char **argv) > > +{ > > + struct perf_pmu *pmu = NULL; > > + struct perf_pmu_caps *caps; > > + > > + argc = parse_options(argc, argv, check_pmu_options, check_pmu_usage, 0); > > + > > + while ((pmu = perf_pmus__scan(pmu)) != NULL) { > > + if (argc) { > > + bool found = false; > > + > > + /* only show entries match to command line arguments */ > > + for (int k = 0; k < argc; k++) { > > + if (strstr(pmu->name, argv[k])) { > > To avoid divergence from parse-events it may be better to use > perf_pmu__wildcard_match? There is also > perf_pmus__scan_matching_wildcard. Sounds good, will change. > > > + found = true; > > + break; > > + } > > + } > > + if (!found) > > + continue; > > + } > > + > > + printf("%s: type = %u\n", pmu->name, pmu->type); > > + if (quiet) > > + continue; > > + > > + if (pmu->is_core || pmu->is_uncore) { > > + printf(" %score PMU", pmu->is_uncore ? "un" : ""); > > + if (!perf_cpu_map__is_empty(pmu->cpus)) { > > + printf(": %s = ", pmu->is_core ? "cpus" : "cpumask"); > > The cpus file is only generally present on hybrid systems. I don't > think this needs to be core/uncore dependent - the only thing I've > ever seen fail that test are some ARM uncore PMUs. I'd always dump > this as cpumask, when !core and !uncore then the default all online > CPUs cpumask is important information as that probably isn't the > cpumask you want with an uncore PMU. Ok, I can remove the core/uncore check. But I think it's better to print them only if they actually have maps to inform users that those PMUs need some more care. :) > > > + cpu_map__fprintf(pmu->cpus, stdout); > > + } else { > > + printf("\n"); > > + } > > + } > > + > > + perf_pmu__caps_parse(pmu); > > + list_for_each_entry(caps, &pmu->caps, list) { > > + printf(" caps: %s = %s\n", caps->name, caps->value); > > + } > > + } > > + return 0; > > If not found return an error? Yep, good idea. Thanks for the review! Namhyung > > > +} > > + > > int cmd_check(int argc, const char **argv) > > { > > argc = parse_options_subcommand(argc, argv, check_options, > > @@ -290,6 +346,8 @@ int cmd_check(int argc, const char **argv) > > return subcommand_feature(argc, argv); > > if (strcmp(argv[0], "system") == 0) > > return subcommand_system(argc, argv); > > + if (strcmp(argv[0], "pmu") == 0) > > + return subcommand_pmu(argc, argv); > > > > /* If no subcommand matched above, print usage help */ > > pr_err("Unknown subcommand: %s\n", argv[0]); > > -- > > 2.51.0 > > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC/PATCH 2/2] perf check: Add 'pmu' subcommand 2025-09-19 20:27 ` Namhyung Kim @ 2025-09-20 14:04 ` Ian Rogers 0 siblings, 0 replies; 8+ messages in thread From: Ian Rogers @ 2025-09-20 14:04 UTC (permalink / raw) To: Namhyung Kim Cc: Arnaldo Carvalho de Melo, Kan Liang, Jiri Olsa, Adrian Hunter, Peter Zijlstra, Ingo Molnar, LKML, linux-perf-users On Fri, Sep 19, 2025 at 1:27 PM Namhyung Kim <namhyung@kernel.org> wrote: > > On Thu, Sep 18, 2025 at 08:33:30AM -0700, Ian Rogers wrote: > > On Wed, Sep 17, 2025 at 11:39 PM Namhyung Kim <namhyung@kernel.org> wrote: > > > > > > The 'perf check pmu' command will show information about PMUs in the > > > system like below: > > > > > > $ perf check pmu | head > > > cpu_atom: type = 10 > > > core PMU: cpus = 16-27 > > > caps: branches = 32 > > > caps: max_precise = 3 > > > caps: pmu_name = alderlake_hybrid > > > cpu_core: type = 4 > > > core PMU: cpus = 0-15 > > > caps: branches = 32 > > > caps: max_precise = 3 > > > caps: pmu_name = alderlake_hybrid > > > > > > The -q option will make it print the name and type of PMUs only. It > > > also takes arguments to show matching PMUs only. > > > > > > $ perf check pmu -q uncore > > > uncore_arb_0: type = 27 > > > uncore_arb_1: type = 28 > > > uncore_cbox_0: type = 15 > > > uncore_cbox_1: type = 16 > > > uncore_cbox_2: type = 17 > > > uncore_cbox_3: type = 18 > > > uncore_cbox_4: type = 19 > > > uncore_cbox_5: type = 20 > > > uncore_cbox_6: type = 21 > > > uncore_cbox_7: type = 22 > > > uncore_cbox_8: type = 23 > > > uncore_cbox_9: type = 24 > > > uncore_cbox_10: type = 25 > > > uncore_cbox_11: type = 26 > > > uncore_clock: type = 29 > > > uncore_imc_free_running_0: type = 32 > > > uncore_imc_free_running_1: type = 33 > > > uncore_imc_0: type = 30 > > > uncore_imc_1: type = 31 > > > > > > Signed-off-by: Namhyung Kim <namhyung@kernel.org> > > > --- > > > tools/perf/Documentation/perf-check.txt | 12 +++++ > > > tools/perf/builtin-check.c | 60 ++++++++++++++++++++++++- > > > 2 files changed, 71 insertions(+), 1 deletion(-) > > > > > > diff --git a/tools/perf/Documentation/perf-check.txt b/tools/perf/Documentation/perf-check.txt > > > index 34dccc29d90d2fdf..2fa007698c0f0814 100644 > > > --- a/tools/perf/Documentation/perf-check.txt > > > +++ b/tools/perf/Documentation/perf-check.txt > > > @@ -11,6 +11,7 @@ SYNOPSIS > > > 'perf check' [<options>] > > > 'perf check' {feature <feature_list>} [<options>] > > > 'perf check' {system <setting_list>} [<options>] > > > +'perf check' {pmu <name_list>} [<options>] > > > > > > DESCRIPTION > > > ----------- > > > @@ -26,6 +27,9 @@ is built-in, otherwise returns with exit status 1. > > > If the subcommand 'system' is used, then system settins are printed on > > > the standard output with explanation. > > > > > > +If the subcommand 'pmu' is used, then available PMU information is printed > > > +on the standard output with explanation. > > > + > > > SUBCOMMANDS > > > ----------- > > > > > > @@ -88,6 +92,14 @@ SUBCOMMANDS > > > nmi_watchdog > > > kptr_restrict > > > > > > +pmu:: > > > + > > > + Print PMU information available in the system. > > > + > > > + Example Usage: > > > + perf check pmu > > > + perf check pmu <name> > > > + > > > > > > OPTIONS > > > ------- > > > diff --git a/tools/perf/builtin-check.c b/tools/perf/builtin-check.c > > > index 1c7c6bb5da5ccbf2..f3d034a94b1227c7 100644 > > > --- a/tools/perf/builtin-check.c > > > +++ b/tools/perf/builtin-check.c > > > @@ -3,6 +3,8 @@ > > > #include "color.h" > > > #include "util/debug.h" > > > #include "util/header.h" > > > +#include "util/pmu.h" > > > +#include "util/pmus.h" > > > #include <api/fs/fs.h> > > > #include <tools/config.h> > > > #include <stdbool.h> > > > @@ -10,13 +12,14 @@ > > > #include <string.h> > > > #include <subcmd/parse-options.h> > > > > > > -static const char * const check_subcommands[] = { "feature", "system", NULL }; > > > +static const char * const check_subcommands[] = { "feature", "system", "pmu", NULL }; > > > static struct option check_options[] = { > > > OPT_BOOLEAN('q', "quiet", &quiet, "do not show any warnings or messages"), > > > OPT_END() > > > }; > > > static struct option check_feature_options[] = { OPT_PARENT(check_options) }; > > > static struct option check_system_options[] = { OPT_PARENT(check_options) }; > > > +static struct option check_pmu_options[] = { OPT_PARENT(check_options) }; > > > > > > static const char *check_usage[] = { NULL, NULL }; > > > static const char *check_feature_usage[] = { > > > @@ -27,6 +30,10 @@ static const char *check_system_usage[] = { > > > "perf check system", > > > NULL > > > }; > > > +static const char *check_pmu_usage[] = { > > > + "perf check pmu", > > > + NULL > > > +}; > > > > > > #define FEATURE_STATUS(name_, macro_) { \ > > > .name = name_, \ > > > @@ -278,6 +285,55 @@ static int subcommand_system(int argc, const char **argv) > > > return 0; > > > } > > > > > > +/** > > > + * Usage: 'perf check pmu <names>' > > > + * > > > + * Show PMU information. > > > + */ > > > +static int subcommand_pmu(int argc, const char **argv) > > > +{ > > > + struct perf_pmu *pmu = NULL; > > > + struct perf_pmu_caps *caps; > > > + > > > + argc = parse_options(argc, argv, check_pmu_options, check_pmu_usage, 0); > > > + > > > + while ((pmu = perf_pmus__scan(pmu)) != NULL) { > > > + if (argc) { > > > + bool found = false; > > > + > > > + /* only show entries match to command line arguments */ > > > + for (int k = 0; k < argc; k++) { > > > + if (strstr(pmu->name, argv[k])) { > > > > To avoid divergence from parse-events it may be better to use > > perf_pmu__wildcard_match? There is also > > perf_pmus__scan_matching_wildcard. > > Sounds good, will change. > > > > > > + found = true; > > > + break; > > > + } > > > + } > > > + if (!found) > > > + continue; > > > + } > > > + > > > + printf("%s: type = %u\n", pmu->name, pmu->type); > > > + if (quiet) > > > + continue; > > > + > > > + if (pmu->is_core || pmu->is_uncore) { > > > + printf(" %score PMU", pmu->is_uncore ? "un" : ""); > > > + if (!perf_cpu_map__is_empty(pmu->cpus)) { > > > + printf(": %s = ", pmu->is_core ? "cpus" : "cpumask"); > > > > The cpus file is only generally present on hybrid systems. I don't > > think this needs to be core/uncore dependent - the only thing I've > > ever seen fail that test are some ARM uncore PMUs. I'd always dump > > this as cpumask, when !core and !uncore then the default all online > > CPUs cpumask is important information as that probably isn't the > > cpumask you want with an uncore PMU. > > Ok, I can remove the core/uncore check. But I think it's better to > print them only if they actually have maps to inform users that those > PMUs need some more care. :) So we have to deal with a bit of history in the code: 1. if there is a cpumask file then this is an uncore PMU and the cpumask is the one given. 2. if there is a cpus file then this is a core PMU typically a hybrid one. 3. if there is no cpus file then all online CPUs are used in the cpumask as this is probably a core PMU. Being a core PMU is only set in the case of the PMU name being "cpu" or "cpum_cf" or for case 2. https://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/tree/tools/perf/util/pmu.c?h=perf-tools-next#n1966 So there is the broken PMU case where no cpumask is provided for an uncore PMU. Historically we treat that as having a cpumask of all online CPUs. There are other workaround case the perf code deals with: - the cpumasks are rewritten for the benefit of NUMA support when there is sub-NUMA clustering: https://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/tree/tools/perf/arch/x86/util/pmu.c?h=perf-tools-next#n309 - on ARM there has been a history of broken cpumasks (note on ARM both arm and arm64 arch directories get into the perf build): https://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/tree/tools/perf/arch/arm/util/pmu.c?h=perf-tools-next#n43 There was an unresolved bug on ARM PMUs where CPU hot plugging wouldn't update the cpumask and so perf would request typically uncore events be opened on a CPU that was offline. A driver fix for that was sent. IIRC Will Deacon had concerns that the kernel's perf API was racy, a CPU hot plug could happen immediately after the read, and so that never landed. I believe this means that if you offline a CPU that is in an ARM uncore cpumask the intersection computation above will make the cpumask empty and so we therefore open the event on all the online CPUs. Doing that will likely cause multiplexing, aggregation of the same count many times and a massive miscalculation of the uncore event's count. I therefore believe, with the caveats above, that the cpumask on perf's internal pmu can never be empty. As it is a complicated thing that has real implications for how events get opened, I think it is best to just always print it. Thanks, Ian > > > > > + cpu_map__fprintf(pmu->cpus, stdout); > > > + } else { > > > + printf("\n"); > > > + } > > > + } > > > + > > > + perf_pmu__caps_parse(pmu); > > > + list_for_each_entry(caps, &pmu->caps, list) { > > > + printf(" caps: %s = %s\n", caps->name, caps->value); > > > + } > > > + } > > > + return 0; > > > > If not found return an error? > > Yep, good idea. > > Thanks for the review! > Namhyung > > > > > > +} > > > + > > > int cmd_check(int argc, const char **argv) > > > { > > > argc = parse_options_subcommand(argc, argv, check_options, > > > @@ -290,6 +346,8 @@ int cmd_check(int argc, const char **argv) > > > return subcommand_feature(argc, argv); > > > if (strcmp(argv[0], "system") == 0) > > > return subcommand_system(argc, argv); > > > + if (strcmp(argv[0], "pmu") == 0) > > > + return subcommand_pmu(argc, argv); > > > > > > /* If no subcommand matched above, print usage help */ > > > pr_err("Unknown subcommand: %s\n", argv[0]); > > > -- > > > 2.51.0 > > > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC/PATCH 1/2] perf check: Add 'system' subcommand 2025-09-18 6:39 [RFC/PATCH 1/2] perf check: Add 'system' subcommand Namhyung Kim 2025-09-18 6:39 ` [RFC/PATCH 2/2] perf check: Add 'pmu' subcommand Namhyung Kim @ 2025-09-18 15:48 ` Ian Rogers 2025-09-18 20:12 ` Arnaldo Carvalho de Melo 2025-09-19 20:21 ` Namhyung Kim 1 sibling, 2 replies; 8+ messages in thread From: Ian Rogers @ 2025-09-18 15:48 UTC (permalink / raw) To: Namhyung Kim Cc: Arnaldo Carvalho de Melo, Kan Liang, Jiri Olsa, Adrian Hunter, Peter Zijlstra, Ingo Molnar, LKML, linux-perf-users On Wed, Sep 17, 2025 at 11:39 PM Namhyung Kim <namhyung@kernel.org> wrote: > > The 'perf check system' is to check sysctl settings related to perf. > By default it'd print the following output. > > $ perf check system > perf_event_paranoid = 2 # non-root can profile user code only > perf_event_max_stack = 127 # maximum callchain length > perf_event_mlock_kb = 516 # maximum ring buffer size (including a header page) for non-root > nmi_watchdog = 1 # a hardware PMU counter may be used by the kernel > kptr_restrict = 0 # kernel pointers are printed as-is > > The -q option suppresses the description. It can also take command line > argument to match specific items. > > $ perf check system -q nmi > nmi_watchdog = 1 > > Signed-off-by: Namhyung Kim <namhyung@kernel.org> > --- > tools/perf/Documentation/perf-check.txt | 20 ++++ > tools/perf/builtin-check.c | 116 +++++++++++++++++++++++- > 2 files changed, 135 insertions(+), 1 deletion(-) > > diff --git a/tools/perf/Documentation/perf-check.txt b/tools/perf/Documentation/perf-check.txt > index ee92042082f73121..34dccc29d90d2fdf 100644 > --- a/tools/perf/Documentation/perf-check.txt > +++ b/tools/perf/Documentation/perf-check.txt > @@ -10,6 +10,7 @@ SYNOPSIS > [verse] > 'perf check' [<options>] > 'perf check' {feature <feature_list>} [<options>] > +'perf check' {system <setting_list>} [<options>] > > DESCRIPTION > ----------- > @@ -22,6 +23,9 @@ compiled-in/built-in or not. > Also, 'perf check feature' returns with exit status 0 if the feature > is built-in, otherwise returns with exit status 1. > > +If the subcommand 'system' is used, then system settins are printed on > +the standard output with explanation. > + > SUBCOMMANDS > ----------- > > @@ -69,6 +73,22 @@ SUBCOMMANDS > zlib / HAVE_ZLIB_SUPPORT > zstd / HAVE_ZSTD_SUPPORT > > +system:: > + > + Print system settings (sysctl) that affect perf behaviors. > + > + Example Usage: > + perf check system > + perf check system watchdog > + > + Supported settings: > + perf_event_paranoid > + perf_event_max_stack > + perf_event_mlock_kb > + nmi_watchdog > + kptr_restrict > + > + > OPTIONS > ------- > -q:: > diff --git a/tools/perf/builtin-check.c b/tools/perf/builtin-check.c > index b1e205871ab17a77..1c7c6bb5da5ccbf2 100644 > --- a/tools/perf/builtin-check.c > +++ b/tools/perf/builtin-check.c > @@ -3,24 +3,30 @@ > #include "color.h" > #include "util/debug.h" > #include "util/header.h" > +#include <api/fs/fs.h> > #include <tools/config.h> > #include <stdbool.h> > #include <stdio.h> > #include <string.h> > #include <subcmd/parse-options.h> > > -static const char * const check_subcommands[] = { "feature", NULL }; > +static const char * const check_subcommands[] = { "feature", "system", NULL }; > static struct option check_options[] = { > OPT_BOOLEAN('q', "quiet", &quiet, "do not show any warnings or messages"), > OPT_END() > }; > static struct option check_feature_options[] = { OPT_PARENT(check_options) }; > +static struct option check_system_options[] = { OPT_PARENT(check_options) }; > > static const char *check_usage[] = { NULL, NULL }; > static const char *check_feature_usage[] = { > "perf check feature <feature_list>", > NULL > }; > +static const char *check_system_usage[] = { > + "perf check system", > + NULL > +}; > > #define FEATURE_STATUS(name_, macro_) { \ > .name = name_, \ > @@ -166,6 +172,112 @@ static int subcommand_feature(int argc, const char **argv) > return !feature_enabled; > } > > +static int read_sysctl_kernel_int(const char *name) > +{ > + char path[128]; > + int value; > + > + scnprintf(path, sizeof(path), "kernel/%s", name); > + if (sysctl__read_int(path, &value)) > + return INT_MAX; > + > + return value; > +} > + > +static const char *system_help_perf_event_paranoid(int value) > +{ > + if (value == 2) > + return "non-root can profile user code only"; > + if (value == 1) > + return "non-root can profile kernel and user code"; > + if (value == 0) > + return "non-root can profile system-wide w/o tracepoints data"; > + if (value < 0) > + return "no restrictions"; > + > + return "non-root cannot use perf event"; > +} > + > +static const char *system_help_perf_event_max_stack(int value __maybe_unused) > +{ > + return "maximum callchain length"; > +} > + > +static const char *system_help_perf_event_mlock_kb(int value __maybe_unused) > +{ > + return "maximum ring buffer size (including a header page) for non-root"; > +} > + > +static const char *system_help_nmi_watchdog(int value) > +{ > + if (value) > + return "a hardware PMU counter may be used by the kernel"; > + > + return "perf can use full PMU counters"; > +} > + > +static const char *system_help_kptr_restrict(int value) > +{ > + if (value == 0) > + return "kernel pointers are printed as-is"; > + if (value == 1) > + return "non-root cannot see the kernel pointers"; > + if (value == 2) > + return "root may not see some kernel pointers"; > + > + return "unknown value"; > +} > + > +/** > + * Usage: 'perf check system <settings>' > + * > + * Show system settings that affect perf behavior. > + */ > +static int subcommand_system(int argc, const char **argv) > +{ > +#define PERF_SYSCTL(name) { #name, system_help_##name } > + struct { > + const char *name; > + const char *(*help)(int value); > + } sysctls[] = { > + PERF_SYSCTL(perf_event_paranoid), > + PERF_SYSCTL(perf_event_max_stack), > + PERF_SYSCTL(perf_event_mlock_kb), > + PERF_SYSCTL(nmi_watchdog), > + PERF_SYSCTL(kptr_restrict), > + }; > +#undef PERF_SYSCTL > + > + argc = parse_options(argc, argv, check_system_options, > + check_system_usage, 0); > + > + for (size_t i = 0; i < ARRAY_SIZE(sysctls); i++) { > + int value; > + > + if (argc) { > + bool found = false; > + > + /* only show entries match to command line arguments */ > + for (int k = 0; k < argc; k++) { > + if (strstr(sysctls[i].name, argv[k])) { > + found = true; > + break; > + } > + } > + if (!found) > + continue; > + } > + > + value = read_sysctl_kernel_int(sysctls[i].name); > + printf("%-20s = %d", sysctls[i].name, value); > + if (!quiet) > + printf("\t# %s", sysctls[i].help(value)); > + printf("\n"); > + } > + > + return 0; This looks useful! Rather than returning 0 should this return something indicating whether perf does or doesn't have the permission? In that case, what about root? We have this pattern in our shell tests: https://web.git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/tree/tools/perf/tests/shell/lib/stat_output.sh?h=perf-tools-next ``` function ParanoidAndNotRoot() { [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] } ``` I wonder things like this can use these values instead. Thanks, Ian > +} > + > int cmd_check(int argc, const char **argv) > { > argc = parse_options_subcommand(argc, argv, check_options, > @@ -176,6 +288,8 @@ int cmd_check(int argc, const char **argv) > > if (strcmp(argv[0], "feature") == 0) > return subcommand_feature(argc, argv); > + if (strcmp(argv[0], "system") == 0) > + return subcommand_system(argc, argv); > > /* If no subcommand matched above, print usage help */ > pr_err("Unknown subcommand: %s\n", argv[0]); > -- > 2.51.0 > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC/PATCH 1/2] perf check: Add 'system' subcommand 2025-09-18 15:48 ` [RFC/PATCH 1/2] perf check: Add 'system' subcommand Ian Rogers @ 2025-09-18 20:12 ` Arnaldo Carvalho de Melo 2025-09-19 20:21 ` Namhyung Kim 1 sibling, 0 replies; 8+ messages in thread From: Arnaldo Carvalho de Melo @ 2025-09-18 20:12 UTC (permalink / raw) To: Ian Rogers Cc: Namhyung Kim, Kan Liang, Jiri Olsa, Adrian Hunter, Peter Zijlstra, Ingo Molnar, LKML, linux-perf-users On Thu, Sep 18, 2025 at 08:48:10AM -0700, Ian Rogers wrote: > On Wed, Sep 17, 2025 at 11:39 PM Namhyung Kim <namhyung@kernel.org> wrote: > > +/** > > + * Usage: 'perf check system <settings>' > > + * > > + * Show system settings that affect perf behavior. > > + */ > > +static int subcommand_system(int argc, const char **argv) > > +{ > > +#define PERF_SYSCTL(name) { #name, system_help_##name } > > + struct { > > + const char *name; > > + const char *(*help)(int value); > > + } sysctls[] = { > > + PERF_SYSCTL(perf_event_paranoid), > > + PERF_SYSCTL(perf_event_max_stack), > > + PERF_SYSCTL(perf_event_mlock_kb), > > + PERF_SYSCTL(nmi_watchdog), > > + PERF_SYSCTL(kptr_restrict), > > + }; > > +#undef PERF_SYSCTL > > + > > + argc = parse_options(argc, argv, check_system_options, > > + check_system_usage, 0); > > + > > + for (size_t i = 0; i < ARRAY_SIZE(sysctls); i++) { > > + int value; > > + > > + if (argc) { > > + bool found = false; > > + > > + /* only show entries match to command line arguments */ > > + for (int k = 0; k < argc; k++) { > > + if (strstr(sysctls[i].name, argv[k])) { > > + found = true; > > + break; > > + } > > + } > > + if (!found) > > + continue; > > + } > > + > > + value = read_sysctl_kernel_int(sysctls[i].name); > > + printf("%-20s = %d", sysctls[i].name, value); > > + if (!quiet) > > + printf("\t# %s", sysctls[i].help(value)); > > + printf("\n"); > > + } > > + > > + return 0; > > This looks useful! Rather than returning 0 should this return > something indicating whether perf does or doesn't have the permission? > In that case, what about root? We have this pattern in our shell > tests: > https://web.git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/tree/tools/perf/tests/shell/lib/stat_output.sh?h=perf-tools-next > ``` > function ParanoidAndNotRoot() > { > [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] > } > ``` > I wonder things like this can use these values instead. Yeah, I thought about that as well, to use these checks in the perf test shell entries. - Arnaldo ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC/PATCH 1/2] perf check: Add 'system' subcommand 2025-09-18 15:48 ` [RFC/PATCH 1/2] perf check: Add 'system' subcommand Ian Rogers 2025-09-18 20:12 ` Arnaldo Carvalho de Melo @ 2025-09-19 20:21 ` Namhyung Kim 1 sibling, 0 replies; 8+ messages in thread From: Namhyung Kim @ 2025-09-19 20:21 UTC (permalink / raw) To: Ian Rogers Cc: Arnaldo Carvalho de Melo, Kan Liang, Jiri Olsa, Adrian Hunter, Peter Zijlstra, Ingo Molnar, LKML, linux-perf-users On Thu, Sep 18, 2025 at 08:48:10AM -0700, Ian Rogers wrote: > On Wed, Sep 17, 2025 at 11:39 PM Namhyung Kim <namhyung@kernel.org> wrote: > > > > The 'perf check system' is to check sysctl settings related to perf. > > By default it'd print the following output. > > > > $ perf check system > > perf_event_paranoid = 2 # non-root can profile user code only > > perf_event_max_stack = 127 # maximum callchain length > > perf_event_mlock_kb = 516 # maximum ring buffer size (including a header page) for non-root > > nmi_watchdog = 1 # a hardware PMU counter may be used by the kernel > > kptr_restrict = 0 # kernel pointers are printed as-is > > > > The -q option suppresses the description. It can also take command line > > argument to match specific items. > > > > $ perf check system -q nmi > > nmi_watchdog = 1 > > > > Signed-off-by: Namhyung Kim <namhyung@kernel.org> > > --- > > tools/perf/Documentation/perf-check.txt | 20 ++++ > > tools/perf/builtin-check.c | 116 +++++++++++++++++++++++- > > 2 files changed, 135 insertions(+), 1 deletion(-) > > > > diff --git a/tools/perf/Documentation/perf-check.txt b/tools/perf/Documentation/perf-check.txt > > index ee92042082f73121..34dccc29d90d2fdf 100644 > > --- a/tools/perf/Documentation/perf-check.txt > > +++ b/tools/perf/Documentation/perf-check.txt > > @@ -10,6 +10,7 @@ SYNOPSIS > > [verse] > > 'perf check' [<options>] > > 'perf check' {feature <feature_list>} [<options>] > > +'perf check' {system <setting_list>} [<options>] > > > > DESCRIPTION > > ----------- > > @@ -22,6 +23,9 @@ compiled-in/built-in or not. > > Also, 'perf check feature' returns with exit status 0 if the feature > > is built-in, otherwise returns with exit status 1. > > > > +If the subcommand 'system' is used, then system settins are printed on > > +the standard output with explanation. > > + > > SUBCOMMANDS > > ----------- > > > > @@ -69,6 +73,22 @@ SUBCOMMANDS > > zlib / HAVE_ZLIB_SUPPORT > > zstd / HAVE_ZSTD_SUPPORT > > > > +system:: > > + > > + Print system settings (sysctl) that affect perf behaviors. > > + > > + Example Usage: > > + perf check system > > + perf check system watchdog > > + > > + Supported settings: > > + perf_event_paranoid > > + perf_event_max_stack > > + perf_event_mlock_kb > > + nmi_watchdog > > + kptr_restrict > > + > > + > > OPTIONS > > ------- > > -q:: > > diff --git a/tools/perf/builtin-check.c b/tools/perf/builtin-check.c > > index b1e205871ab17a77..1c7c6bb5da5ccbf2 100644 > > --- a/tools/perf/builtin-check.c > > +++ b/tools/perf/builtin-check.c > > @@ -3,24 +3,30 @@ > > #include "color.h" > > #include "util/debug.h" > > #include "util/header.h" > > +#include <api/fs/fs.h> > > #include <tools/config.h> > > #include <stdbool.h> > > #include <stdio.h> > > #include <string.h> > > #include <subcmd/parse-options.h> > > > > -static const char * const check_subcommands[] = { "feature", NULL }; > > +static const char * const check_subcommands[] = { "feature", "system", NULL }; > > static struct option check_options[] = { > > OPT_BOOLEAN('q', "quiet", &quiet, "do not show any warnings or messages"), > > OPT_END() > > }; > > static struct option check_feature_options[] = { OPT_PARENT(check_options) }; > > +static struct option check_system_options[] = { OPT_PARENT(check_options) }; > > > > static const char *check_usage[] = { NULL, NULL }; > > static const char *check_feature_usage[] = { > > "perf check feature <feature_list>", > > NULL > > }; > > +static const char *check_system_usage[] = { > > + "perf check system", > > + NULL > > +}; > > > > #define FEATURE_STATUS(name_, macro_) { \ > > .name = name_, \ > > @@ -166,6 +172,112 @@ static int subcommand_feature(int argc, const char **argv) > > return !feature_enabled; > > } > > > > +static int read_sysctl_kernel_int(const char *name) > > +{ > > + char path[128]; > > + int value; > > + > > + scnprintf(path, sizeof(path), "kernel/%s", name); > > + if (sysctl__read_int(path, &value)) > > + return INT_MAX; > > + > > + return value; > > +} > > + > > +static const char *system_help_perf_event_paranoid(int value) > > +{ > > + if (value == 2) > > + return "non-root can profile user code only"; > > + if (value == 1) > > + return "non-root can profile kernel and user code"; > > + if (value == 0) > > + return "non-root can profile system-wide w/o tracepoints data"; > > + if (value < 0) > > + return "no restrictions"; > > + > > + return "non-root cannot use perf event"; > > +} > > + > > +static const char *system_help_perf_event_max_stack(int value __maybe_unused) > > +{ > > + return "maximum callchain length"; > > +} > > + > > +static const char *system_help_perf_event_mlock_kb(int value __maybe_unused) > > +{ > > + return "maximum ring buffer size (including a header page) for non-root"; > > +} > > + > > +static const char *system_help_nmi_watchdog(int value) > > +{ > > + if (value) > > + return "a hardware PMU counter may be used by the kernel"; > > + > > + return "perf can use full PMU counters"; > > +} > > + > > +static const char *system_help_kptr_restrict(int value) > > +{ > > + if (value == 0) > > + return "kernel pointers are printed as-is"; > > + if (value == 1) > > + return "non-root cannot see the kernel pointers"; > > + if (value == 2) > > + return "root may not see some kernel pointers"; > > + > > + return "unknown value"; > > +} > > + > > +/** > > + * Usage: 'perf check system <settings>' > > + * > > + * Show system settings that affect perf behavior. > > + */ > > +static int subcommand_system(int argc, const char **argv) > > +{ > > +#define PERF_SYSCTL(name) { #name, system_help_##name } > > + struct { > > + const char *name; > > + const char *(*help)(int value); > > + } sysctls[] = { > > + PERF_SYSCTL(perf_event_paranoid), > > + PERF_SYSCTL(perf_event_max_stack), > > + PERF_SYSCTL(perf_event_mlock_kb), > > + PERF_SYSCTL(nmi_watchdog), > > + PERF_SYSCTL(kptr_restrict), > > + }; > > +#undef PERF_SYSCTL > > + > > + argc = parse_options(argc, argv, check_system_options, > > + check_system_usage, 0); > > + > > + for (size_t i = 0; i < ARRAY_SIZE(sysctls); i++) { > > + int value; > > + > > + if (argc) { > > + bool found = false; > > + > > + /* only show entries match to command line arguments */ > > + for (int k = 0; k < argc; k++) { > > + if (strstr(sysctls[i].name, argv[k])) { > > + found = true; > > + break; > > + } > > + } > > + if (!found) > > + continue; > > + } > > + > > + value = read_sysctl_kernel_int(sysctls[i].name); > > + printf("%-20s = %d", sysctls[i].name, value); > > + if (!quiet) > > + printf("\t# %s", sysctls[i].help(value)); > > + printf("\n"); > > + } > > + > > + return 0; > > This looks useful! Rather than returning 0 should this return > something indicating whether perf does or doesn't have the permission? > In that case, what about root? We have this pattern in our shell > tests: > https://web.git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/tree/tools/perf/tests/shell/lib/stat_output.sh?h=perf-tools-next > ``` > function ParanoidAndNotRoot() > { > [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] > } > ``` > I wonder things like this can use these values instead. Yep, but I guess it needs a separate interface to do that. Maybe something like this? $ perf check permission (user|kernel|cpu|raw-tp) Thanks, Namhyung > > > +} > > + > > int cmd_check(int argc, const char **argv) > > { > > argc = parse_options_subcommand(argc, argv, check_options, > > @@ -176,6 +288,8 @@ int cmd_check(int argc, const char **argv) > > > > if (strcmp(argv[0], "feature") == 0) > > return subcommand_feature(argc, argv); > > + if (strcmp(argv[0], "system") == 0) > > + return subcommand_system(argc, argv); > > > > /* If no subcommand matched above, print usage help */ > > pr_err("Unknown subcommand: %s\n", argv[0]); > > -- > > 2.51.0 > > ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-09-20 14:05 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-09-18 6:39 [RFC/PATCH 1/2] perf check: Add 'system' subcommand Namhyung Kim 2025-09-18 6:39 ` [RFC/PATCH 2/2] perf check: Add 'pmu' subcommand Namhyung Kim 2025-09-18 15:33 ` Ian Rogers 2025-09-19 20:27 ` Namhyung Kim 2025-09-20 14:04 ` Ian Rogers 2025-09-18 15:48 ` [RFC/PATCH 1/2] perf check: Add 'system' subcommand Ian Rogers 2025-09-18 20:12 ` Arnaldo Carvalho de Melo 2025-09-19 20:21 ` Namhyung Kim
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).