Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf report: Support builtin perf script in scripts menu

The scripts menu traditionally only showed custom perf scripts.

Allow to run standard perf script with useful default options too.

- Normal perf script
- perf script with assembler (needs xed installed)
- perf script with source code output (needs debuginfo)
- perf script with custom arguments

Then we automatically select the right options to display the
information in the perf.data file.

For example with -b display branch contexts.

It's not easily possible to check for xed's existence in advance. perf
script usually gives sensible error messages when it's not available.

Signed-off-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Link: http://lkml.kernel.org/r/20190311144502.15423-7-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Andi Kleen and committed by
Arnaldo Carvalho de Melo
6f3da20e 1d6c49df

+120 -40
+1 -1
tools/perf/ui/browsers/annotate.c
··· 750 750 continue; 751 751 case 'r': 752 752 { 753 - script_browse(NULL); 753 + script_browse(NULL, NULL); 754 754 continue; 755 755 } 756 756 case 'k':
+13 -10
tools/perf/ui/browsers/hists.c
··· 2344 2344 struct thread *thread; 2345 2345 struct map_symbol ms; 2346 2346 int socket; 2347 + struct perf_evsel *evsel; 2347 2348 2348 2349 int (*fn)(struct hist_browser *browser, struct popup_action *act); 2349 2350 }; ··· 2567 2566 n += snprintf(script_opt + n, len - n, " --time %s,%s", start, end); 2568 2567 } 2569 2568 2570 - script_browse(script_opt); 2569 + script_browse(script_opt, act->evsel); 2571 2570 free(script_opt); 2572 2571 return 0; 2573 2572 } ··· 2576 2575 add_script_opt_2(struct hist_browser *browser __maybe_unused, 2577 2576 struct popup_action *act, char **optstr, 2578 2577 struct thread *thread, struct symbol *sym, 2579 - const char *tstr) 2578 + struct perf_evsel *evsel, const char *tstr) 2580 2579 { 2581 2580 2582 2581 if (thread) { ··· 2594 2593 2595 2594 act->thread = thread; 2596 2595 act->ms.sym = sym; 2596 + act->evsel = evsel; 2597 2597 act->fn = do_run_script; 2598 2598 return 1; 2599 2599 } ··· 2602 2600 static int 2603 2601 add_script_opt(struct hist_browser *browser, 2604 2602 struct popup_action *act, char **optstr, 2605 - struct thread *thread, struct symbol *sym) 2603 + struct thread *thread, struct symbol *sym, 2604 + struct perf_evsel *evsel) 2606 2605 { 2607 2606 int n, j; 2608 2607 struct hist_entry *he; 2609 2608 2610 - n = add_script_opt_2(browser, act, optstr, thread, sym, ""); 2609 + n = add_script_opt_2(browser, act, optstr, thread, sym, evsel, ""); 2611 2610 2612 2611 he = hist_browser__selected_entry(browser); 2613 2612 if (sort_order && strstr(sort_order, "time")) { ··· 2621 2618 sizeof tstr - j); 2622 2619 j += sprintf(tstr + j, "-"); 2623 2620 timestamp__scnprintf_usec(he->time + symbol_conf.time_quantum, 2624 - tstr + j, 2625 - sizeof tstr - j); 2621 + tstr + j, sizeof tstr - j); 2626 2622 n += add_script_opt_2(browser, act, optstr, thread, sym, 2627 - tstr); 2623 + evsel, tstr); 2628 2624 act->time = he->time; 2629 2625 } 2630 2626 return n; ··· 3094 3092 nr_options += add_script_opt(browser, 3095 3093 &actions[nr_options], 3096 3094 &options[nr_options], 3097 - thread, NULL); 3095 + thread, NULL, evsel); 3098 3096 } 3099 3097 /* 3100 3098 * Note that browser->selection != NULL ··· 3109 3107 nr_options += add_script_opt(browser, 3110 3108 &actions[nr_options], 3111 3109 &options[nr_options], 3112 - NULL, browser->selection->sym); 3110 + NULL, browser->selection->sym, 3111 + evsel); 3113 3112 } 3114 3113 } 3115 3114 nr_options += add_script_opt(browser, &actions[nr_options], 3116 - &options[nr_options], NULL, NULL); 3115 + &options[nr_options], NULL, NULL, evsel); 3117 3116 nr_options += add_switch_opt(browser, &actions[nr_options], 3118 3117 &options[nr_options]); 3119 3118 skip_scripting:
+100 -27
tools/perf/ui/browsers/scripts.c
··· 17 17 */ 18 18 #define SCRIPT_FULLPATH_LEN 256 19 19 20 + struct script_config { 21 + const char **names; 22 + char **paths; 23 + int index; 24 + const char *perf; 25 + char extra_format[256]; 26 + }; 27 + 28 + void attr_to_script(char *extra_format, struct perf_event_attr *attr) 29 + { 30 + extra_format[0] = 0; 31 + if (attr->read_format & PERF_FORMAT_GROUP) 32 + strcat(extra_format, " -F +metric"); 33 + if (attr->sample_type & PERF_SAMPLE_BRANCH_STACK) 34 + strcat(extra_format, " -F +brstackinsn --xed"); 35 + if (attr->sample_type & PERF_SAMPLE_REGS_INTR) 36 + strcat(extra_format, " -F +iregs"); 37 + if (attr->sample_type & PERF_SAMPLE_REGS_USER) 38 + strcat(extra_format, " -F +uregs"); 39 + if (attr->sample_type & PERF_SAMPLE_PHYS_ADDR) 40 + strcat(extra_format, " -F +phys_addr"); 41 + } 42 + 43 + static int add_script_option(const char *name, const char *opt, 44 + struct script_config *c) 45 + { 46 + c->names[c->index] = name; 47 + if (asprintf(&c->paths[c->index], 48 + "%s script %s -F +metric %s %s", 49 + c->perf, opt, symbol_conf.inline_name ? " --inline" : "", 50 + c->extra_format) < 0) 51 + return -1; 52 + c->index++; 53 + return 0; 54 + } 55 + 20 56 /* 21 57 * When success, will copy the full path of the selected script 22 58 * into the buffer pointed by script_name, and return 0. 23 59 * Return -1 on failure. 24 60 */ 25 - static int list_scripts(char *script_name) 61 + static int list_scripts(char *script_name, bool *custom, 62 + struct perf_evsel *evsel) 26 63 { 27 - char *buf, *names[SCRIPT_MAX_NO], *paths[SCRIPT_MAX_NO]; 28 - int i, num, choice, ret = -1; 64 + char *buf, *paths[SCRIPT_MAX_NO], *names[SCRIPT_MAX_NO]; 65 + int i, num, choice; 66 + int ret = 0; 67 + int max_std, custom_perf; 68 + char pbuf[256]; 69 + const char *perf = perf_exe(pbuf, sizeof pbuf); 70 + struct script_config scriptc = { 71 + .names = (const char **)names, 72 + .paths = paths, 73 + .perf = perf 74 + }; 75 + 76 + script_name[0] = 0; 29 77 30 78 /* Preset the script name to SCRIPT_NAMELEN */ 31 79 buf = malloc(SCRIPT_MAX_NO * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN)); 32 80 if (!buf) 33 - return ret; 81 + return -1; 34 82 35 - for (i = 0; i < SCRIPT_MAX_NO; i++) { 36 - names[i] = buf + i * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN); 83 + if (evsel) 84 + attr_to_script(scriptc.extra_format, &evsel->attr); 85 + add_script_option("Show individual samples", "", &scriptc); 86 + add_script_option("Show individual samples with assembler", "-F +insn --xed", 87 + &scriptc); 88 + add_script_option("Show individual samples with source", "-F +srcline,+srccode", 89 + &scriptc); 90 + custom_perf = scriptc.index; 91 + add_script_option("Show samples with custom perf script arguments", "", &scriptc); 92 + i = scriptc.index; 93 + max_std = i; 94 + 95 + for (; i < SCRIPT_MAX_NO; i++) { 96 + names[i] = buf + (i - max_std) * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN); 37 97 paths[i] = names[i] + SCRIPT_NAMELEN; 38 98 } 39 99 40 - num = find_scripts(names, paths); 41 - if (num > 0) { 42 - choice = ui__popup_menu(num, names); 43 - if (choice < num && choice >= 0) { 44 - strcpy(script_name, paths[choice]); 45 - ret = 0; 46 - } 100 + num = find_scripts(names + max_std, paths + max_std); 101 + if (num < 0) 102 + num = 0; 103 + choice = ui__popup_menu(num + max_std, (char * const *)names); 104 + if (choice < 0) { 105 + ret = -1; 106 + goto out; 47 107 } 108 + if (choice == custom_perf) { 109 + char script_args[50]; 110 + int key = ui_browser__input_window("perf script command", 111 + "Enter perf script command line (without perf script prefix)", 112 + script_args, "", 0); 113 + if (key != K_ENTER) 114 + return -1; 115 + sprintf(script_name, "%s script %s", perf, script_args); 116 + } else if (choice < num + max_std) { 117 + strcpy(script_name, paths[choice]); 118 + } 119 + *custom = choice >= max_std; 48 120 121 + out: 49 122 free(buf); 123 + for (i = 0; i < max_std; i++) 124 + free(paths[i]); 50 125 return ret; 51 126 } 52 127 ··· 141 66 SLsmg_refresh(); 142 67 } 143 68 144 - int script_browse(const char *script_opt) 69 + int script_browse(const char *script_opt, struct perf_evsel *evsel) 145 70 { 146 - char cmd[SCRIPT_FULLPATH_LEN*2], script_name[SCRIPT_FULLPATH_LEN]; 71 + char *cmd, script_name[SCRIPT_FULLPATH_LEN]; 72 + bool custom = false; 147 73 148 74 memset(script_name, 0, SCRIPT_FULLPATH_LEN); 149 - if (list_scripts(script_name)) 75 + if (list_scripts(script_name, &custom, evsel)) 150 76 return -1; 151 77 152 - sprintf(cmd, "perf script -s %s ", script_name); 153 - 154 - if (script_opt) 155 - strcat(cmd, script_opt); 156 - 157 - if (input_name) { 158 - strcat(cmd, " -i "); 159 - strcat(cmd, input_name); 160 - } 161 - 162 - strcat(cmd, " 2>&1 | less"); 78 + if (asprintf(&cmd, "%s%s %s %s%s 2>&1 | less", 79 + custom ? "perf script -s " : "", 80 + script_name, 81 + script_opt ? script_opt : "", 82 + input_name ? "-i " : "", 83 + input_name ? input_name : "") < 0) 84 + return -1; 163 85 164 86 run_script(cmd); 87 + free(cmd); 165 88 166 89 return 0; 167 90 }
+6 -2
tools/perf/util/hist.h
··· 436 436 437 437 #ifdef HAVE_SLANG_SUPPORT 438 438 #include "../ui/keysyms.h" 439 + void attr_to_script(char *buf, struct perf_event_attr *attr); 440 + 439 441 int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, 440 442 struct hist_browser_timer *hbt, 441 443 struct annotation_options *annotation_opts); ··· 452 450 struct perf_env *env, 453 451 bool warn_lost_event, 454 452 struct annotation_options *annotation_options); 455 - int script_browse(const char *script_opt); 453 + 454 + int script_browse(const char *script_opt, struct perf_evsel *evsel); 456 455 #else 457 456 static inline 458 457 int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, ··· 482 479 return 0; 483 480 } 484 481 485 - static inline int script_browse(const char *script_opt __maybe_unused) 482 + static inline int script_browse(const char *script_opt __maybe_unused, 483 + struct perf_evsel *evsel __maybe_unused) 486 484 { 487 485 return 0; 488 486 }