Root/tools/perf/builtin-script.c

1#include "builtin.h"
2
3#include "perf.h"
4#include "util/cache.h"
5#include "util/debug.h"
6#include "util/exec_cmd.h"
7#include "util/header.h"
8#include "util/parse-options.h"
9#include "util/session.h"
10#include "util/symbol.h"
11#include "util/thread.h"
12#include "util/trace-event.h"
13#include "util/util.h"
14#include "util/evlist.h"
15#include "util/evsel.h"
16
17static char const *script_name;
18static char const *generate_script_lang;
19static bool debug_mode;
20static u64 last_timestamp;
21static u64 nr_unordered;
22extern const struct option record_options[];
23static bool no_callchain;
24
25enum perf_output_field {
26    PERF_OUTPUT_COMM = 1U << 0,
27    PERF_OUTPUT_TID = 1U << 1,
28    PERF_OUTPUT_PID = 1U << 2,
29    PERF_OUTPUT_TIME = 1U << 3,
30    PERF_OUTPUT_CPU = 1U << 4,
31    PERF_OUTPUT_EVNAME = 1U << 5,
32    PERF_OUTPUT_TRACE = 1U << 6,
33    PERF_OUTPUT_SYM = 1U << 7,
34};
35
36struct output_option {
37    const char *str;
38    enum perf_output_field field;
39} all_output_options[] = {
40    {.str = "comm", .field = PERF_OUTPUT_COMM},
41    {.str = "tid", .field = PERF_OUTPUT_TID},
42    {.str = "pid", .field = PERF_OUTPUT_PID},
43    {.str = "time", .field = PERF_OUTPUT_TIME},
44    {.str = "cpu", .field = PERF_OUTPUT_CPU},
45    {.str = "event", .field = PERF_OUTPUT_EVNAME},
46    {.str = "trace", .field = PERF_OUTPUT_TRACE},
47    {.str = "sym", .field = PERF_OUTPUT_SYM},
48};
49
50/* default set to maintain compatibility with current format */
51static struct {
52    bool user_set;
53    bool wildcard_set;
54    u64 fields;
55    u64 invalid_fields;
56} output[PERF_TYPE_MAX] = {
57
58    [PERF_TYPE_HARDWARE] = {
59        .user_set = false,
60
61        .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
62                  PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
63                  PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
64
65        .invalid_fields = PERF_OUTPUT_TRACE,
66    },
67
68    [PERF_TYPE_SOFTWARE] = {
69        .user_set = false,
70
71        .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
72                  PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
73                  PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
74
75        .invalid_fields = PERF_OUTPUT_TRACE,
76    },
77
78    [PERF_TYPE_TRACEPOINT] = {
79        .user_set = false,
80
81        .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
82                  PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
83                  PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE,
84    },
85
86    [PERF_TYPE_RAW] = {
87        .user_set = false,
88
89        .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
90                  PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
91                  PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
92
93        .invalid_fields = PERF_OUTPUT_TRACE,
94    },
95};
96
97static bool output_set_by_user(void)
98{
99    int j;
100    for (j = 0; j < PERF_TYPE_MAX; ++j) {
101        if (output[j].user_set)
102            return true;
103    }
104    return false;
105}
106
107static const char *output_field2str(enum perf_output_field field)
108{
109    int i, imax = ARRAY_SIZE(all_output_options);
110    const char *str = "";
111
112    for (i = 0; i < imax; ++i) {
113        if (all_output_options[i].field == field) {
114            str = all_output_options[i].str;
115            break;
116        }
117    }
118    return str;
119}
120
121#define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x)
122
123static int perf_event_attr__check_stype(struct perf_event_attr *attr,
124                  u64 sample_type, const char *sample_msg,
125                  enum perf_output_field field)
126{
127    int type = attr->type;
128    const char *evname;
129
130    if (attr->sample_type & sample_type)
131        return 0;
132
133    if (output[type].user_set) {
134        evname = __event_name(attr->type, attr->config);
135        pr_err("Samples for '%s' event do not have %s attribute set. "
136               "Cannot print '%s' field.\n",
137               evname, sample_msg, output_field2str(field));
138        return -1;
139    }
140
141    /* user did not ask for it explicitly so remove from the default list */
142    output[type].fields &= ~field;
143    evname = __event_name(attr->type, attr->config);
144    pr_debug("Samples for '%s' event do not have %s attribute set. "
145         "Skipping '%s' field.\n",
146         evname, sample_msg, output_field2str(field));
147
148    return 0;
149}
150
151static int perf_evsel__check_attr(struct perf_evsel *evsel,
152                  struct perf_session *session)
153{
154    struct perf_event_attr *attr = &evsel->attr;
155
156    if (PRINT_FIELD(TRACE) &&
157        !perf_session__has_traces(session, "record -R"))
158        return -EINVAL;
159
160    if (PRINT_FIELD(SYM)) {
161        if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP",
162                       PERF_OUTPUT_SYM))
163            return -EINVAL;
164
165        if (!no_callchain &&
166            !(attr->sample_type & PERF_SAMPLE_CALLCHAIN))
167            symbol_conf.use_callchain = false;
168    }
169
170    if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
171        perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID",
172                       PERF_OUTPUT_TID|PERF_OUTPUT_PID))
173        return -EINVAL;
174
175    if (PRINT_FIELD(TIME) &&
176        perf_event_attr__check_stype(attr, PERF_SAMPLE_TIME, "TIME",
177                       PERF_OUTPUT_TIME))
178        return -EINVAL;
179
180    if (PRINT_FIELD(CPU) &&
181        perf_event_attr__check_stype(attr, PERF_SAMPLE_CPU, "CPU",
182                       PERF_OUTPUT_CPU))
183        return -EINVAL;
184
185    return 0;
186}
187
188/*
189 * verify all user requested events exist and the samples
190 * have the expected data
191 */
192static int perf_session__check_output_opt(struct perf_session *session)
193{
194    int j;
195    struct perf_evsel *evsel;
196
197    for (j = 0; j < PERF_TYPE_MAX; ++j) {
198        evsel = perf_session__find_first_evtype(session, j);
199
200        /*
201         * even if fields is set to 0 (ie., show nothing) event must
202         * exist if user explicitly includes it on the command line
203         */
204        if (!evsel && output[j].user_set && !output[j].wildcard_set) {
205            pr_err("%s events do not exist. "
206                   "Remove corresponding -f option to proceed.\n",
207                   event_type(j));
208            return -1;
209        }
210
211        if (evsel && output[j].fields &&
212            perf_evsel__check_attr(evsel, session))
213            return -1;
214    }
215
216    return 0;
217}
218
219static void print_sample_start(struct perf_sample *sample,
220                   struct thread *thread,
221                   struct perf_event_attr *attr)
222{
223    int type;
224    struct event *event;
225    const char *evname = NULL;
226    unsigned long secs;
227    unsigned long usecs;
228    unsigned long long nsecs;
229
230    if (PRINT_FIELD(COMM)) {
231        if (latency_format)
232            printf("%8.8s ", thread->comm);
233        else if (PRINT_FIELD(SYM) && symbol_conf.use_callchain)
234            printf("%s ", thread->comm);
235        else
236            printf("%16s ", thread->comm);
237    }
238
239    if (PRINT_FIELD(PID) && PRINT_FIELD(TID))
240        printf("%5d/%-5d ", sample->pid, sample->tid);
241    else if (PRINT_FIELD(PID))
242        printf("%5d ", sample->pid);
243    else if (PRINT_FIELD(TID))
244        printf("%5d ", sample->tid);
245
246    if (PRINT_FIELD(CPU)) {
247        if (latency_format)
248            printf("%3d ", sample->cpu);
249        else
250            printf("[%03d] ", sample->cpu);
251    }
252
253    if (PRINT_FIELD(TIME)) {
254        nsecs = sample->time;
255        secs = nsecs / NSECS_PER_SEC;
256        nsecs -= secs * NSECS_PER_SEC;
257        usecs = nsecs / NSECS_PER_USEC;
258        printf("%5lu.%06lu: ", secs, usecs);
259    }
260
261    if (PRINT_FIELD(EVNAME)) {
262        if (attr->type == PERF_TYPE_TRACEPOINT) {
263            type = trace_parse_common_type(sample->raw_data);
264            event = trace_find_event(type);
265            if (event)
266                evname = event->name;
267        } else
268            evname = __event_name(attr->type, attr->config);
269
270        printf("%s: ", evname ? evname : "(unknown)");
271    }
272}
273
274static void process_event(union perf_event *event __unused,
275              struct perf_sample *sample,
276              struct perf_evsel *evsel,
277              struct perf_session *session,
278              struct thread *thread)
279{
280    struct perf_event_attr *attr = &evsel->attr;
281
282    if (output[attr->type].fields == 0)
283        return;
284
285    print_sample_start(sample, thread, attr);
286
287    if (PRINT_FIELD(TRACE))
288        print_trace_event(sample->cpu, sample->raw_data,
289                  sample->raw_size);
290
291    if (PRINT_FIELD(SYM)) {
292        if (!symbol_conf.use_callchain)
293            printf(" ");
294        else
295            printf("\n");
296        perf_session__print_symbols(event, sample, session);
297    }
298
299    printf("\n");
300}
301
302static int default_start_script(const char *script __unused,
303                int argc __unused,
304                const char **argv __unused)
305{
306    return 0;
307}
308
309static int default_stop_script(void)
310{
311    return 0;
312}
313
314static int default_generate_script(const char *outfile __unused)
315{
316    return 0;
317}
318
319static struct scripting_ops default_scripting_ops = {
320    .start_script = default_start_script,
321    .stop_script = default_stop_script,
322    .process_event = process_event,
323    .generate_script = default_generate_script,
324};
325
326static struct scripting_ops *scripting_ops;
327
328static void setup_scripting(void)
329{
330    setup_perl_scripting();
331    setup_python_scripting();
332
333    scripting_ops = &default_scripting_ops;
334}
335
336static int cleanup_scripting(void)
337{
338    pr_debug("\nperf script stopped\n");
339
340    return scripting_ops->stop_script();
341}
342
343static char const *input_name = "perf.data";
344
345static int process_sample_event(union perf_event *event,
346                struct perf_sample *sample,
347                struct perf_evsel *evsel,
348                struct perf_session *session)
349{
350    struct thread *thread = perf_session__findnew(session, event->ip.pid);
351
352    if (thread == NULL) {
353        pr_debug("problem processing %d event, skipping it.\n",
354             event->header.type);
355        return -1;
356    }
357
358    if (debug_mode) {
359        if (sample->time < last_timestamp) {
360            pr_err("Samples misordered, previous: %" PRIu64
361                " this: %" PRIu64 "\n", last_timestamp,
362                sample->time);
363            nr_unordered++;
364        }
365        last_timestamp = sample->time;
366        return 0;
367    }
368    scripting_ops->process_event(event, sample, evsel, session, thread);
369
370    session->hists.stats.total_period += sample->period;
371    return 0;
372}
373
374static struct perf_event_ops event_ops = {
375    .sample = process_sample_event,
376    .mmap = perf_event__process_mmap,
377    .comm = perf_event__process_comm,
378    .exit = perf_event__process_task,
379    .fork = perf_event__process_task,
380    .attr = perf_event__process_attr,
381    .event_type = perf_event__process_event_type,
382    .tracing_data = perf_event__process_tracing_data,
383    .build_id = perf_event__process_build_id,
384    .ordered_samples = true,
385    .ordering_requires_timestamps = true,
386};
387
388extern volatile int session_done;
389
390static void sig_handler(int sig __unused)
391{
392    session_done = 1;
393}
394
395static int __cmd_script(struct perf_session *session)
396{
397    int ret;
398
399    signal(SIGINT, sig_handler);
400
401    ret = perf_session__process_events(session, &event_ops);
402
403    if (debug_mode)
404        pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
405
406    return ret;
407}
408
409struct script_spec {
410    struct list_head node;
411    struct scripting_ops *ops;
412    char spec[0];
413};
414
415static LIST_HEAD(script_specs);
416
417static struct script_spec *script_spec__new(const char *spec,
418                        struct scripting_ops *ops)
419{
420    struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1);
421
422    if (s != NULL) {
423        strcpy(s->spec, spec);
424        s->ops = ops;
425    }
426
427    return s;
428}
429
430static void script_spec__delete(struct script_spec *s)
431{
432    free(s->spec);
433    free(s);
434}
435
436static void script_spec__add(struct script_spec *s)
437{
438    list_add_tail(&s->node, &script_specs);
439}
440
441static struct script_spec *script_spec__find(const char *spec)
442{
443    struct script_spec *s;
444
445    list_for_each_entry(s, &script_specs, node)
446        if (strcasecmp(s->spec, spec) == 0)
447            return s;
448    return NULL;
449}
450
451static struct script_spec *script_spec__findnew(const char *spec,
452                        struct scripting_ops *ops)
453{
454    struct script_spec *s = script_spec__find(spec);
455
456    if (s)
457        return s;
458
459    s = script_spec__new(spec, ops);
460    if (!s)
461        goto out_delete_spec;
462
463    script_spec__add(s);
464
465    return s;
466
467out_delete_spec:
468    script_spec__delete(s);
469
470    return NULL;
471}
472
473int script_spec_register(const char *spec, struct scripting_ops *ops)
474{
475    struct script_spec *s;
476
477    s = script_spec__find(spec);
478    if (s)
479        return -1;
480
481    s = script_spec__findnew(spec, ops);
482    if (!s)
483        return -1;
484
485    return 0;
486}
487
488static struct scripting_ops *script_spec__lookup(const char *spec)
489{
490    struct script_spec *s = script_spec__find(spec);
491    if (!s)
492        return NULL;
493
494    return s->ops;
495}
496
497static void list_available_languages(void)
498{
499    struct script_spec *s;
500
501    fprintf(stderr, "\n");
502    fprintf(stderr, "Scripting language extensions (used in "
503        "perf script -s [spec:]script.[spec]):\n\n");
504
505    list_for_each_entry(s, &script_specs, node)
506        fprintf(stderr, " %-42s [%s]\n", s->spec, s->ops->name);
507
508    fprintf(stderr, "\n");
509}
510
511static int parse_scriptname(const struct option *opt __used,
512                const char *str, int unset __used)
513{
514    char spec[PATH_MAX];
515    const char *script, *ext;
516    int len;
517
518    if (strcmp(str, "lang") == 0) {
519        list_available_languages();
520        exit(0);
521    }
522
523    script = strchr(str, ':');
524    if (script) {
525        len = script - str;
526        if (len >= PATH_MAX) {
527            fprintf(stderr, "invalid language specifier");
528            return -1;
529        }
530        strncpy(spec, str, len);
531        spec[len] = '\0';
532        scripting_ops = script_spec__lookup(spec);
533        if (!scripting_ops) {
534            fprintf(stderr, "invalid language specifier");
535            return -1;
536        }
537        script++;
538    } else {
539        script = str;
540        ext = strrchr(script, '.');
541        if (!ext) {
542            fprintf(stderr, "invalid script extension");
543            return -1;
544        }
545        scripting_ops = script_spec__lookup(++ext);
546        if (!scripting_ops) {
547            fprintf(stderr, "invalid script extension");
548            return -1;
549        }
550    }
551
552    script_name = strdup(script);
553
554    return 0;
555}
556
557static int parse_output_fields(const struct option *opt __used,
558                const char *arg, int unset __used)
559{
560    char *tok;
561    int i, imax = sizeof(all_output_options) / sizeof(struct output_option);
562    int j;
563    int rc = 0;
564    char *str = strdup(arg);
565    int type = -1;
566
567    if (!str)
568        return -ENOMEM;
569
570    /* first word can state for which event type the user is specifying
571     * the fields. If no type exists, the specified fields apply to all
572     * event types found in the file minus the invalid fields for a type.
573     */
574    tok = strchr(str, ':');
575    if (tok) {
576        *tok = '\0';
577        tok++;
578        if (!strcmp(str, "hw"))
579            type = PERF_TYPE_HARDWARE;
580        else if (!strcmp(str, "sw"))
581            type = PERF_TYPE_SOFTWARE;
582        else if (!strcmp(str, "trace"))
583            type = PERF_TYPE_TRACEPOINT;
584        else if (!strcmp(str, "raw"))
585            type = PERF_TYPE_RAW;
586        else {
587            fprintf(stderr, "Invalid event type in field string.\n");
588            return -EINVAL;
589        }
590
591        if (output[type].user_set)
592            pr_warning("Overriding previous field request for %s events.\n",
593                   event_type(type));
594
595        output[type].fields = 0;
596        output[type].user_set = true;
597        output[type].wildcard_set = false;
598
599    } else {
600        tok = str;
601        if (strlen(str) == 0) {
602            fprintf(stderr,
603                "Cannot set fields to 'none' for all event types.\n");
604            rc = -EINVAL;
605            goto out;
606        }
607
608        if (output_set_by_user())
609            pr_warning("Overriding previous field request for all events.\n");
610
611        for (j = 0; j < PERF_TYPE_MAX; ++j) {
612            output[j].fields = 0;
613            output[j].user_set = true;
614            output[j].wildcard_set = true;
615        }
616    }
617
618    tok = strtok(tok, ",");
619    while (tok) {
620        for (i = 0; i < imax; ++i) {
621            if (strcmp(tok, all_output_options[i].str) == 0)
622                break;
623        }
624        if (i == imax) {
625            fprintf(stderr, "Invalid field requested.\n");
626            rc = -EINVAL;
627            goto out;
628        }
629
630        if (type == -1) {
631            /* add user option to all events types for
632             * which it is valid
633             */
634            for (j = 0; j < PERF_TYPE_MAX; ++j) {
635                if (output[j].invalid_fields & all_output_options[i].field) {
636                    pr_warning("\'%s\' not valid for %s events. Ignoring.\n",
637                           all_output_options[i].str, event_type(j));
638                } else
639                    output[j].fields |= all_output_options[i].field;
640            }
641        } else {
642            if (output[type].invalid_fields & all_output_options[i].field) {
643                fprintf(stderr, "\'%s\' not valid for %s events.\n",
644                     all_output_options[i].str, event_type(type));
645
646                rc = -EINVAL;
647                goto out;
648            }
649            output[type].fields |= all_output_options[i].field;
650        }
651
652        tok = strtok(NULL, ",");
653    }
654
655    if (type >= 0) {
656        if (output[type].fields == 0) {
657            pr_debug("No fields requested for %s type. "
658                 "Events will not be displayed.\n", event_type(type));
659        }
660    }
661
662out:
663    free(str);
664    return rc;
665}
666
667/* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */
668static int is_directory(const char *base_path, const struct dirent *dent)
669{
670    char path[PATH_MAX];
671    struct stat st;
672
673    sprintf(path, "%s/%s", base_path, dent->d_name);
674    if (stat(path, &st))
675        return 0;
676
677    return S_ISDIR(st.st_mode);
678}
679
680#define for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next)\
681    while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \
682           lang_next) \
683        if ((lang_dirent.d_type == DT_DIR || \
684             (lang_dirent.d_type == DT_UNKNOWN && \
685              is_directory(scripts_path, &lang_dirent))) && \
686            (strcmp(lang_dirent.d_name, ".")) && \
687            (strcmp(lang_dirent.d_name, "..")))
688
689#define for_each_script(lang_path, lang_dir, script_dirent, script_next)\
690    while (!readdir_r(lang_dir, &script_dirent, &script_next) && \
691           script_next) \
692        if (script_dirent.d_type != DT_DIR && \
693            (script_dirent.d_type != DT_UNKNOWN || \
694             !is_directory(lang_path, &script_dirent)))
695
696
697#define RECORD_SUFFIX "-record"
698#define REPORT_SUFFIX "-report"
699
700struct script_desc {
701    struct list_head node;
702    char *name;
703    char *half_liner;
704    char *args;
705};
706
707static LIST_HEAD(script_descs);
708
709static struct script_desc *script_desc__new(const char *name)
710{
711    struct script_desc *s = zalloc(sizeof(*s));
712
713    if (s != NULL && name)
714        s->name = strdup(name);
715
716    return s;
717}
718
719static void script_desc__delete(struct script_desc *s)
720{
721    free(s->name);
722    free(s->half_liner);
723    free(s->args);
724    free(s);
725}
726
727static void script_desc__add(struct script_desc *s)
728{
729    list_add_tail(&s->node, &script_descs);
730}
731
732static struct script_desc *script_desc__find(const char *name)
733{
734    struct script_desc *s;
735
736    list_for_each_entry(s, &script_descs, node)
737        if (strcasecmp(s->name, name) == 0)
738            return s;
739    return NULL;
740}
741
742static struct script_desc *script_desc__findnew(const char *name)
743{
744    struct script_desc *s = script_desc__find(name);
745
746    if (s)
747        return s;
748
749    s = script_desc__new(name);
750    if (!s)
751        goto out_delete_desc;
752
753    script_desc__add(s);
754
755    return s;
756
757out_delete_desc:
758    script_desc__delete(s);
759
760    return NULL;
761}
762
763static const char *ends_with(const char *str, const char *suffix)
764{
765    size_t suffix_len = strlen(suffix);
766    const char *p = str;
767
768    if (strlen(str) > suffix_len) {
769        p = str + strlen(str) - suffix_len;
770        if (!strncmp(p, suffix, suffix_len))
771            return p;
772    }
773
774    return NULL;
775}
776
777static char *ltrim(char *str)
778{
779    int len = strlen(str);
780
781    while (len && isspace(*str)) {
782        len--;
783        str++;
784    }
785
786    return str;
787}
788
789static int read_script_info(struct script_desc *desc, const char *filename)
790{
791    char line[BUFSIZ], *p;
792    FILE *fp;
793
794    fp = fopen(filename, "r");
795    if (!fp)
796        return -1;
797
798    while (fgets(line, sizeof(line), fp)) {
799        p = ltrim(line);
800        if (strlen(p) == 0)
801            continue;
802        if (*p != '#')
803            continue;
804        p++;
805        if (strlen(p) && *p == '!')
806            continue;
807
808        p = ltrim(p);
809        if (strlen(p) && p[strlen(p) - 1] == '\n')
810            p[strlen(p) - 1] = '\0';
811
812        if (!strncmp(p, "description:", strlen("description:"))) {
813            p += strlen("description:");
814            desc->half_liner = strdup(ltrim(p));
815            continue;
816        }
817
818        if (!strncmp(p, "args:", strlen("args:"))) {
819            p += strlen("args:");
820            desc->args = strdup(ltrim(p));
821            continue;
822        }
823    }
824
825    fclose(fp);
826
827    return 0;
828}
829
830static int list_available_scripts(const struct option *opt __used,
831                  const char *s __used, int unset __used)
832{
833    struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
834    char scripts_path[MAXPATHLEN];
835    DIR *scripts_dir, *lang_dir;
836    char script_path[MAXPATHLEN];
837    char lang_path[MAXPATHLEN];
838    struct script_desc *desc;
839    char first_half[BUFSIZ];
840    char *script_root;
841    char *str;
842
843    snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
844
845    scripts_dir = opendir(scripts_path);
846    if (!scripts_dir)
847        return -1;
848
849    for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
850        snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
851             lang_dirent.d_name);
852        lang_dir = opendir(lang_path);
853        if (!lang_dir)
854            continue;
855
856        for_each_script(lang_path, lang_dir, script_dirent, script_next) {
857            script_root = strdup(script_dirent.d_name);
858            str = (char *)ends_with(script_root, REPORT_SUFFIX);
859            if (str) {
860                *str = '\0';
861                desc = script_desc__findnew(script_root);
862                snprintf(script_path, MAXPATHLEN, "%s/%s",
863                     lang_path, script_dirent.d_name);
864                read_script_info(desc, script_path);
865            }
866            free(script_root);
867        }
868    }
869
870    fprintf(stdout, "List of available trace scripts:\n");
871    list_for_each_entry(desc, &script_descs, node) {
872        sprintf(first_half, "%s %s", desc->name,
873            desc->args ? desc->args : "");
874        fprintf(stdout, " %-36s %s\n", first_half,
875            desc->half_liner ? desc->half_liner : "");
876    }
877
878    exit(0);
879}
880
881static char *get_script_path(const char *script_root, const char *suffix)
882{
883    struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
884    char scripts_path[MAXPATHLEN];
885    char script_path[MAXPATHLEN];
886    DIR *scripts_dir, *lang_dir;
887    char lang_path[MAXPATHLEN];
888    char *str, *__script_root;
889    char *path = NULL;
890
891    snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
892
893    scripts_dir = opendir(scripts_path);
894    if (!scripts_dir)
895        return NULL;
896
897    for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
898        snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
899             lang_dirent.d_name);
900        lang_dir = opendir(lang_path);
901        if (!lang_dir)
902            continue;
903
904        for_each_script(lang_path, lang_dir, script_dirent, script_next) {
905            __script_root = strdup(script_dirent.d_name);
906            str = (char *)ends_with(__script_root, suffix);
907            if (str) {
908                *str = '\0';
909                if (strcmp(__script_root, script_root))
910                    continue;
911                snprintf(script_path, MAXPATHLEN, "%s/%s",
912                     lang_path, script_dirent.d_name);
913                path = strdup(script_path);
914                free(__script_root);
915                break;
916            }
917            free(__script_root);
918        }
919    }
920
921    return path;
922}
923
924static bool is_top_script(const char *script_path)
925{
926    return ends_with(script_path, "top") == NULL ? false : true;
927}
928
929static int has_required_arg(char *script_path)
930{
931    struct script_desc *desc;
932    int n_args = 0;
933    char *p;
934
935    desc = script_desc__new(NULL);
936
937    if (read_script_info(desc, script_path))
938        goto out;
939
940    if (!desc->args)
941        goto out;
942
943    for (p = desc->args; *p; p++)
944        if (*p == '<')
945            n_args++;
946out:
947    script_desc__delete(desc);
948
949    return n_args;
950}
951
952static const char * const script_usage[] = {
953    "perf script [<options>]",
954    "perf script [<options>] record <script> [<record-options>] <command>",
955    "perf script [<options>] report <script> [script-args]",
956    "perf script [<options>] <script> [<record-options>] <command>",
957    "perf script [<options>] <top-script> [script-args]",
958    NULL
959};
960
961static const struct option options[] = {
962    OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
963            "dump raw trace in ASCII"),
964    OPT_INCR('v', "verbose", &verbose,
965            "be more verbose (show symbol address, etc)"),
966    OPT_BOOLEAN('L', "Latency", &latency_format,
967            "show latency attributes (irqs/preemption disabled, etc)"),
968    OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
969               list_available_scripts),
970    OPT_CALLBACK('s', "script", NULL, "name",
971             "script file name (lang:script name, script name, or *)",
972             parse_scriptname),
973    OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
974           "generate perf-script.xx script in specified language"),
975    OPT_STRING('i', "input", &input_name, "file",
976            "input file name"),
977    OPT_BOOLEAN('d', "debug-mode", &debug_mode,
978           "do various checks like samples ordering and lost events"),
979    OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
980           "file", "vmlinux pathname"),
981    OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
982           "file", "kallsyms pathname"),
983    OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
984            "When printing symbols do not display call chain"),
985    OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
986            "Look for files with symbols relative to this directory"),
987    OPT_CALLBACK('f', "fields", NULL, "str",
988             "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,sym",
989             parse_output_fields),
990
991    OPT_END()
992};
993
994static bool have_cmd(int argc, const char **argv)
995{
996    char **__argv = malloc(sizeof(const char *) * argc);
997
998    if (!__argv)
999        die("malloc");
1000    memcpy(__argv, argv, sizeof(const char *) * argc);
1001    argc = parse_options(argc, (const char **)__argv, record_options,
1002                 NULL, PARSE_OPT_STOP_AT_NON_OPTION);
1003    free(__argv);
1004
1005    return argc != 0;
1006}
1007
1008int cmd_script(int argc, const char **argv, const char *prefix __used)
1009{
1010    char *rec_script_path = NULL;
1011    char *rep_script_path = NULL;
1012    struct perf_session *session;
1013    char *script_path = NULL;
1014    const char **__argv;
1015    bool system_wide;
1016    int i, j, err;
1017
1018    setup_scripting();
1019
1020    argc = parse_options(argc, argv, options, script_usage,
1021                 PARSE_OPT_STOP_AT_NON_OPTION);
1022
1023    if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
1024        rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
1025        if (!rec_script_path)
1026            return cmd_record(argc, argv, NULL);
1027    }
1028
1029    if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) {
1030        rep_script_path = get_script_path(argv[1], REPORT_SUFFIX);
1031        if (!rep_script_path) {
1032            fprintf(stderr,
1033                "Please specify a valid report script"
1034                "(see 'perf script -l' for listing)\n");
1035            return -1;
1036        }
1037    }
1038
1039    /* make sure PERF_EXEC_PATH is set for scripts */
1040    perf_set_argv_exec_path(perf_exec_path());
1041
1042    if (argc && !script_name && !rec_script_path && !rep_script_path) {
1043        int live_pipe[2];
1044        int rep_args;
1045        pid_t pid;
1046
1047        rec_script_path = get_script_path(argv[0], RECORD_SUFFIX);
1048        rep_script_path = get_script_path(argv[0], REPORT_SUFFIX);
1049
1050        if (!rec_script_path && !rep_script_path) {
1051            fprintf(stderr, " Couldn't find script %s\n\n See perf"
1052                " script -l for available scripts.\n", argv[0]);
1053            usage_with_options(script_usage, options);
1054        }
1055
1056        if (is_top_script(argv[0])) {
1057            rep_args = argc - 1;
1058        } else {
1059            int rec_args;
1060
1061            rep_args = has_required_arg(rep_script_path);
1062            rec_args = (argc - 1) - rep_args;
1063            if (rec_args < 0) {
1064                fprintf(stderr, " %s script requires options."
1065                    "\n\n See perf script -l for available "
1066                    "scripts and options.\n", argv[0]);
1067                usage_with_options(script_usage, options);
1068            }
1069        }
1070
1071        if (pipe(live_pipe) < 0) {
1072            perror("failed to create pipe");
1073            exit(-1);
1074        }
1075
1076        pid = fork();
1077        if (pid < 0) {
1078            perror("failed to fork");
1079            exit(-1);
1080        }
1081
1082        if (!pid) {
1083            system_wide = true;
1084            j = 0;
1085
1086            dup2(live_pipe[1], 1);
1087            close(live_pipe[0]);
1088
1089            if (!is_top_script(argv[0]))
1090                system_wide = !have_cmd(argc - rep_args,
1091                            &argv[rep_args]);
1092
1093            __argv = malloc((argc + 6) * sizeof(const char *));
1094            if (!__argv)
1095                die("malloc");
1096
1097            __argv[j++] = "/bin/sh";
1098            __argv[j++] = rec_script_path;
1099            if (system_wide)
1100                __argv[j++] = "-a";
1101            __argv[j++] = "-q";
1102            __argv[j++] = "-o";
1103            __argv[j++] = "-";
1104            for (i = rep_args + 1; i < argc; i++)
1105                __argv[j++] = argv[i];
1106            __argv[j++] = NULL;
1107
1108            execvp("/bin/sh", (char **)__argv);
1109            free(__argv);
1110            exit(-1);
1111        }
1112
1113        dup2(live_pipe[0], 0);
1114        close(live_pipe[1]);
1115
1116        __argv = malloc((argc + 4) * sizeof(const char *));
1117        if (!__argv)
1118            die("malloc");
1119        j = 0;
1120        __argv[j++] = "/bin/sh";
1121        __argv[j++] = rep_script_path;
1122        for (i = 1; i < rep_args + 1; i++)
1123            __argv[j++] = argv[i];
1124        __argv[j++] = "-i";
1125        __argv[j++] = "-";
1126        __argv[j++] = NULL;
1127
1128        execvp("/bin/sh", (char **)__argv);
1129        free(__argv);
1130        exit(-1);
1131    }
1132
1133    if (rec_script_path)
1134        script_path = rec_script_path;
1135    if (rep_script_path)
1136        script_path = rep_script_path;
1137
1138    if (script_path) {
1139        system_wide = false;
1140        j = 0;
1141
1142        if (rec_script_path)
1143            system_wide = !have_cmd(argc - 1, &argv[1]);
1144
1145        __argv = malloc((argc + 2) * sizeof(const char *));
1146        if (!__argv)
1147            die("malloc");
1148        __argv[j++] = "/bin/sh";
1149        __argv[j++] = script_path;
1150        if (system_wide)
1151            __argv[j++] = "-a";
1152        for (i = 2; i < argc; i++)
1153            __argv[j++] = argv[i];
1154        __argv[j++] = NULL;
1155
1156        execvp("/bin/sh", (char **)__argv);
1157        free(__argv);
1158        exit(-1);
1159    }
1160
1161    if (symbol__init() < 0)
1162        return -1;
1163    if (!script_name)
1164        setup_pager();
1165
1166    session = perf_session__new(input_name, O_RDONLY, 0, false, &event_ops);
1167    if (session == NULL)
1168        return -ENOMEM;
1169
1170    if (!no_callchain)
1171        symbol_conf.use_callchain = true;
1172    else
1173        symbol_conf.use_callchain = false;
1174
1175    if (generate_script_lang) {
1176        struct stat perf_stat;
1177        int input;
1178
1179        if (output_set_by_user()) {
1180            fprintf(stderr,
1181                "custom fields not supported for generated scripts");
1182            return -1;
1183        }
1184
1185        input = open(input_name, O_RDONLY);
1186        if (input < 0) {
1187            perror("failed to open file");
1188            exit(-1);
1189        }
1190
1191        err = fstat(input, &perf_stat);
1192        if (err < 0) {
1193            perror("failed to stat file");
1194            exit(-1);
1195        }
1196
1197        if (!perf_stat.st_size) {
1198            fprintf(stderr, "zero-sized file, nothing to do!\n");
1199            exit(0);
1200        }
1201
1202        scripting_ops = script_spec__lookup(generate_script_lang);
1203        if (!scripting_ops) {
1204            fprintf(stderr, "invalid language specifier");
1205            return -1;
1206        }
1207
1208        err = scripting_ops->generate_script("perf-script");
1209        goto out;
1210    }
1211
1212    if (script_name) {
1213        err = scripting_ops->start_script(script_name, argc, argv);
1214        if (err)
1215            goto out;
1216        pr_debug("perf script started with script %s\n\n", script_name);
1217    }
1218
1219
1220    err = perf_session__check_output_opt(session);
1221    if (err < 0)
1222        goto out;
1223
1224    err = __cmd_script(session);
1225
1226    perf_session__delete(session);
1227    cleanup_scripting();
1228out:
1229    return err;
1230}
1231

Archive Download this file



interactive