scripts.c 4.2 KB

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