]> git.karo-electronics.de Git - karo-tx-linux.git/blob - tools/perf/builtin-trace.c
perf/scripts: Fix supported language listing option
[karo-tx-linux.git] / tools / perf / builtin-trace.c
1 #include "builtin.h"
2
3 #include "util/util.h"
4 #include "util/cache.h"
5 #include "util/symbol.h"
6 #include "util/thread.h"
7 #include "util/header.h"
8 #include "util/exec_cmd.h"
9 #include "util/trace-event.h"
10 #include "util/session.h"
11
12 static char const               *script_name;
13 static char const               *generate_script_lang;
14
15 static int default_start_script(const char *script __unused,
16                                 int argc __unused,
17                                 const char **argv __unused)
18 {
19         return 0;
20 }
21
22 static int default_stop_script(void)
23 {
24         return 0;
25 }
26
27 static int default_generate_script(const char *outfile __unused)
28 {
29         return 0;
30 }
31
32 static struct scripting_ops default_scripting_ops = {
33         .start_script           = default_start_script,
34         .stop_script            = default_stop_script,
35         .process_event          = print_event,
36         .generate_script        = default_generate_script,
37 };
38
39 static struct scripting_ops     *scripting_ops;
40
41 static void setup_scripting(void)
42 {
43         /* make sure PERF_EXEC_PATH is set for scripts */
44         perf_set_argv_exec_path(perf_exec_path());
45
46         setup_perl_scripting();
47
48         scripting_ops = &default_scripting_ops;
49 }
50
51 static int cleanup_scripting(void)
52 {
53         return scripting_ops->stop_script();
54 }
55
56 #include "util/parse-options.h"
57
58 #include "perf.h"
59 #include "util/debug.h"
60
61 #include "util/trace-event.h"
62 #include "util/exec_cmd.h"
63
64 static char const               *input_name = "perf.data";
65
66 static int process_sample_event(event_t *event, struct perf_session *session)
67 {
68         struct sample_data data;
69         struct thread *thread;
70
71         memset(&data, 0, sizeof(data));
72         data.time = -1;
73         data.cpu = -1;
74         data.period = 1;
75
76         event__parse_sample(event, session->sample_type, &data);
77
78         dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
79                     data.pid, data.tid, data.ip, data.period);
80
81         thread = perf_session__findnew(session, event->ip.pid);
82         if (thread == NULL) {
83                 pr_debug("problem processing %d event, skipping it.\n",
84                          event->header.type);
85                 return -1;
86         }
87
88         if (session->sample_type & PERF_SAMPLE_RAW) {
89                 /*
90                  * FIXME: better resolve from pid from the struct trace_entry
91                  * field, although it should be the same than this perf
92                  * event pid
93                  */
94                 scripting_ops->process_event(data.cpu, data.raw_data,
95                                              data.raw_size,
96                                              data.time, thread->comm);
97         }
98
99         session->events_stats.total += data.period;
100         return 0;
101 }
102
103 static struct perf_event_ops event_ops = {
104         .sample = process_sample_event,
105         .comm   = event__process_comm,
106 };
107
108 static int __cmd_trace(struct perf_session *session)
109 {
110         return perf_session__process_events(session, &event_ops);
111 }
112
113 struct script_spec {
114         struct list_head        node;
115         struct scripting_ops    *ops;
116         char                    spec[0];
117 };
118
119 LIST_HEAD(script_specs);
120
121 static struct script_spec *script_spec__new(const char *spec,
122                                             struct scripting_ops *ops)
123 {
124         struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1);
125
126         if (s != NULL) {
127                 strcpy(s->spec, spec);
128                 s->ops = ops;
129         }
130
131         return s;
132 }
133
134 static void script_spec__delete(struct script_spec *s)
135 {
136         free(s->spec);
137         free(s);
138 }
139
140 static void script_spec__add(struct script_spec *s)
141 {
142         list_add_tail(&s->node, &script_specs);
143 }
144
145 static struct script_spec *script_spec__find(const char *spec)
146 {
147         struct script_spec *s;
148
149         list_for_each_entry(s, &script_specs, node)
150                 if (strcasecmp(s->spec, spec) == 0)
151                         return s;
152         return NULL;
153 }
154
155 static struct script_spec *script_spec__findnew(const char *spec,
156                                                 struct scripting_ops *ops)
157 {
158         struct script_spec *s = script_spec__find(spec);
159
160         if (s)
161                 return s;
162
163         s = script_spec__new(spec, ops);
164         if (!s)
165                 goto out_delete_spec;
166
167         script_spec__add(s);
168
169         return s;
170
171 out_delete_spec:
172         script_spec__delete(s);
173
174         return NULL;
175 }
176
177 int script_spec_register(const char *spec, struct scripting_ops *ops)
178 {
179         struct script_spec *s;
180
181         s = script_spec__find(spec);
182         if (s)
183                 return -1;
184
185         s = script_spec__findnew(spec, ops);
186         if (!s)
187                 return -1;
188
189         return 0;
190 }
191
192 static struct scripting_ops *script_spec__lookup(const char *spec)
193 {
194         struct script_spec *s = script_spec__find(spec);
195         if (!s)
196                 return NULL;
197
198         return s->ops;
199 }
200
201 static void list_available_languages(void)
202 {
203         struct script_spec *s;
204
205         fprintf(stderr, "\n");
206         fprintf(stderr, "Scripting language extensions (used in "
207                 "perf trace -s [spec:]script.[spec]):\n\n");
208
209         list_for_each_entry(s, &script_specs, node)
210                 fprintf(stderr, "  %-42s [%s]\n", s->spec, s->ops->name);
211
212         fprintf(stderr, "\n");
213 }
214
215 static int parse_scriptname(const struct option *opt __used,
216                             const char *str, int unset __used)
217 {
218         char spec[PATH_MAX];
219         const char *script, *ext;
220         int len;
221
222         if (strcmp(str, "lang") == 0) {
223                 list_available_languages();
224                 exit(0);
225         }
226
227         script = strchr(str, ':');
228         if (script) {
229                 len = script - str;
230                 if (len >= PATH_MAX) {
231                         fprintf(stderr, "invalid language specifier");
232                         return -1;
233                 }
234                 strncpy(spec, str, len);
235                 spec[len] = '\0';
236                 scripting_ops = script_spec__lookup(spec);
237                 if (!scripting_ops) {
238                         fprintf(stderr, "invalid language specifier");
239                         return -1;
240                 }
241                 script++;
242         } else {
243                 script = str;
244                 ext = strchr(script, '.');
245                 if (!ext) {
246                         fprintf(stderr, "invalid script extension");
247                         return -1;
248                 }
249                 scripting_ops = script_spec__lookup(++ext);
250                 if (!scripting_ops) {
251                         fprintf(stderr, "invalid script extension");
252                         return -1;
253                 }
254         }
255
256         script_name = strdup(script);
257
258         return 0;
259 }
260
261 #define for_each_lang(scripts_dir, lang_dirent, lang_next)              \
262         while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) &&     \
263                lang_next)                                               \
264                 if (lang_dirent.d_type == DT_DIR &&                     \
265                     (strcmp(lang_dirent.d_name, ".")) &&                \
266                     (strcmp(lang_dirent.d_name, "..")))
267
268 #define for_each_script(lang_dir, script_dirent, script_next)           \
269         while (!readdir_r(lang_dir, &script_dirent, &script_next) &&    \
270                script_next)                                             \
271                 if (script_dirent.d_type != DT_DIR)
272
273
274 #define RECORD_SUFFIX                   "-record"
275 #define REPORT_SUFFIX                   "-report"
276
277 struct script_desc {
278         struct list_head        node;
279         char                    *name;
280         char                    *half_liner;
281         char                    *args;
282 };
283
284 LIST_HEAD(script_descs);
285
286 static struct script_desc *script_desc__new(const char *name)
287 {
288         struct script_desc *s = zalloc(sizeof(*s));
289
290         if (s != NULL)
291                 s->name = strdup(name);
292
293         return s;
294 }
295
296 static void script_desc__delete(struct script_desc *s)
297 {
298         free(s->name);
299         free(s);
300 }
301
302 static void script_desc__add(struct script_desc *s)
303 {
304         list_add_tail(&s->node, &script_descs);
305 }
306
307 static struct script_desc *script_desc__find(const char *name)
308 {
309         struct script_desc *s;
310
311         list_for_each_entry(s, &script_descs, node)
312                 if (strcasecmp(s->name, name) == 0)
313                         return s;
314         return NULL;
315 }
316
317 static struct script_desc *script_desc__findnew(const char *name)
318 {
319         struct script_desc *s = script_desc__find(name);
320
321         if (s)
322                 return s;
323
324         s = script_desc__new(name);
325         if (!s)
326                 goto out_delete_desc;
327
328         script_desc__add(s);
329
330         return s;
331
332 out_delete_desc:
333         script_desc__delete(s);
334
335         return NULL;
336 }
337
338 static char *ends_with(char *str, const char *suffix)
339 {
340         size_t suffix_len = strlen(suffix);
341         char *p = str;
342
343         if (strlen(str) > suffix_len) {
344                 p = str + strlen(str) - suffix_len;
345                 if (!strncmp(p, suffix, suffix_len))
346                         return p;
347         }
348
349         return NULL;
350 }
351
352 static char *ltrim(char *str)
353 {
354         int len = strlen(str);
355
356         while (len && isspace(*str)) {
357                 len--;
358                 str++;
359         }
360
361         return str;
362 }
363
364 static int read_script_info(struct script_desc *desc, const char *filename)
365 {
366         char line[BUFSIZ], *p;
367         FILE *fp;
368
369         fp = fopen(filename, "r");
370         if (!fp)
371                 return -1;
372
373         while (fgets(line, sizeof(line), fp)) {
374                 p = ltrim(line);
375                 if (strlen(p) == 0)
376                         continue;
377                 if (*p != '#')
378                         continue;
379                 p++;
380                 if (strlen(p) && *p == '!')
381                         continue;
382
383                 p = ltrim(p);
384                 if (strlen(p) && p[strlen(p) - 1] == '\n')
385                         p[strlen(p) - 1] = '\0';
386
387                 if (!strncmp(p, "description:", strlen("description:"))) {
388                         p += strlen("description:");
389                         desc->half_liner = strdup(ltrim(p));
390                         continue;
391                 }
392
393                 if (!strncmp(p, "args:", strlen("args:"))) {
394                         p += strlen("args:");
395                         desc->args = strdup(ltrim(p));
396                         continue;
397                 }
398         }
399
400         fclose(fp);
401
402         return 0;
403 }
404
405 static int list_available_scripts(const struct option *opt __used,
406                                   const char *s __used, int unset __used)
407 {
408         struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
409         char scripts_path[MAXPATHLEN];
410         DIR *scripts_dir, *lang_dir;
411         char script_path[MAXPATHLEN];
412         char lang_path[MAXPATHLEN];
413         struct script_desc *desc;
414         char first_half[BUFSIZ];
415         char *script_root;
416         char *str;
417
418         snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
419
420         scripts_dir = opendir(scripts_path);
421         if (!scripts_dir)
422                 return -1;
423
424         for_each_lang(scripts_dir, lang_dirent, lang_next) {
425                 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
426                          lang_dirent.d_name);
427                 lang_dir = opendir(lang_path);
428                 if (!lang_dir)
429                         continue;
430
431                 for_each_script(lang_dir, script_dirent, script_next) {
432                         script_root = strdup(script_dirent.d_name);
433                         str = ends_with(script_root, REPORT_SUFFIX);
434                         if (str) {
435                                 *str = '\0';
436                                 desc = script_desc__findnew(script_root);
437                                 snprintf(script_path, MAXPATHLEN, "%s/%s",
438                                          lang_path, script_dirent.d_name);
439                                 read_script_info(desc, script_path);
440                         }
441                         free(script_root);
442                 }
443         }
444
445         fprintf(stdout, "List of available trace scripts:\n");
446         list_for_each_entry(desc, &script_descs, node) {
447                 sprintf(first_half, "%s %s", desc->name,
448                         desc->args ? desc->args : "");
449                 fprintf(stdout, "  %-36s %s\n", first_half,
450                         desc->half_liner ? desc->half_liner : "");
451         }
452
453         exit(0);
454 }
455
456 static char *get_script_path(const char *script_root, const char *suffix)
457 {
458         struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
459         char scripts_path[MAXPATHLEN];
460         char script_path[MAXPATHLEN];
461         DIR *scripts_dir, *lang_dir;
462         char lang_path[MAXPATHLEN];
463         char *str, *__script_root;
464         char *path = NULL;
465
466         snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
467
468         scripts_dir = opendir(scripts_path);
469         if (!scripts_dir)
470                 return NULL;
471
472         for_each_lang(scripts_dir, lang_dirent, lang_next) {
473                 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
474                          lang_dirent.d_name);
475                 lang_dir = opendir(lang_path);
476                 if (!lang_dir)
477                         continue;
478
479                 for_each_script(lang_dir, script_dirent, script_next) {
480                         __script_root = strdup(script_dirent.d_name);
481                         str = ends_with(__script_root, suffix);
482                         if (str) {
483                                 *str = '\0';
484                                 if (strcmp(__script_root, script_root))
485                                         continue;
486                                 snprintf(script_path, MAXPATHLEN, "%s/%s",
487                                          lang_path, script_dirent.d_name);
488                                 path = strdup(script_path);
489                                 free(__script_root);
490                                 break;
491                         }
492                         free(__script_root);
493                 }
494         }
495
496         return path;
497 }
498
499 static const char * const trace_usage[] = {
500         "perf trace [<options>] <command>",
501         NULL
502 };
503
504 static const struct option options[] = {
505         OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
506                     "dump raw trace in ASCII"),
507         OPT_BOOLEAN('v', "verbose", &verbose,
508                     "be more verbose (show symbol address, etc)"),
509         OPT_BOOLEAN('L', "Latency", &latency_format,
510                     "show latency attributes (irqs/preemption disabled, etc)"),
511         OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
512                            list_available_scripts),
513         OPT_CALLBACK('s', "script", NULL, "name",
514                      "script file name (lang:script name, script name, or *)",
515                      parse_scriptname),
516         OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
517                    "generate perf-trace.xx script in specified language"),
518         OPT_STRING('i', "input", &input_name, "file",
519                     "input file name"),
520
521         OPT_END()
522 };
523
524 int cmd_trace(int argc, const char **argv, const char *prefix __used)
525 {
526         struct perf_session *session;
527         const char *suffix = NULL;
528         const char **__argv;
529         char *script_path;
530         int i, err;
531
532         if (argc >= 2 && strncmp(argv[1], "rec", strlen("rec")) == 0) {
533                 if (argc < 3) {
534                         fprintf(stderr,
535                                 "Please specify a record script\n");
536                         return -1;
537                 }
538                 suffix = RECORD_SUFFIX;
539         }
540
541         if (argc >= 2 && strncmp(argv[1], "rep", strlen("rep")) == 0) {
542                 if (argc < 3) {
543                         fprintf(stderr,
544                                 "Please specify a report script\n");
545                         return -1;
546                 }
547                 suffix = REPORT_SUFFIX;
548         }
549
550         if (suffix) {
551                 script_path = get_script_path(argv[2], suffix);
552                 if (!script_path) {
553                         fprintf(stderr, "script not found\n");
554                         return -1;
555                 }
556
557                 __argv = malloc((argc + 1) * sizeof(const char *));
558                 __argv[0] = "/bin/sh";
559                 __argv[1] = script_path;
560                 for (i = 3; i < argc; i++)
561                         __argv[i - 1] = argv[i];
562                 __argv[argc - 1] = NULL;
563
564                 execvp("/bin/sh", (char **)__argv);
565                 exit(-1);
566         }
567
568         setup_scripting();
569
570         argc = parse_options(argc, argv, options, trace_usage,
571                              PARSE_OPT_STOP_AT_NON_OPTION);
572
573         if (symbol__init() < 0)
574                 return -1;
575         setup_pager();
576
577         session = perf_session__new(input_name, O_RDONLY, 0);
578         if (session == NULL)
579                 return -ENOMEM;
580
581         if (!perf_session__has_traces(session, "record -R"))
582                 return -EINVAL;
583
584         if (generate_script_lang) {
585                 struct stat perf_stat;
586
587                 int input = open(input_name, O_RDONLY);
588                 if (input < 0) {
589                         perror("failed to open file");
590                         exit(-1);
591                 }
592
593                 err = fstat(input, &perf_stat);
594                 if (err < 0) {
595                         perror("failed to stat file");
596                         exit(-1);
597                 }
598
599                 if (!perf_stat.st_size) {
600                         fprintf(stderr, "zero-sized file, nothing to do!\n");
601                         exit(0);
602                 }
603
604                 scripting_ops = script_spec__lookup(generate_script_lang);
605                 if (!scripting_ops) {
606                         fprintf(stderr, "invalid language specifier");
607                         return -1;
608                 }
609
610                 perf_header__read(&session->header, input);
611                 err = scripting_ops->generate_script("perf-trace");
612                 goto out;
613         }
614
615         if (script_name) {
616                 err = scripting_ops->start_script(script_name, argc, argv);
617                 if (err)
618                         goto out;
619         }
620
621         err = __cmd_trace(session);
622
623         perf_session__delete(session);
624         cleanup_scripting();
625 out:
626         return err;
627 }