From 22ca2f7f32cc783b57bc1223b84d6f5ba3e5d1e2 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 9 Feb 2026 12:22:06 -0800 Subject: [PATCH] perf script: Allow the generated script to be a path Allow the script generated by "perf script -g " to be a file path and the language determined by the file extension. This is useful in testing so that the generated script file can be written to a test directory. Committer testing: $ perf record ls a.a ls: cannot access 'a.a': No such file or directory [ perf record: Woken up 2 times to write data ] [ perf record: Captured and wrote 0.003 MB perf.data (7 samples) ] $ perf script -g python generated Python script: perf-script.py $ perf script -g myscript.py generated Python script: myscript.py $ diff -u perf-script.py myscript.py $ tail myscript.py def trace_unhandled(event_name, context, event_fields_dict, perf_sample_dict): print(get_dict_as_string(event_fields_dict)) print('Sample: {'+get_dict_as_string(perf_sample_dict['sample'], ', ')+'}') def print_header(event_name, cpu, secs, nsecs, pid, comm): print("%-20s %5u %05u.%09u %8u %-20s " % \ (event_name, cpu, secs, nsecs, pid, comm), end="") def get_dict_as_string(a_dict, delimiter=' '): return delimiter.join(['%s=%s'%(k,str(v))for k,v in sorted(a_dict.items())]) $ Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Leo Yan Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Sandipan Das Cc: Yujie Liu Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-script.txt | 6 ++++-- tools/perf/builtin-script.c | 24 ++++++++++++++++++++---- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 03d112960632..ddf92f9c7821 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -98,8 +98,10 @@ OPTIONS -g:: --gen-script=:: - Generate perf-script.[ext] starter script for given language, - using current perf.data. + Generate a starter script. If a language is given then the + script is named perf-script.[ext] according to the + language. If a file path is given then python is used for + files ending '.py' and perl used for files ending '.pl'. --dlfilter=:: Filter sample events using the given shared object file. diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 14c6f6c3c4f2..7c743a303507 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -4489,6 +4489,7 @@ script_found: if (generate_script_lang) { struct stat perf_stat; int input; + char *filename = strdup("perf-script"); if (output_set_by_user()) { fprintf(stderr, @@ -4516,17 +4517,32 @@ script_found: } scripting_ops = script_spec__lookup(generate_script_lang); + if (!scripting_ops && ends_with(generate_script_lang, ".py")) { + scripting_ops = script_spec__lookup("python"); + free(filename); + filename = strdup(generate_script_lang); + filename[strlen(filename) - 3] = '\0'; + } else if (!scripting_ops && ends_with(generate_script_lang, ".pl")) { + scripting_ops = script_spec__lookup("perl"); + free(filename); + filename = strdup(generate_script_lang); + filename[strlen(filename) - 3] = '\0'; + } if (!scripting_ops) { - fprintf(stderr, "invalid language specifier"); + fprintf(stderr, "invalid language specifier '%s'\n", generate_script_lang); err = -ENOENT; goto out_delete; } + if (!filename) { + err = -ENOMEM; + goto out_delete; + } #ifdef HAVE_LIBTRACEEVENT - err = scripting_ops->generate_script(session->tevent.pevent, - "perf-script"); + err = scripting_ops->generate_script(session->tevent.pevent, filename); #else - err = scripting_ops->generate_script(NULL, "perf-script"); + err = scripting_ops->generate_script(NULL, filename); #endif + free(filename); goto out_delete; }