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