perf sched: Fix record failure when CONFIG_SCHEDSTATS is not set

The tracepoints trace_sched_stat_{wait, sleep, iowait} are not exposed to user
if CONFIG_SCHEDSTATS is not set, "perf sched record" records the three events.
As a result, the command fails.

Before:

#perf sched record sleep 1
event syntax error: 'sched:sched_stat_wait'
\___ unknown tracepoint

Error: File /sys/kernel/tracing/events/sched/sched_stat_wait not found.
Hint: Perhaps this kernel misses some CONFIG_ setting to enable this feature?.

Run 'perf list' for a list of valid events

Usage: perf record [<options>] [<command>]
or: perf record [<options>] -- <command> [<options>]

-e, --event <event> event selector. use 'perf list' to list available events

Solution:
Check whether schedstat tracepoints are exposed. If no, these events are not recorded.

After:
# perf sched record sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.163 MB perf.data (1091 samples) ]
# perf sched report
run measurement overhead: 4736 nsecs
sleep measurement overhead: 9059979 nsecs
the run test took 999854 nsecs
the sleep test took 8945271 nsecs
nr_run_events: 716
nr_sleep_events: 785
nr_wakeup_events: 0
...
------------------------------------------------------------

Fixes: 2a09b5de235a6 ("sched/fair: do not expose some tracepoints to user if CONFIG_SCHEDSTATS is not set")
Signed-off-by: Yang Jihong <yangjihong1@huawei.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Steven Rostedt (VMware) <rostedt@goodmis.org>
Cc: Yafang Shao <laoar.shao@gmail.com>
Link: http://lore.kernel.org/lkml/20210713112358.194693-1-yangjihong1@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by Yang Jihong and committed by Arnaldo Carvalho de Melo b0f00855 22a66551

Changed files
+29 -4
tools
+29 -4
tools/perf/builtin-sched.c
··· 3335 3335 sort_dimension__add("pid", &sched->cmp_pid); 3336 3336 } 3337 3337 3338 + static bool schedstat_events_exposed(void) 3339 + { 3340 + /* 3341 + * Select "sched:sched_stat_wait" event to check 3342 + * whether schedstat tracepoints are exposed. 3343 + */ 3344 + return IS_ERR(trace_event__tp_format("sched", "sched_stat_wait")) ? 3345 + false : true; 3346 + } 3347 + 3338 3348 static int __cmd_record(int argc, const char **argv) 3339 3349 { 3340 3350 unsigned int rec_argc, i, j; ··· 3356 3346 "-m", "1024", 3357 3347 "-c", "1", 3358 3348 "-e", "sched:sched_switch", 3359 - "-e", "sched:sched_stat_wait", 3360 - "-e", "sched:sched_stat_sleep", 3361 - "-e", "sched:sched_stat_iowait", 3362 3349 "-e", "sched:sched_stat_runtime", 3363 3350 "-e", "sched:sched_process_fork", 3364 3351 "-e", "sched:sched_wakeup_new", 3365 3352 "-e", "sched:sched_migrate_task", 3366 3353 }; 3354 + 3355 + /* 3356 + * The tracepoints trace_sched_stat_{wait, sleep, iowait} 3357 + * are not exposed to user if CONFIG_SCHEDSTATS is not set, 3358 + * to prevent "perf sched record" execution failure, determine 3359 + * whether to record schedstat events according to actual situation. 3360 + */ 3361 + const char * const schedstat_args[] = { 3362 + "-e", "sched:sched_stat_wait", 3363 + "-e", "sched:sched_stat_sleep", 3364 + "-e", "sched:sched_stat_iowait", 3365 + }; 3366 + unsigned int schedstat_argc = schedstat_events_exposed() ? 3367 + ARRAY_SIZE(schedstat_args) : 0; 3368 + 3367 3369 struct tep_event *waking_event; 3368 3370 3369 3371 /* 3370 3372 * +2 for either "-e", "sched:sched_wakeup" or 3371 3373 * "-e", "sched:sched_waking" 3372 3374 */ 3373 - rec_argc = ARRAY_SIZE(record_args) + 2 + argc - 1; 3375 + rec_argc = ARRAY_SIZE(record_args) + 2 + schedstat_argc + argc - 1; 3374 3376 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 3375 3377 3376 3378 if (rec_argv == NULL) ··· 3397 3375 rec_argv[i++] = strdup("sched:sched_waking"); 3398 3376 else 3399 3377 rec_argv[i++] = strdup("sched:sched_wakeup"); 3378 + 3379 + for (j = 0; j < schedstat_argc; j++) 3380 + rec_argv[i++] = strdup(schedstat_args[j]); 3400 3381 3401 3382 for (j = 1; j < (unsigned int)argc; j++, i++) 3402 3383 rec_argv[i] = argv[j];