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