scripts.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include "../../builtin.h"
  3. #include "../../perf.h"
  4. #include "../../util/util.h" // perf_exe()
  5. #include "../util.h"
  6. #include "../../util/hist.h"
  7. #include "../../util/debug.h"
  8. #include "../../util/symbol.h"
  9. #include "../browser.h"
  10. #include "../libslang.h"
  11. #include "config.h"
  12. #include <linux/string.h>
  13. #include <linux/zalloc.h>
  14. #include <stdlib.h>
  15. #define SCRIPT_NAMELEN 128
  16. #define SCRIPT_MAX_NO 64
  17. /*
  18. * Usually the full path for a script is:
  19. * /home/username/libexec/perf-core/scripts/python/xxx.py
  20. * /home/username/libexec/perf-core/scripts/perl/xxx.pl
  21. * So 256 should be long enough to contain the full path.
  22. */
  23. #define SCRIPT_FULLPATH_LEN 256
  24. struct script_config {
  25. const char **names;
  26. char **paths;
  27. int index;
  28. const char *perf;
  29. char extra_format[256];
  30. };
  31. void attr_to_script(char *extra_format, struct perf_event_attr *attr)
  32. {
  33. extra_format[0] = 0;
  34. if (attr->read_format & PERF_FORMAT_GROUP)
  35. strcat(extra_format, " -F +metric");
  36. if (attr->sample_type & PERF_SAMPLE_BRANCH_STACK)
  37. strcat(extra_format, " -F +brstackinsn --xed");
  38. if (attr->sample_type & PERF_SAMPLE_REGS_INTR)
  39. strcat(extra_format, " -F +iregs");
  40. if (attr->sample_type & PERF_SAMPLE_REGS_USER)
  41. strcat(extra_format, " -F +uregs");
  42. if (attr->sample_type & PERF_SAMPLE_PHYS_ADDR)
  43. strcat(extra_format, " -F +phys_addr");
  44. }
  45. static int add_script_option(const char *name, const char *opt,
  46. struct script_config *c)
  47. {
  48. c->names[c->index] = name;
  49. if (asprintf(&c->paths[c->index],
  50. "%s script %s -F +metric %s %s",
  51. c->perf, opt, symbol_conf.inline_name ? " --inline" : "",
  52. c->extra_format) < 0)
  53. return -1;
  54. c->index++;
  55. return 0;
  56. }
  57. static int scripts_config(const char *var, const char *value, void *data)
  58. {
  59. struct script_config *c = data;
  60. if (!strstarts(var, "scripts."))
  61. return -1;
  62. if (c->index >= SCRIPT_MAX_NO)
  63. return -1;
  64. c->names[c->index] = strdup(var + 7);
  65. if (!c->names[c->index])
  66. return -1;
  67. if (asprintf(&c->paths[c->index], "%s %s", value,
  68. c->extra_format) < 0)
  69. return -1;
  70. c->index++;
  71. return 0;
  72. }
  73. /*
  74. * When success, will copy the full path of the selected script
  75. * into the buffer pointed by script_name, and return 0.
  76. * Return -1 on failure.
  77. */
  78. static int list_scripts(char *script_name, bool *custom,
  79. struct evsel *evsel)
  80. {
  81. char *buf, *paths[SCRIPT_MAX_NO], *names[SCRIPT_MAX_NO];
  82. int i, num, choice;
  83. int ret = 0;
  84. int max_std, custom_perf;
  85. char pbuf[256];
  86. const char *perf = perf_exe(pbuf, sizeof pbuf);
  87. struct script_config scriptc = {
  88. .names = (const char **)names,
  89. .paths = paths,
  90. .perf = perf
  91. };
  92. script_name[0] = 0;
  93. /* Preset the script name to SCRIPT_NAMELEN */
  94. buf = malloc(SCRIPT_MAX_NO * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN));
  95. if (!buf)
  96. return -1;
  97. if (evsel)
  98. attr_to_script(scriptc.extra_format, &evsel->core.attr);
  99. add_script_option("Show individual samples", "", &scriptc);
  100. add_script_option("Show individual samples with assembler", "-F +disasm",
  101. &scriptc);
  102. add_script_option("Show individual samples with source", "-F +srcline,+srccode",
  103. &scriptc);
  104. perf_config(scripts_config, &scriptc);
  105. custom_perf = scriptc.index;
  106. add_script_option("Show samples with custom perf script arguments", "", &scriptc);
  107. i = scriptc.index;
  108. max_std = i;
  109. for (; i < SCRIPT_MAX_NO; i++) {
  110. names[i] = buf + (i - max_std) * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN);
  111. paths[i] = names[i] + SCRIPT_NAMELEN;
  112. }
  113. num = find_scripts(names + max_std, paths + max_std, SCRIPT_MAX_NO - max_std,
  114. SCRIPT_FULLPATH_LEN);
  115. if (num < 0)
  116. num = 0;
  117. choice = ui__popup_menu(num + max_std, (char * const *)names, NULL);
  118. if (choice < 0) {
  119. ret = -1;
  120. goto out;
  121. }
  122. if (choice == custom_perf) {
  123. char script_args[50];
  124. int key = ui_browser__input_window("perf script command",
  125. "Enter perf script command line (without perf script prefix)",
  126. script_args, "", 0);
  127. if (key != K_ENTER) {
  128. ret = -1;
  129. goto out;
  130. }
  131. sprintf(script_name, "%s script %s", perf, script_args);
  132. } else if (choice < num + max_std) {
  133. strcpy(script_name, paths[choice]);
  134. }
  135. *custom = choice >= max_std;
  136. out:
  137. free(buf);
  138. for (i = 0; i < max_std; i++)
  139. zfree(&paths[i]);
  140. return ret;
  141. }
  142. void run_script(char *cmd)
  143. {
  144. pr_debug("Running %s\n", cmd);
  145. SLang_reset_tty();
  146. if (system(cmd) < 0)
  147. pr_warning("Cannot run %s\n", cmd);
  148. /*
  149. * SLang doesn't seem to reset the whole terminal, so be more
  150. * forceful to get back to the original state.
  151. */
  152. printf("\033[c\033[H\033[J");
  153. fflush(stdout);
  154. SLang_init_tty(0, 0, 0);
  155. SLtty_set_suspend_state(true);
  156. SLsmg_refresh();
  157. }
  158. int script_browse(const char *script_opt, struct evsel *evsel)
  159. {
  160. char *cmd, script_name[SCRIPT_FULLPATH_LEN];
  161. bool custom = false;
  162. memset(script_name, 0, SCRIPT_FULLPATH_LEN);
  163. if (list_scripts(script_name, &custom, evsel))
  164. return -1;
  165. if (asprintf(&cmd, "%s%s %s %s%s 2>&1 | less",
  166. custom ? "perf script -s " : "",
  167. script_name,
  168. script_opt ? script_opt : "",
  169. input_name ? "-i " : "",
  170. input_name ? input_name : "") < 0)
  171. return -1;
  172. run_script(cmd);
  173. free(cmd);
  174. return 0;
  175. }