diff options
Diffstat (limited to 'tools/perf/builtin-script.c')
| -rw-r--r-- | tools/perf/builtin-script.c | 106 |
1 files changed, 65 insertions, 41 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 8e395a538eb9..1e60ab70b2b1 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
| @@ -28,6 +28,11 @@ static bool system_wide; | |||
| 28 | static const char *cpu_list; | 28 | static const char *cpu_list; |
| 29 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 29 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
| 30 | 30 | ||
| 31 | struct perf_script { | ||
| 32 | struct perf_tool tool; | ||
| 33 | struct perf_session *session; | ||
| 34 | }; | ||
| 35 | |||
| 31 | enum perf_output_field { | 36 | enum perf_output_field { |
| 32 | PERF_OUTPUT_COMM = 1U << 0, | 37 | PERF_OUTPUT_COMM = 1U << 0, |
| 33 | PERF_OUTPUT_TID = 1U << 1, | 38 | PERF_OUTPUT_TID = 1U << 1, |
| @@ -137,10 +142,11 @@ static const char *output_field2str(enum perf_output_field field) | |||
| 137 | 142 | ||
| 138 | #define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x) | 143 | #define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x) |
| 139 | 144 | ||
| 140 | static int perf_event_attr__check_stype(struct perf_event_attr *attr, | 145 | static int perf_evsel__check_stype(struct perf_evsel *evsel, |
| 141 | u64 sample_type, const char *sample_msg, | 146 | u64 sample_type, const char *sample_msg, |
| 142 | enum perf_output_field field) | 147 | enum perf_output_field field) |
| 143 | { | 148 | { |
| 149 | struct perf_event_attr *attr = &evsel->attr; | ||
| 144 | int type = attr->type; | 150 | int type = attr->type; |
| 145 | const char *evname; | 151 | const char *evname; |
| 146 | 152 | ||
| @@ -148,7 +154,7 @@ static int perf_event_attr__check_stype(struct perf_event_attr *attr, | |||
| 148 | return 0; | 154 | return 0; |
| 149 | 155 | ||
| 150 | if (output[type].user_set) { | 156 | if (output[type].user_set) { |
| 151 | evname = __event_name(attr->type, attr->config); | 157 | evname = perf_evsel__name(evsel); |
| 152 | pr_err("Samples for '%s' event do not have %s attribute set. " | 158 | pr_err("Samples for '%s' event do not have %s attribute set. " |
| 153 | "Cannot print '%s' field.\n", | 159 | "Cannot print '%s' field.\n", |
| 154 | evname, sample_msg, output_field2str(field)); | 160 | evname, sample_msg, output_field2str(field)); |
| @@ -157,7 +163,7 @@ static int perf_event_attr__check_stype(struct perf_event_attr *attr, | |||
| 157 | 163 | ||
| 158 | /* user did not ask for it explicitly so remove from the default list */ | 164 | /* user did not ask for it explicitly so remove from the default list */ |
| 159 | output[type].fields &= ~field; | 165 | output[type].fields &= ~field; |
| 160 | evname = __event_name(attr->type, attr->config); | 166 | evname = perf_evsel__name(evsel); |
| 161 | pr_debug("Samples for '%s' event do not have %s attribute set. " | 167 | pr_debug("Samples for '%s' event do not have %s attribute set. " |
| 162 | "Skipping '%s' field.\n", | 168 | "Skipping '%s' field.\n", |
| 163 | evname, sample_msg, output_field2str(field)); | 169 | evname, sample_msg, output_field2str(field)); |
| @@ -175,8 +181,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
| 175 | return -EINVAL; | 181 | return -EINVAL; |
| 176 | 182 | ||
| 177 | if (PRINT_FIELD(IP)) { | 183 | if (PRINT_FIELD(IP)) { |
| 178 | if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP", | 184 | if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP", |
| 179 | PERF_OUTPUT_IP)) | 185 | PERF_OUTPUT_IP)) |
| 180 | return -EINVAL; | 186 | return -EINVAL; |
| 181 | 187 | ||
| 182 | if (!no_callchain && | 188 | if (!no_callchain && |
| @@ -185,8 +191,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
| 185 | } | 191 | } |
| 186 | 192 | ||
| 187 | if (PRINT_FIELD(ADDR) && | 193 | if (PRINT_FIELD(ADDR) && |
| 188 | perf_event_attr__check_stype(attr, PERF_SAMPLE_ADDR, "ADDR", | 194 | perf_evsel__check_stype(evsel, PERF_SAMPLE_ADDR, "ADDR", |
| 189 | PERF_OUTPUT_ADDR)) | 195 | PERF_OUTPUT_ADDR)) |
| 190 | return -EINVAL; | 196 | return -EINVAL; |
| 191 | 197 | ||
| 192 | if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { | 198 | if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { |
| @@ -208,18 +214,18 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
| 208 | } | 214 | } |
| 209 | 215 | ||
| 210 | if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && | 216 | if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && |
| 211 | perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID", | 217 | perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID", |
| 212 | PERF_OUTPUT_TID|PERF_OUTPUT_PID)) | 218 | PERF_OUTPUT_TID|PERF_OUTPUT_PID)) |
| 213 | return -EINVAL; | 219 | return -EINVAL; |
| 214 | 220 | ||
| 215 | if (PRINT_FIELD(TIME) && | 221 | if (PRINT_FIELD(TIME) && |
| 216 | perf_event_attr__check_stype(attr, PERF_SAMPLE_TIME, "TIME", | 222 | perf_evsel__check_stype(evsel, PERF_SAMPLE_TIME, "TIME", |
| 217 | PERF_OUTPUT_TIME)) | 223 | PERF_OUTPUT_TIME)) |
| 218 | return -EINVAL; | 224 | return -EINVAL; |
| 219 | 225 | ||
| 220 | if (PRINT_FIELD(CPU) && | 226 | if (PRINT_FIELD(CPU) && |
| 221 | perf_event_attr__check_stype(attr, PERF_SAMPLE_CPU, "CPU", | 227 | perf_evsel__check_stype(evsel, PERF_SAMPLE_CPU, "CPU", |
| 222 | PERF_OUTPUT_CPU)) | 228 | PERF_OUTPUT_CPU)) |
| 223 | return -EINVAL; | 229 | return -EINVAL; |
| 224 | 230 | ||
| 225 | return 0; | 231 | return 0; |
| @@ -256,11 +262,13 @@ static int perf_session__check_output_opt(struct perf_session *session) | |||
| 256 | return 0; | 262 | return 0; |
| 257 | } | 263 | } |
| 258 | 264 | ||
| 259 | static void print_sample_start(struct perf_sample *sample, | 265 | static void print_sample_start(struct pevent *pevent, |
| 266 | struct perf_sample *sample, | ||
| 260 | struct thread *thread, | 267 | struct thread *thread, |
| 261 | struct perf_event_attr *attr) | 268 | struct perf_evsel *evsel) |
| 262 | { | 269 | { |
| 263 | int type; | 270 | int type; |
| 271 | struct perf_event_attr *attr = &evsel->attr; | ||
| 264 | struct event_format *event; | 272 | struct event_format *event; |
| 265 | const char *evname = NULL; | 273 | const char *evname = NULL; |
| 266 | unsigned long secs; | 274 | unsigned long secs; |
| @@ -300,12 +308,18 @@ static void print_sample_start(struct perf_sample *sample, | |||
| 300 | 308 | ||
| 301 | if (PRINT_FIELD(EVNAME)) { | 309 | if (PRINT_FIELD(EVNAME)) { |
| 302 | if (attr->type == PERF_TYPE_TRACEPOINT) { | 310 | if (attr->type == PERF_TYPE_TRACEPOINT) { |
| 303 | type = trace_parse_common_type(sample->raw_data); | 311 | /* |
| 304 | event = trace_find_event(type); | 312 | * XXX Do we really need this here? |
| 313 | * perf_evlist__set_tracepoint_names should have done | ||
| 314 | * this already | ||
| 315 | */ | ||
| 316 | type = trace_parse_common_type(pevent, | ||
| 317 | sample->raw_data); | ||
| 318 | event = pevent_find_event(pevent, type); | ||
| 305 | if (event) | 319 | if (event) |
| 306 | evname = event->name; | 320 | evname = event->name; |
| 307 | } else | 321 | } else |
| 308 | evname = __event_name(attr->type, attr->config); | 322 | evname = perf_evsel__name(evsel); |
| 309 | 323 | ||
| 310 | printf("%s: ", evname ? evname : "[unknown]"); | 324 | printf("%s: ", evname ? evname : "[unknown]"); |
| 311 | } | 325 | } |
| @@ -387,7 +401,7 @@ static void print_sample_bts(union perf_event *event, | |||
| 387 | printf(" "); | 401 | printf(" "); |
| 388 | else | 402 | else |
| 389 | printf("\n"); | 403 | printf("\n"); |
| 390 | perf_event__print_ip(event, sample, machine, evsel, | 404 | perf_event__print_ip(event, sample, machine, |
| 391 | PRINT_FIELD(SYM), PRINT_FIELD(DSO), | 405 | PRINT_FIELD(SYM), PRINT_FIELD(DSO), |
| 392 | PRINT_FIELD(SYMOFFSET)); | 406 | PRINT_FIELD(SYMOFFSET)); |
| 393 | } | 407 | } |
| @@ -402,6 +416,7 @@ static void print_sample_bts(union perf_event *event, | |||
| 402 | } | 416 | } |
| 403 | 417 | ||
| 404 | static void process_event(union perf_event *event __unused, | 418 | static void process_event(union perf_event *event __unused, |
| 419 | struct pevent *pevent, | ||
| 405 | struct perf_sample *sample, | 420 | struct perf_sample *sample, |
| 406 | struct perf_evsel *evsel, | 421 | struct perf_evsel *evsel, |
| 407 | struct machine *machine, | 422 | struct machine *machine, |
| @@ -412,7 +427,7 @@ static void process_event(union perf_event *event __unused, | |||
| 412 | if (output[attr->type].fields == 0) | 427 | if (output[attr->type].fields == 0) |
| 413 | return; | 428 | return; |
| 414 | 429 | ||
| 415 | print_sample_start(sample, thread, attr); | 430 | print_sample_start(pevent, sample, thread, evsel); |
| 416 | 431 | ||
| 417 | if (is_bts_event(attr)) { | 432 | if (is_bts_event(attr)) { |
| 418 | print_sample_bts(event, sample, evsel, machine, thread); | 433 | print_sample_bts(event, sample, evsel, machine, thread); |
| @@ -420,7 +435,7 @@ static void process_event(union perf_event *event __unused, | |||
| 420 | } | 435 | } |
| 421 | 436 | ||
| 422 | if (PRINT_FIELD(TRACE)) | 437 | if (PRINT_FIELD(TRACE)) |
| 423 | print_trace_event(sample->cpu, sample->raw_data, | 438 | print_trace_event(pevent, sample->cpu, sample->raw_data, |
| 424 | sample->raw_size); | 439 | sample->raw_size); |
| 425 | 440 | ||
| 426 | if (PRINT_FIELD(ADDR)) | 441 | if (PRINT_FIELD(ADDR)) |
| @@ -431,7 +446,7 @@ static void process_event(union perf_event *event __unused, | |||
| 431 | printf(" "); | 446 | printf(" "); |
| 432 | else | 447 | else |
| 433 | printf("\n"); | 448 | printf("\n"); |
| 434 | perf_event__print_ip(event, sample, machine, evsel, | 449 | perf_event__print_ip(event, sample, machine, |
| 435 | PRINT_FIELD(SYM), PRINT_FIELD(DSO), | 450 | PRINT_FIELD(SYM), PRINT_FIELD(DSO), |
| 436 | PRINT_FIELD(SYMOFFSET)); | 451 | PRINT_FIELD(SYMOFFSET)); |
| 437 | } | 452 | } |
| @@ -451,7 +466,8 @@ static int default_stop_script(void) | |||
| 451 | return 0; | 466 | return 0; |
| 452 | } | 467 | } |
| 453 | 468 | ||
| 454 | static int default_generate_script(const char *outfile __unused) | 469 | static int default_generate_script(struct pevent *pevent __unused, |
| 470 | const char *outfile __unused) | ||
| 455 | { | 471 | { |
| 456 | return 0; | 472 | return 0; |
| 457 | } | 473 | } |
| @@ -489,6 +505,7 @@ static int process_sample_event(struct perf_tool *tool __used, | |||
| 489 | struct machine *machine) | 505 | struct machine *machine) |
| 490 | { | 506 | { |
| 491 | struct addr_location al; | 507 | struct addr_location al; |
| 508 | struct perf_script *scr = container_of(tool, struct perf_script, tool); | ||
| 492 | struct thread *thread = machine__findnew_thread(machine, event->ip.tid); | 509 | struct thread *thread = machine__findnew_thread(machine, event->ip.tid); |
| 493 | 510 | ||
| 494 | if (thread == NULL) { | 511 | if (thread == NULL) { |
| @@ -520,24 +537,27 @@ static int process_sample_event(struct perf_tool *tool __used, | |||
| 520 | if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) | 537 | if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) |
| 521 | return 0; | 538 | return 0; |
| 522 | 539 | ||
| 523 | scripting_ops->process_event(event, sample, evsel, machine, thread); | 540 | scripting_ops->process_event(event, scr->session->pevent, |
| 541 | sample, evsel, machine, thread); | ||
| 524 | 542 | ||
| 525 | evsel->hists.stats.total_period += sample->period; | 543 | evsel->hists.stats.total_period += sample->period; |
| 526 | return 0; | 544 | return 0; |
| 527 | } | 545 | } |
| 528 | 546 | ||
| 529 | static struct perf_tool perf_script = { | 547 | static struct perf_script perf_script = { |
| 530 | .sample = process_sample_event, | 548 | .tool = { |
| 531 | .mmap = perf_event__process_mmap, | 549 | .sample = process_sample_event, |
| 532 | .comm = perf_event__process_comm, | 550 | .mmap = perf_event__process_mmap, |
| 533 | .exit = perf_event__process_task, | 551 | .comm = perf_event__process_comm, |
| 534 | .fork = perf_event__process_task, | 552 | .exit = perf_event__process_task, |
| 535 | .attr = perf_event__process_attr, | 553 | .fork = perf_event__process_task, |
| 536 | .event_type = perf_event__process_event_type, | 554 | .attr = perf_event__process_attr, |
| 537 | .tracing_data = perf_event__process_tracing_data, | 555 | .event_type = perf_event__process_event_type, |
| 538 | .build_id = perf_event__process_build_id, | 556 | .tracing_data = perf_event__process_tracing_data, |
| 539 | .ordered_samples = true, | 557 | .build_id = perf_event__process_build_id, |
| 540 | .ordering_requires_timestamps = true, | 558 | .ordered_samples = true, |
| 559 | .ordering_requires_timestamps = true, | ||
| 560 | }, | ||
| 541 | }; | 561 | }; |
| 542 | 562 | ||
| 543 | extern volatile int session_done; | 563 | extern volatile int session_done; |
| @@ -553,7 +573,7 @@ static int __cmd_script(struct perf_session *session) | |||
| 553 | 573 | ||
| 554 | signal(SIGINT, sig_handler); | 574 | signal(SIGINT, sig_handler); |
| 555 | 575 | ||
| 556 | ret = perf_session__process_events(session, &perf_script); | 576 | ret = perf_session__process_events(session, &perf_script.tool); |
| 557 | 577 | ||
| 558 | if (debug_mode) | 578 | if (debug_mode) |
| 559 | pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); | 579 | pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); |
| @@ -1335,10 +1355,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) | |||
| 1335 | if (!script_name) | 1355 | if (!script_name) |
| 1336 | setup_pager(); | 1356 | setup_pager(); |
| 1337 | 1357 | ||
| 1338 | session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_script); | 1358 | session = perf_session__new(input_name, O_RDONLY, 0, false, |
| 1359 | &perf_script.tool); | ||
| 1339 | if (session == NULL) | 1360 | if (session == NULL) |
| 1340 | return -ENOMEM; | 1361 | return -ENOMEM; |
| 1341 | 1362 | ||
| 1363 | perf_script.session = session; | ||
| 1364 | |||
| 1342 | if (cpu_list) { | 1365 | if (cpu_list) { |
| 1343 | if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap)) | 1366 | if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap)) |
| 1344 | return -1; | 1367 | return -1; |
| @@ -1384,7 +1407,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) | |||
| 1384 | return -1; | 1407 | return -1; |
| 1385 | } | 1408 | } |
| 1386 | 1409 | ||
| 1387 | err = scripting_ops->generate_script("perf-script"); | 1410 | err = scripting_ops->generate_script(session->pevent, |
| 1411 | "perf-script"); | ||
| 1388 | goto out; | 1412 | goto out; |
| 1389 | } | 1413 | } |
| 1390 | 1414 | ||
