perf script: Allow the generated script to be a path

Allow the script generated by "perf script -g <language>" 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 <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Leo Yan <leo.yan@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sandipan Das <sandipan.das@amd.com>
Cc: Yujie Liu <yujie.liu@intel.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Ian Rogers 2026-02-09 12:22:06 -08:00 committed by Arnaldo Carvalho de Melo
parent 9083ce531a
commit 22ca2f7f32
2 changed files with 24 additions and 6 deletions

View file

@ -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=<file>::
Filter sample events using the given shared object file.

View file

@ -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;
}