scripts.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <elf.h>
  3. #include <inttypes.h>
  4. #include <sys/ttydefaults.h>
  5. #include <string.h>
  6. #include "../../util/sort.h"
  7. #include "../../util/util.h"
  8. #include "../../util/hist.h"
  9. #include "../../util/debug.h"
  10. #include "../../util/symbol.h"
  11. #include "../browser.h"
  12. #include "../helpline.h"
  13. #include "../libslang.h"
  14. /* 2048 lines should be enough for a script output */
  15. #define MAX_LINES 2048
  16. /* 160 bytes for one output line */
  17. #define AVERAGE_LINE_LEN 160
  18. struct script_line {
  19. struct list_head node;
  20. char line[AVERAGE_LINE_LEN];
  21. };
  22. struct perf_script_browser {
  23. struct ui_browser b;
  24. struct list_head entries;
  25. const char *script_name;
  26. int nr_lines;
  27. };
  28. #define SCRIPT_NAMELEN 128
  29. #define SCRIPT_MAX_NO 64
  30. /*
  31. * Usually the full path for a script is:
  32. * /home/username/libexec/perf-core/scripts/python/xxx.py
  33. * /home/username/libexec/perf-core/scripts/perl/xxx.pl
  34. * So 256 should be long enough to contain the full path.
  35. */
  36. #define SCRIPT_FULLPATH_LEN 256
  37. /*
  38. * When success, will copy the full path of the selected script
  39. * into the buffer pointed by script_name, and return 0.
  40. * Return -1 on failure.
  41. */
  42. static int list_scripts(char *script_name)
  43. {
  44. char *buf, *names[SCRIPT_MAX_NO], *paths[SCRIPT_MAX_NO];
  45. int i, num, choice, ret = -1;
  46. /* Preset the script name to SCRIPT_NAMELEN */
  47. buf = malloc(SCRIPT_MAX_NO * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN));
  48. if (!buf)
  49. return ret;
  50. for (i = 0; i < SCRIPT_MAX_NO; i++) {
  51. names[i] = buf + i * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN);
  52. paths[i] = names[i] + SCRIPT_NAMELEN;
  53. }
  54. num = find_scripts(names, paths);
  55. if (num > 0) {
  56. choice = ui__popup_menu(num, names);
  57. if (choice < num && choice >= 0) {
  58. strcpy(script_name, paths[choice]);
  59. ret = 0;
  60. }
  61. }
  62. free(buf);
  63. return ret;
  64. }
  65. static void script_browser__write(struct ui_browser *browser,
  66. void *entry, int row)
  67. {
  68. struct script_line *sline = list_entry(entry, struct script_line, node);
  69. bool current_entry = ui_browser__is_current_entry(browser, row);
  70. ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
  71. HE_COLORSET_NORMAL);
  72. ui_browser__write_nstring(browser, sline->line, browser->width);
  73. }
  74. static int script_browser__run(struct perf_script_browser *browser)
  75. {
  76. int key;
  77. if (ui_browser__show(&browser->b, browser->script_name,
  78. "Press ESC to exit") < 0)
  79. return -1;
  80. while (1) {
  81. key = ui_browser__run(&browser->b, 0);
  82. /* We can add some special key handling here if needed */
  83. break;
  84. }
  85. ui_browser__hide(&browser->b);
  86. return key;
  87. }
  88. int script_browse(const char *script_opt)
  89. {
  90. char cmd[SCRIPT_FULLPATH_LEN*2], script_name[SCRIPT_FULLPATH_LEN];
  91. char *line = NULL;
  92. size_t len = 0;
  93. ssize_t retlen;
  94. int ret = -1, nr_entries = 0;
  95. FILE *fp;
  96. void *buf;
  97. struct script_line *sline;
  98. struct perf_script_browser script = {
  99. .b = {
  100. .refresh = ui_browser__list_head_refresh,
  101. .seek = ui_browser__list_head_seek,
  102. .write = script_browser__write,
  103. },
  104. .script_name = script_name,
  105. };
  106. INIT_LIST_HEAD(&script.entries);
  107. /* Save each line of the output in one struct script_line object. */
  108. buf = zalloc((sizeof(*sline)) * MAX_LINES);
  109. if (!buf)
  110. return -1;
  111. sline = buf;
  112. memset(script_name, 0, SCRIPT_FULLPATH_LEN);
  113. if (list_scripts(script_name))
  114. goto exit;
  115. sprintf(cmd, "perf script -s %s ", script_name);
  116. if (script_opt)
  117. strcat(cmd, script_opt);
  118. if (input_name) {
  119. strcat(cmd, " -i ");
  120. strcat(cmd, input_name);
  121. }
  122. strcat(cmd, " 2>&1");
  123. fp = popen(cmd, "r");
  124. if (!fp)
  125. goto exit;
  126. while ((retlen = getline(&line, &len, fp)) != -1) {
  127. strncpy(sline->line, line, AVERAGE_LINE_LEN);
  128. /* If one output line is very large, just cut it short */
  129. if (retlen >= AVERAGE_LINE_LEN) {
  130. sline->line[AVERAGE_LINE_LEN - 1] = '\0';
  131. sline->line[AVERAGE_LINE_LEN - 2] = '\n';
  132. }
  133. list_add_tail(&sline->node, &script.entries);
  134. if (script.b.width < retlen)
  135. script.b.width = retlen;
  136. if (nr_entries++ >= MAX_LINES - 1)
  137. break;
  138. sline++;
  139. }
  140. if (script.b.width > AVERAGE_LINE_LEN)
  141. script.b.width = AVERAGE_LINE_LEN;
  142. free(line);
  143. pclose(fp);
  144. script.nr_lines = nr_entries;
  145. script.b.nr_entries = nr_entries;
  146. script.b.entries = &script.entries;
  147. ret = script_browser__run(&script);
  148. exit:
  149. free(buf);
  150. return ret;
  151. }