diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-12-16 11:55:55 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-12-16 12:30:12 -0500 |
commit | 856e96608a72412d319e498a3a7c557571f811bd (patch) | |
tree | 07e5e92c0778c35d4b9b5e2f9172541ec5002333 /tools/perf/builtin-record.c | |
parent | f4c4176f21533e22bcc292030da72bcfa105f5b8 (diff) |
perf record: Properly synchronize child creation
Remove that ugly usleep and provide proper serialization between
parent and child just like perf-stat does.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: fweisbec@gmail.com
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <20091216165904.908184135@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r-- | tools/perf/builtin-record.c | 109 |
1 files changed, 71 insertions, 38 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 65301c5ca1d..9b7c6d887d5 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -402,7 +402,7 @@ static void atexit_header(void) | |||
402 | perf_header__write(&session->header, output, true); | 402 | perf_header__write(&session->header, output, true); |
403 | } | 403 | } |
404 | 404 | ||
405 | static int __cmd_record(int argc, const char **argv) | 405 | static int __cmd_record(int argc __used, const char **argv) |
406 | { | 406 | { |
407 | int i, counter; | 407 | int i, counter; |
408 | struct stat st; | 408 | struct stat st; |
@@ -410,6 +410,8 @@ static int __cmd_record(int argc, const char **argv) | |||
410 | int flags; | 410 | int flags; |
411 | int err; | 411 | int err; |
412 | unsigned long waking = 0; | 412 | unsigned long waking = 0; |
413 | int child_ready_pipe[2], go_pipe[2]; | ||
414 | char buf; | ||
413 | 415 | ||
414 | page_size = sysconf(_SC_PAGE_SIZE); | 416 | page_size = sysconf(_SC_PAGE_SIZE); |
415 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); | 417 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); |
@@ -420,6 +422,11 @@ static int __cmd_record(int argc, const char **argv) | |||
420 | signal(SIGCHLD, sig_handler); | 422 | signal(SIGCHLD, sig_handler); |
421 | signal(SIGINT, sig_handler); | 423 | signal(SIGINT, sig_handler); |
422 | 424 | ||
425 | if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) { | ||
426 | perror("failed to create pipes"); | ||
427 | exit(-1); | ||
428 | } | ||
429 | |||
423 | if (!stat(output_name, &st) && st.st_size) { | 430 | if (!stat(output_name, &st) && st.st_size) { |
424 | if (!force) { | 431 | if (!force) { |
425 | if (!append_file) { | 432 | if (!append_file) { |
@@ -476,19 +483,65 @@ static int __cmd_record(int argc, const char **argv) | |||
476 | 483 | ||
477 | atexit(atexit_header); | 484 | atexit(atexit_header); |
478 | 485 | ||
479 | if (!system_wide) { | 486 | if (target_pid == -1) { |
480 | pid = target_pid; | 487 | pid = fork(); |
481 | if (pid == -1) | 488 | if (pid < 0) { |
482 | pid = getpid(); | 489 | perror("failed to fork"); |
490 | exit(-1); | ||
491 | } | ||
483 | 492 | ||
484 | open_counters(profile_cpu, pid); | 493 | if (!pid) { |
485 | } else { | 494 | close(child_ready_pipe[0]); |
486 | if (profile_cpu != -1) { | 495 | close(go_pipe[1]); |
487 | open_counters(profile_cpu, target_pid); | 496 | fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); |
488 | } else { | 497 | |
489 | for (i = 0; i < nr_cpus; i++) | 498 | /* |
490 | open_counters(i, target_pid); | 499 | * Do a dummy execvp to get the PLT entry resolved, |
500 | * so we avoid the resolver overhead on the real | ||
501 | * execvp call. | ||
502 | */ | ||
503 | execvp("", (char **)argv); | ||
504 | |||
505 | /* | ||
506 | * Tell the parent we're ready to go | ||
507 | */ | ||
508 | close(child_ready_pipe[1]); | ||
509 | |||
510 | /* | ||
511 | * Wait until the parent tells us to go. | ||
512 | */ | ||
513 | if (read(go_pipe[0], &buf, 1) == -1) | ||
514 | perror("unable to read pipe"); | ||
515 | |||
516 | execvp(argv[0], (char **)argv); | ||
517 | |||
518 | perror(argv[0]); | ||
519 | exit(-1); | ||
491 | } | 520 | } |
521 | |||
522 | child_pid = pid; | ||
523 | |||
524 | if (!system_wide) | ||
525 | target_pid = pid; | ||
526 | |||
527 | close(child_ready_pipe[1]); | ||
528 | close(go_pipe[0]); | ||
529 | /* | ||
530 | * wait for child to settle | ||
531 | */ | ||
532 | if (read(child_ready_pipe[0], &buf, 1) == -1) { | ||
533 | perror("unable to read pipe"); | ||
534 | exit(-1); | ||
535 | } | ||
536 | close(child_ready_pipe[0]); | ||
537 | } | ||
538 | |||
539 | |||
540 | if (!system_wide || profile_cpu != -1) { | ||
541 | open_counters(profile_cpu, target_pid); | ||
542 | } else { | ||
543 | for (i = 0; i < nr_cpus; i++) | ||
544 | open_counters(i, target_pid); | ||
492 | } | 545 | } |
493 | 546 | ||
494 | if (file_new) { | 547 | if (file_new) { |
@@ -503,31 +556,6 @@ static int __cmd_record(int argc, const char **argv) | |||
503 | else | 556 | else |
504 | event__synthesize_threads(process_synthesized_event, session); | 557 | event__synthesize_threads(process_synthesized_event, session); |
505 | 558 | ||
506 | if (target_pid == -1 && argc) { | ||
507 | pid = fork(); | ||
508 | if (pid < 0) | ||
509 | die("failed to fork"); | ||
510 | |||
511 | if (!pid) { | ||
512 | if (execvp(argv[0], (char **)argv)) { | ||
513 | perror(argv[0]); | ||
514 | exit(-1); | ||
515 | } | ||
516 | } else { | ||
517 | /* | ||
518 | * Wait a bit for the execv'ed child to appear | ||
519 | * and be updated in /proc | ||
520 | * FIXME: Do you know a less heuristical solution? | ||
521 | */ | ||
522 | usleep(1000); | ||
523 | event__synthesize_thread(pid, | ||
524 | process_synthesized_event, | ||
525 | session); | ||
526 | } | ||
527 | |||
528 | child_pid = pid; | ||
529 | } | ||
530 | |||
531 | if (realtime_prio) { | 559 | if (realtime_prio) { |
532 | struct sched_param param; | 560 | struct sched_param param; |
533 | 561 | ||
@@ -538,6 +566,11 @@ static int __cmd_record(int argc, const char **argv) | |||
538 | } | 566 | } |
539 | } | 567 | } |
540 | 568 | ||
569 | /* | ||
570 | * Let the child rip | ||
571 | */ | ||
572 | close(go_pipe[1]); | ||
573 | |||
541 | for (;;) { | 574 | for (;;) { |
542 | int hits = samples; | 575 | int hits = samples; |
543 | 576 | ||
@@ -634,7 +667,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
634 | 667 | ||
635 | argc = parse_options(argc, argv, options, record_usage, | 668 | argc = parse_options(argc, argv, options, record_usage, |
636 | PARSE_OPT_STOP_AT_NON_OPTION); | 669 | PARSE_OPT_STOP_AT_NON_OPTION); |
637 | if (!argc && target_pid == -1 && !system_wide) | 670 | if (!argc && target_pid == -1 && (!system_wide || profile_cpu == -1)) |
638 | usage_with_options(record_usage, options); | 671 | usage_with_options(record_usage, options); |
639 | 672 | ||
640 | symbol__init(); | 673 | symbol__init(); |