diff options
Diffstat (limited to 'tools/perf/builtin-record.c')
| -rw-r--r-- | tools/perf/builtin-record.c | 70 |
1 files changed, 48 insertions, 22 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 8648c6d3003d..404ab3434052 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
| @@ -190,16 +190,30 @@ out: | |||
| 190 | return rc; | 190 | return rc; |
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | static int process_sample_event(struct perf_tool *tool, | ||
| 194 | union perf_event *event, | ||
| 195 | struct perf_sample *sample, | ||
| 196 | struct perf_evsel *evsel, | ||
| 197 | struct machine *machine) | ||
| 198 | { | ||
| 199 | struct record *rec = container_of(tool, struct record, tool); | ||
| 200 | |||
| 201 | rec->samples++; | ||
| 202 | |||
| 203 | return build_id__mark_dso_hit(tool, event, sample, evsel, machine); | ||
| 204 | } | ||
| 205 | |||
| 193 | static int process_buildids(struct record *rec) | 206 | static int process_buildids(struct record *rec) |
| 194 | { | 207 | { |
| 195 | struct perf_data_file *file = &rec->file; | 208 | struct perf_data_file *file = &rec->file; |
| 196 | struct perf_session *session = rec->session; | 209 | struct perf_session *session = rec->session; |
| 197 | u64 start = session->header.data_offset; | ||
| 198 | 210 | ||
| 199 | u64 size = lseek(file->fd, 0, SEEK_CUR); | 211 | u64 size = lseek(perf_data_file__fd(file), 0, SEEK_CUR); |
| 200 | if (size == 0) | 212 | if (size == 0) |
| 201 | return 0; | 213 | return 0; |
| 202 | 214 | ||
| 215 | file->size = size; | ||
| 216 | |||
| 203 | /* | 217 | /* |
| 204 | * During this process, it'll load kernel map and replace the | 218 | * During this process, it'll load kernel map and replace the |
| 205 | * dso->long_name to a real pathname it found. In this case | 219 | * dso->long_name to a real pathname it found. In this case |
| @@ -211,9 +225,7 @@ static int process_buildids(struct record *rec) | |||
| 211 | */ | 225 | */ |
| 212 | symbol_conf.ignore_vmlinux_buildid = true; | 226 | symbol_conf.ignore_vmlinux_buildid = true; |
| 213 | 227 | ||
| 214 | return __perf_session__process_events(session, start, | 228 | return perf_session__process_events(session, &rec->tool); |
| 215 | size - start, | ||
| 216 | size, &build_id__mark_dso_hit_ops); | ||
| 217 | } | 229 | } |
| 218 | 230 | ||
| 219 | static void perf_event__synthesize_guest_os(struct machine *machine, void *data) | 231 | static void perf_event__synthesize_guest_os(struct machine *machine, void *data) |
| @@ -322,6 +334,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
| 322 | struct perf_data_file *file = &rec->file; | 334 | struct perf_data_file *file = &rec->file; |
| 323 | struct perf_session *session; | 335 | struct perf_session *session; |
| 324 | bool disabled = false, draining = false; | 336 | bool disabled = false, draining = false; |
| 337 | int fd; | ||
| 325 | 338 | ||
| 326 | rec->progname = argv[0]; | 339 | rec->progname = argv[0]; |
| 327 | 340 | ||
| @@ -336,6 +349,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
| 336 | return -1; | 349 | return -1; |
| 337 | } | 350 | } |
| 338 | 351 | ||
| 352 | fd = perf_data_file__fd(file); | ||
| 339 | rec->session = session; | 353 | rec->session = session; |
| 340 | 354 | ||
| 341 | record__init_features(rec); | 355 | record__init_features(rec); |
| @@ -360,12 +374,11 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
| 360 | perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); | 374 | perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); |
| 361 | 375 | ||
| 362 | if (file->is_pipe) { | 376 | if (file->is_pipe) { |
| 363 | err = perf_header__write_pipe(file->fd); | 377 | err = perf_header__write_pipe(fd); |
| 364 | if (err < 0) | 378 | if (err < 0) |
| 365 | goto out_child; | 379 | goto out_child; |
| 366 | } else { | 380 | } else { |
| 367 | err = perf_session__write_header(session, rec->evlist, | 381 | err = perf_session__write_header(session, rec->evlist, fd, false); |
| 368 | file->fd, false); | ||
| 369 | if (err < 0) | 382 | if (err < 0) |
| 370 | goto out_child; | 383 | goto out_child; |
| 371 | } | 384 | } |
| @@ -397,7 +410,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
| 397 | * return this more properly and also | 410 | * return this more properly and also |
| 398 | * propagate errors that now are calling die() | 411 | * propagate errors that now are calling die() |
| 399 | */ | 412 | */ |
| 400 | err = perf_event__synthesize_tracing_data(tool, file->fd, rec->evlist, | 413 | err = perf_event__synthesize_tracing_data(tool, fd, rec->evlist, |
| 401 | process_synthesized_event); | 414 | process_synthesized_event); |
| 402 | if (err <= 0) { | 415 | if (err <= 0) { |
| 403 | pr_err("Couldn't record tracing data.\n"); | 416 | pr_err("Couldn't record tracing data.\n"); |
| @@ -504,19 +517,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
| 504 | goto out_child; | 517 | goto out_child; |
| 505 | } | 518 | } |
| 506 | 519 | ||
| 507 | if (!quiet) { | 520 | if (!quiet) |
| 508 | fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); | 521 | fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); |
| 509 | 522 | ||
| 510 | /* | ||
| 511 | * Approximate RIP event size: 24 bytes. | ||
| 512 | */ | ||
| 513 | fprintf(stderr, | ||
| 514 | "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", | ||
| 515 | (double)rec->bytes_written / 1024.0 / 1024.0, | ||
| 516 | file->path, | ||
| 517 | rec->bytes_written / 24); | ||
| 518 | } | ||
| 519 | |||
| 520 | out_child: | 523 | out_child: |
| 521 | if (forks) { | 524 | if (forks) { |
| 522 | int exit_status; | 525 | int exit_status; |
| @@ -535,13 +538,29 @@ out_child: | |||
| 535 | } else | 538 | } else |
| 536 | status = err; | 539 | status = err; |
| 537 | 540 | ||
| 541 | /* this will be recalculated during process_buildids() */ | ||
| 542 | rec->samples = 0; | ||
| 543 | |||
| 538 | if (!err && !file->is_pipe) { | 544 | if (!err && !file->is_pipe) { |
| 539 | rec->session->header.data_size += rec->bytes_written; | 545 | rec->session->header.data_size += rec->bytes_written; |
| 540 | 546 | ||
| 541 | if (!rec->no_buildid) | 547 | if (!rec->no_buildid) |
| 542 | process_buildids(rec); | 548 | process_buildids(rec); |
| 543 | perf_session__write_header(rec->session, rec->evlist, | 549 | perf_session__write_header(rec->session, rec->evlist, fd, true); |
| 544 | file->fd, true); | 550 | } |
| 551 | |||
| 552 | if (!err && !quiet) { | ||
| 553 | char samples[128]; | ||
| 554 | |||
| 555 | if (rec->samples) | ||
| 556 | scnprintf(samples, sizeof(samples), | ||
| 557 | " (%" PRIu64 " samples)", rec->samples); | ||
| 558 | else | ||
| 559 | samples[0] = '\0'; | ||
| 560 | |||
| 561 | fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s ]\n", | ||
| 562 | perf_data_file__size(file) / 1024.0 / 1024.0, | ||
| 563 | file->path, samples); | ||
| 545 | } | 564 | } |
| 546 | 565 | ||
| 547 | out_delete_session: | 566 | out_delete_session: |
| @@ -720,6 +739,13 @@ static struct record record = { | |||
| 720 | .default_per_cpu = true, | 739 | .default_per_cpu = true, |
| 721 | }, | 740 | }, |
| 722 | }, | 741 | }, |
| 742 | .tool = { | ||
| 743 | .sample = process_sample_event, | ||
| 744 | .fork = perf_event__process_fork, | ||
| 745 | .comm = perf_event__process_comm, | ||
| 746 | .mmap = perf_event__process_mmap, | ||
| 747 | .mmap2 = perf_event__process_mmap2, | ||
| 748 | }, | ||
| 723 | }; | 749 | }; |
| 724 | 750 | ||
| 725 | #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: " | 751 | #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: " |
