diff options
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r-- | tools/perf/builtin-script.c | 130 |
1 files changed, 74 insertions, 56 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 2f62a295226..fd1909afcfd 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include "util/header.h" | 7 | #include "util/header.h" |
8 | #include "util/parse-options.h" | 8 | #include "util/parse-options.h" |
9 | #include "util/session.h" | 9 | #include "util/session.h" |
10 | #include "util/tool.h" | ||
10 | #include "util/symbol.h" | 11 | #include "util/symbol.h" |
11 | #include "util/thread.h" | 12 | #include "util/thread.h" |
12 | #include "util/trace-event.h" | 13 | #include "util/trace-event.h" |
@@ -23,6 +24,7 @@ static u64 nr_unordered; | |||
23 | extern const struct option record_options[]; | 24 | extern const struct option record_options[]; |
24 | static bool no_callchain; | 25 | static bool no_callchain; |
25 | static bool show_full_info; | 26 | static bool show_full_info; |
27 | static bool system_wide; | ||
26 | static const char *cpu_list; | 28 | static const char *cpu_list; |
27 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 29 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
28 | 30 | ||
@@ -315,7 +317,7 @@ static bool sample_addr_correlates_sym(struct perf_event_attr *attr) | |||
315 | 317 | ||
316 | static void print_sample_addr(union perf_event *event, | 318 | static void print_sample_addr(union perf_event *event, |
317 | struct perf_sample *sample, | 319 | struct perf_sample *sample, |
318 | struct perf_session *session, | 320 | struct machine *machine, |
319 | struct thread *thread, | 321 | struct thread *thread, |
320 | struct perf_event_attr *attr) | 322 | struct perf_event_attr *attr) |
321 | { | 323 | { |
@@ -328,11 +330,11 @@ static void print_sample_addr(union perf_event *event, | |||
328 | if (!sample_addr_correlates_sym(attr)) | 330 | if (!sample_addr_correlates_sym(attr)) |
329 | return; | 331 | return; |
330 | 332 | ||
331 | thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, | 333 | thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, |
332 | event->ip.pid, sample->addr, &al); | 334 | sample->addr, &al); |
333 | if (!al.map) | 335 | if (!al.map) |
334 | thread__find_addr_map(thread, session, cpumode, MAP__VARIABLE, | 336 | thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE, |
335 | event->ip.pid, sample->addr, &al); | 337 | sample->addr, &al); |
336 | 338 | ||
337 | al.cpu = sample->cpu; | 339 | al.cpu = sample->cpu; |
338 | al.sym = NULL; | 340 | al.sym = NULL; |
@@ -362,7 +364,7 @@ static void print_sample_addr(union perf_event *event, | |||
362 | static void process_event(union perf_event *event __unused, | 364 | static void process_event(union perf_event *event __unused, |
363 | struct perf_sample *sample, | 365 | struct perf_sample *sample, |
364 | struct perf_evsel *evsel, | 366 | struct perf_evsel *evsel, |
365 | struct perf_session *session, | 367 | struct machine *machine, |
366 | struct thread *thread) | 368 | struct thread *thread) |
367 | { | 369 | { |
368 | struct perf_event_attr *attr = &evsel->attr; | 370 | struct perf_event_attr *attr = &evsel->attr; |
@@ -377,15 +379,15 @@ static void process_event(union perf_event *event __unused, | |||
377 | sample->raw_size); | 379 | sample->raw_size); |
378 | 380 | ||
379 | if (PRINT_FIELD(ADDR)) | 381 | if (PRINT_FIELD(ADDR)) |
380 | print_sample_addr(event, sample, session, thread, attr); | 382 | print_sample_addr(event, sample, machine, thread, attr); |
381 | 383 | ||
382 | if (PRINT_FIELD(IP)) { | 384 | if (PRINT_FIELD(IP)) { |
383 | if (!symbol_conf.use_callchain) | 385 | if (!symbol_conf.use_callchain) |
384 | printf(" "); | 386 | printf(" "); |
385 | else | 387 | else |
386 | printf("\n"); | 388 | printf("\n"); |
387 | perf_session__print_ip(event, sample, session, | 389 | perf_event__print_ip(event, sample, machine, evsel, |
388 | PRINT_FIELD(SYM), PRINT_FIELD(DSO)); | 390 | PRINT_FIELD(SYM), PRINT_FIELD(DSO)); |
389 | } | 391 | } |
390 | 392 | ||
391 | printf("\n"); | 393 | printf("\n"); |
@@ -432,14 +434,16 @@ static int cleanup_scripting(void) | |||
432 | return scripting_ops->stop_script(); | 434 | return scripting_ops->stop_script(); |
433 | } | 435 | } |
434 | 436 | ||
435 | static char const *input_name = "perf.data"; | 437 | static const char *input_name; |
436 | 438 | ||
437 | static int process_sample_event(union perf_event *event, | 439 | static int process_sample_event(struct perf_tool *tool __used, |
440 | union perf_event *event, | ||
438 | struct perf_sample *sample, | 441 | struct perf_sample *sample, |
439 | struct perf_evsel *evsel, | 442 | struct perf_evsel *evsel, |
440 | struct perf_session *session) | 443 | struct machine *machine) |
441 | { | 444 | { |
442 | struct thread *thread = perf_session__findnew(session, event->ip.pid); | 445 | struct addr_location al; |
446 | struct thread *thread = machine__findnew_thread(machine, event->ip.tid); | ||
443 | 447 | ||
444 | if (thread == NULL) { | 448 | if (thread == NULL) { |
445 | pr_debug("problem processing %d event, skipping it.\n", | 449 | pr_debug("problem processing %d event, skipping it.\n", |
@@ -458,16 +462,25 @@ static int process_sample_event(union perf_event *event, | |||
458 | return 0; | 462 | return 0; |
459 | } | 463 | } |
460 | 464 | ||
465 | if (perf_event__preprocess_sample(event, machine, &al, sample, 0) < 0) { | ||
466 | pr_err("problem processing %d event, skipping it.\n", | ||
467 | event->header.type); | ||
468 | return -1; | ||
469 | } | ||
470 | |||
471 | if (al.filtered) | ||
472 | return 0; | ||
473 | |||
461 | if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) | 474 | if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) |
462 | return 0; | 475 | return 0; |
463 | 476 | ||
464 | scripting_ops->process_event(event, sample, evsel, session, thread); | 477 | scripting_ops->process_event(event, sample, evsel, machine, thread); |
465 | 478 | ||
466 | session->hists.stats.total_period += sample->period; | 479 | evsel->hists.stats.total_period += sample->period; |
467 | return 0; | 480 | return 0; |
468 | } | 481 | } |
469 | 482 | ||
470 | static struct perf_event_ops event_ops = { | 483 | static struct perf_tool perf_script = { |
471 | .sample = process_sample_event, | 484 | .sample = process_sample_event, |
472 | .mmap = perf_event__process_mmap, | 485 | .mmap = perf_event__process_mmap, |
473 | .comm = perf_event__process_comm, | 486 | .comm = perf_event__process_comm, |
@@ -494,7 +507,7 @@ static int __cmd_script(struct perf_session *session) | |||
494 | 507 | ||
495 | signal(SIGINT, sig_handler); | 508 | signal(SIGINT, sig_handler); |
496 | 509 | ||
497 | ret = perf_session__process_events(session, &event_ops); | 510 | ret = perf_session__process_events(session, &perf_script); |
498 | 511 | ||
499 | if (debug_mode) | 512 | if (debug_mode) |
500 | pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); | 513 | pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); |
@@ -523,12 +536,6 @@ static struct script_spec *script_spec__new(const char *spec, | |||
523 | return s; | 536 | return s; |
524 | } | 537 | } |
525 | 538 | ||
526 | static void script_spec__delete(struct script_spec *s) | ||
527 | { | ||
528 | free(s->spec); | ||
529 | free(s); | ||
530 | } | ||
531 | |||
532 | static void script_spec__add(struct script_spec *s) | 539 | static void script_spec__add(struct script_spec *s) |
533 | { | 540 | { |
534 | list_add_tail(&s->node, &script_specs); | 541 | list_add_tail(&s->node, &script_specs); |
@@ -554,16 +561,11 @@ static struct script_spec *script_spec__findnew(const char *spec, | |||
554 | 561 | ||
555 | s = script_spec__new(spec, ops); | 562 | s = script_spec__new(spec, ops); |
556 | if (!s) | 563 | if (!s) |
557 | goto out_delete_spec; | 564 | return NULL; |
558 | 565 | ||
559 | script_spec__add(s); | 566 | script_spec__add(s); |
560 | 567 | ||
561 | return s; | 568 | return s; |
562 | |||
563 | out_delete_spec: | ||
564 | script_spec__delete(s); | ||
565 | |||
566 | return NULL; | ||
567 | } | 569 | } |
568 | 570 | ||
569 | int script_spec_register(const char *spec, struct scripting_ops *ops) | 571 | int script_spec_register(const char *spec, struct scripting_ops *ops) |
@@ -681,7 +683,8 @@ static int parse_output_fields(const struct option *opt __used, | |||
681 | type = PERF_TYPE_RAW; | 683 | type = PERF_TYPE_RAW; |
682 | else { | 684 | else { |
683 | fprintf(stderr, "Invalid event type in field string.\n"); | 685 | fprintf(stderr, "Invalid event type in field string.\n"); |
684 | return -EINVAL; | 686 | rc = -EINVAL; |
687 | goto out; | ||
685 | } | 688 | } |
686 | 689 | ||
687 | if (output[type].user_set) | 690 | if (output[type].user_set) |
@@ -923,6 +926,24 @@ static int read_script_info(struct script_desc *desc, const char *filename) | |||
923 | return 0; | 926 | return 0; |
924 | } | 927 | } |
925 | 928 | ||
929 | static char *get_script_root(struct dirent *script_dirent, const char *suffix) | ||
930 | { | ||
931 | char *script_root, *str; | ||
932 | |||
933 | script_root = strdup(script_dirent->d_name); | ||
934 | if (!script_root) | ||
935 | return NULL; | ||
936 | |||
937 | str = (char *)ends_with(script_root, suffix); | ||
938 | if (!str) { | ||
939 | free(script_root); | ||
940 | return NULL; | ||
941 | } | ||
942 | |||
943 | *str = '\0'; | ||
944 | return script_root; | ||
945 | } | ||
946 | |||
926 | static int list_available_scripts(const struct option *opt __used, | 947 | static int list_available_scripts(const struct option *opt __used, |
927 | const char *s __used, int unset __used) | 948 | const char *s __used, int unset __used) |
928 | { | 949 | { |
@@ -934,7 +955,6 @@ static int list_available_scripts(const struct option *opt __used, | |||
934 | struct script_desc *desc; | 955 | struct script_desc *desc; |
935 | char first_half[BUFSIZ]; | 956 | char first_half[BUFSIZ]; |
936 | char *script_root; | 957 | char *script_root; |
937 | char *str; | ||
938 | 958 | ||
939 | snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); | 959 | snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); |
940 | 960 | ||
@@ -950,16 +970,14 @@ static int list_available_scripts(const struct option *opt __used, | |||
950 | continue; | 970 | continue; |
951 | 971 | ||
952 | for_each_script(lang_path, lang_dir, script_dirent, script_next) { | 972 | for_each_script(lang_path, lang_dir, script_dirent, script_next) { |
953 | script_root = strdup(script_dirent.d_name); | 973 | script_root = get_script_root(&script_dirent, REPORT_SUFFIX); |
954 | str = (char *)ends_with(script_root, REPORT_SUFFIX); | 974 | if (script_root) { |
955 | if (str) { | ||
956 | *str = '\0'; | ||
957 | desc = script_desc__findnew(script_root); | 975 | desc = script_desc__findnew(script_root); |
958 | snprintf(script_path, MAXPATHLEN, "%s/%s", | 976 | snprintf(script_path, MAXPATHLEN, "%s/%s", |
959 | lang_path, script_dirent.d_name); | 977 | lang_path, script_dirent.d_name); |
960 | read_script_info(desc, script_path); | 978 | read_script_info(desc, script_path); |
979 | free(script_root); | ||
961 | } | 980 | } |
962 | free(script_root); | ||
963 | } | 981 | } |
964 | } | 982 | } |
965 | 983 | ||
@@ -981,8 +999,7 @@ static char *get_script_path(const char *script_root, const char *suffix) | |||
981 | char script_path[MAXPATHLEN]; | 999 | char script_path[MAXPATHLEN]; |
982 | DIR *scripts_dir, *lang_dir; | 1000 | DIR *scripts_dir, *lang_dir; |
983 | char lang_path[MAXPATHLEN]; | 1001 | char lang_path[MAXPATHLEN]; |
984 | char *str, *__script_root; | 1002 | char *__script_root; |
985 | char *path = NULL; | ||
986 | 1003 | ||
987 | snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); | 1004 | snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); |
988 | 1005 | ||
@@ -998,23 +1015,18 @@ static char *get_script_path(const char *script_root, const char *suffix) | |||
998 | continue; | 1015 | continue; |
999 | 1016 | ||
1000 | for_each_script(lang_path, lang_dir, script_dirent, script_next) { | 1017 | for_each_script(lang_path, lang_dir, script_dirent, script_next) { |
1001 | __script_root = strdup(script_dirent.d_name); | 1018 | __script_root = get_script_root(&script_dirent, suffix); |
1002 | str = (char *)ends_with(__script_root, suffix); | 1019 | if (__script_root && !strcmp(script_root, __script_root)) { |
1003 | if (str) { | 1020 | free(__script_root); |
1004 | *str = '\0'; | ||
1005 | if (strcmp(__script_root, script_root)) | ||
1006 | continue; | ||
1007 | snprintf(script_path, MAXPATHLEN, "%s/%s", | 1021 | snprintf(script_path, MAXPATHLEN, "%s/%s", |
1008 | lang_path, script_dirent.d_name); | 1022 | lang_path, script_dirent.d_name); |
1009 | path = strdup(script_path); | 1023 | return strdup(script_path); |
1010 | free(__script_root); | ||
1011 | break; | ||
1012 | } | 1024 | } |
1013 | free(__script_root); | 1025 | free(__script_root); |
1014 | } | 1026 | } |
1015 | } | 1027 | } |
1016 | 1028 | ||
1017 | return path; | 1029 | return NULL; |
1018 | } | 1030 | } |
1019 | 1031 | ||
1020 | static bool is_top_script(const char *script_path) | 1032 | static bool is_top_script(const char *script_path) |
@@ -1083,7 +1095,11 @@ static const struct option options[] = { | |||
1083 | OPT_CALLBACK('f', "fields", NULL, "str", | 1095 | OPT_CALLBACK('f', "fields", NULL, "str", |
1084 | "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr", | 1096 | "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr", |
1085 | parse_output_fields), | 1097 | parse_output_fields), |
1086 | OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), | 1098 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
1099 | "system-wide collection from all CPUs"), | ||
1100 | OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), | ||
1101 | OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", | ||
1102 | "only display events for these comms"), | ||
1087 | OPT_BOOLEAN('I', "show-info", &show_full_info, | 1103 | OPT_BOOLEAN('I', "show-info", &show_full_info, |
1088 | "display extended information from perf.data file"), | 1104 | "display extended information from perf.data file"), |
1089 | OPT_END() | 1105 | OPT_END() |
@@ -1110,7 +1126,6 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) | |||
1110 | struct perf_session *session; | 1126 | struct perf_session *session; |
1111 | char *script_path = NULL; | 1127 | char *script_path = NULL; |
1112 | const char **__argv; | 1128 | const char **__argv; |
1113 | bool system_wide; | ||
1114 | int i, j, err; | 1129 | int i, j, err; |
1115 | 1130 | ||
1116 | setup_scripting(); | 1131 | setup_scripting(); |
@@ -1178,15 +1193,17 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) | |||
1178 | } | 1193 | } |
1179 | 1194 | ||
1180 | if (!pid) { | 1195 | if (!pid) { |
1181 | system_wide = true; | ||
1182 | j = 0; | 1196 | j = 0; |
1183 | 1197 | ||
1184 | dup2(live_pipe[1], 1); | 1198 | dup2(live_pipe[1], 1); |
1185 | close(live_pipe[0]); | 1199 | close(live_pipe[0]); |
1186 | 1200 | ||
1187 | if (!is_top_script(argv[0])) | 1201 | if (is_top_script(argv[0])) { |
1202 | system_wide = true; | ||
1203 | } else if (!system_wide) { | ||
1188 | system_wide = !have_cmd(argc - rep_args, | 1204 | system_wide = !have_cmd(argc - rep_args, |
1189 | &argv[rep_args]); | 1205 | &argv[rep_args]); |
1206 | } | ||
1190 | 1207 | ||
1191 | __argv = malloc((argc + 6) * sizeof(const char *)); | 1208 | __argv = malloc((argc + 6) * sizeof(const char *)); |
1192 | if (!__argv) | 1209 | if (!__argv) |
@@ -1234,10 +1251,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) | |||
1234 | script_path = rep_script_path; | 1251 | script_path = rep_script_path; |
1235 | 1252 | ||
1236 | if (script_path) { | 1253 | if (script_path) { |
1237 | system_wide = false; | ||
1238 | j = 0; | 1254 | j = 0; |
1239 | 1255 | ||
1240 | if (rec_script_path) | 1256 | if (!rec_script_path) |
1257 | system_wide = false; | ||
1258 | else if (!system_wide) | ||
1241 | system_wide = !have_cmd(argc - 1, &argv[1]); | 1259 | system_wide = !have_cmd(argc - 1, &argv[1]); |
1242 | 1260 | ||
1243 | __argv = malloc((argc + 2) * sizeof(const char *)); | 1261 | __argv = malloc((argc + 2) * sizeof(const char *)); |
@@ -1261,7 +1279,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) | |||
1261 | if (!script_name) | 1279 | if (!script_name) |
1262 | setup_pager(); | 1280 | setup_pager(); |
1263 | 1281 | ||
1264 | session = perf_session__new(input_name, O_RDONLY, 0, false, &event_ops); | 1282 | session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_script); |
1265 | if (session == NULL) | 1283 | if (session == NULL) |
1266 | return -ENOMEM; | 1284 | return -ENOMEM; |
1267 | 1285 | ||
@@ -1287,7 +1305,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) | |||
1287 | return -1; | 1305 | return -1; |
1288 | } | 1306 | } |
1289 | 1307 | ||
1290 | input = open(input_name, O_RDONLY); | 1308 | input = open(session->filename, O_RDONLY); /* input_name */ |
1291 | if (input < 0) { | 1309 | if (input < 0) { |
1292 | perror("failed to open file"); | 1310 | perror("failed to open file"); |
1293 | exit(-1); | 1311 | exit(-1); |