aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/builtin-record.c81
-rw-r--r--tools/perf/perf.h1
-rw-r--r--tools/perf/util/evlist.c96
-rw-r--r--tools/perf/util/evlist.h10
4 files changed, 120 insertions, 68 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index c3ac5415c097..4799195ed246 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -47,11 +47,9 @@ static struct perf_record_opts record_opts = {
47static unsigned int page_size; 47static unsigned int page_size;
48static unsigned int mmap_pages = UINT_MAX; 48static unsigned int mmap_pages = UINT_MAX;
49static int output; 49static int output;
50static int pipe_output = 0;
51static const char *output_name = NULL; 50static const char *output_name = NULL;
52static bool group = false; 51static bool group = false;
53static int realtime_prio = 0; 52static int realtime_prio = 0;
54static pid_t child_pid = -1;
55static enum write_mode_t write_mode = WRITE_FORCE; 53static enum write_mode_t write_mode = WRITE_FORCE;
56static bool no_buildid = false; 54static bool no_buildid = false;
57static bool no_buildid_cache = false; 55static bool no_buildid_cache = false;
@@ -144,9 +142,9 @@ static void sig_atexit(void)
144{ 142{
145 int status; 143 int status;
146 144
147 if (child_pid > 0) { 145 if (evsel_list->workload.pid > 0) {
148 if (!child_finished) 146 if (!child_finished)
149 kill(child_pid, SIGTERM); 147 kill(evsel_list->workload.pid, SIGTERM);
150 148
151 wait(&status); 149 wait(&status);
152 if (WIFSIGNALED(status)) 150 if (WIFSIGNALED(status))
@@ -304,7 +302,7 @@ static int process_buildids(void)
304 302
305static void atexit_header(void) 303static void atexit_header(void)
306{ 304{
307 if (!pipe_output) { 305 if (!record_opts.pipe_output) {
308 session->header.data_size += bytes_written; 306 session->header.data_size += bytes_written;
309 307
310 if (!no_buildid) 308 if (!no_buildid)
@@ -377,9 +375,7 @@ static int __cmd_record(int argc, const char **argv)
377 int flags; 375 int flags;
378 int err; 376 int err;
379 unsigned long waking = 0; 377 unsigned long waking = 0;
380 int child_ready_pipe[2], go_pipe[2];
381 const bool forks = argc > 0; 378 const bool forks = argc > 0;
382 char buf;
383 struct machine *machine; 379 struct machine *machine;
384 380
385 progname = argv[0]; 381 progname = argv[0];
@@ -391,20 +387,15 @@ static int __cmd_record(int argc, const char **argv)
391 signal(SIGINT, sig_handler); 387 signal(SIGINT, sig_handler);
392 signal(SIGUSR1, sig_handler); 388 signal(SIGUSR1, sig_handler);
393 389
394 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
395 perror("failed to create pipes");
396 exit(-1);
397 }
398
399 if (!output_name) { 390 if (!output_name) {
400 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) 391 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
401 pipe_output = true; 392 record_opts.pipe_output = true;
402 else 393 else
403 output_name = "perf.data"; 394 output_name = "perf.data";
404 } 395 }
405 if (output_name) { 396 if (output_name) {
406 if (!strcmp(output_name, "-")) 397 if (!strcmp(output_name, "-"))
407 pipe_output = true; 398 record_opts.pipe_output = true;
408 else if (!stat(output_name, &st) && st.st_size) { 399 else if (!stat(output_name, &st) && st.st_size) {
409 if (write_mode == WRITE_FORCE) { 400 if (write_mode == WRITE_FORCE) {
410 char oldname[PATH_MAX]; 401 char oldname[PATH_MAX];
@@ -424,7 +415,7 @@ static int __cmd_record(int argc, const char **argv)
424 else 415 else
425 flags |= O_TRUNC; 416 flags |= O_TRUNC;
426 417
427 if (pipe_output) 418 if (record_opts.pipe_output)
428 output = STDOUT_FILENO; 419 output = STDOUT_FILENO;
429 else 420 else
430 output = open(output_name, flags, S_IRUSR | S_IWUSR); 421 output = open(output_name, flags, S_IRUSR | S_IWUSR);
@@ -470,57 +461,11 @@ static int __cmd_record(int argc, const char **argv)
470 mmap_pages = (512 * 1024) / page_size; 461 mmap_pages = (512 * 1024) / page_size;
471 462
472 if (forks) { 463 if (forks) {
473 child_pid = fork(); 464 err = perf_evlist__prepare_workload(evsel_list, &record_opts, argv);
474 if (child_pid < 0) { 465 if (err < 0) {
475 perror("failed to fork"); 466 pr_err("Couldn't run the workload!\n");
476 exit(-1); 467 goto out_delete_session;
477 }
478
479 if (!child_pid) {
480 if (pipe_output)
481 dup2(2, 1);
482 close(child_ready_pipe[0]);
483 close(go_pipe[1]);
484 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
485
486 /*
487 * Do a dummy execvp to get the PLT entry resolved,
488 * so we avoid the resolver overhead on the real
489 * execvp call.
490 */
491 execvp("", (char **)argv);
492
493 /*
494 * Tell the parent we're ready to go
495 */
496 close(child_ready_pipe[1]);
497
498 /*
499 * Wait until the parent tells us to go.
500 */
501 if (read(go_pipe[0], &buf, 1) == -1)
502 perror("unable to read pipe");
503
504 execvp(argv[0], (char **)argv);
505
506 perror(argv[0]);
507 kill(getppid(), SIGUSR1);
508 exit(-1);
509 }
510
511 if (!record_opts.system_wide && record_opts.target_tid == -1 && record_opts.target_pid == -1)
512 evsel_list->threads->map[0] = child_pid;
513
514 close(child_ready_pipe[1]);
515 close(go_pipe[0]);
516 /*
517 * wait for child to settle
518 */
519 if (read(child_ready_pipe[0], &buf, 1) == -1) {
520 perror("unable to read pipe");
521 exit(-1);
522 } 468 }
523 close(child_ready_pipe[0]);
524 } 469 }
525 470
526 open_counters(evsel_list); 471 open_counters(evsel_list);
@@ -530,7 +475,7 @@ static int __cmd_record(int argc, const char **argv)
530 */ 475 */
531 atexit(atexit_header); 476 atexit(atexit_header);
532 477
533 if (pipe_output) { 478 if (record_opts.pipe_output) {
534 err = perf_header__write_pipe(output); 479 err = perf_header__write_pipe(output);
535 if (err < 0) 480 if (err < 0)
536 return err; 481 return err;
@@ -543,7 +488,7 @@ static int __cmd_record(int argc, const char **argv)
543 488
544 post_processing_offset = lseek(output, 0, SEEK_CUR); 489 post_processing_offset = lseek(output, 0, SEEK_CUR);
545 490
546 if (pipe_output) { 491 if (record_opts.pipe_output) {
547 err = perf_session__synthesize_attrs(session, 492 err = perf_session__synthesize_attrs(session,
548 process_synthesized_event); 493 process_synthesized_event);
549 if (err < 0) { 494 if (err < 0) {
@@ -629,7 +574,7 @@ static int __cmd_record(int argc, const char **argv)
629 * Let the child rip 574 * Let the child rip
630 */ 575 */
631 if (forks) 576 if (forks)
632 close(go_pipe[1]); 577 perf_evlist__start_workload(evsel_list);
633 578
634 for (;;) { 579 for (;;) {
635 int hits = samples; 580 int hits = samples;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index eb6a13881887..32ee6ca8eabd 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -193,6 +193,7 @@ struct perf_record_opts {
193 bool no_delay; 193 bool no_delay;
194 bool no_inherit; 194 bool no_inherit;
195 bool no_samples; 195 bool no_samples;
196 bool pipe_output;
196 bool raw_samples; 197 bool raw_samples;
197 bool sample_address; 198 bool sample_address;
198 bool sample_time; 199 bool sample_time;
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index b774341e797f..a472247af191 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -13,6 +13,7 @@
13#include "thread_map.h" 13#include "thread_map.h"
14#include "evlist.h" 14#include "evlist.h"
15#include "evsel.h" 15#include "evsel.h"
16#include <unistd.h>
16 17
17#include "parse-events.h" 18#include "parse-events.h"
18 19
@@ -33,6 +34,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
33 INIT_HLIST_HEAD(&evlist->heads[i]); 34 INIT_HLIST_HEAD(&evlist->heads[i]);
34 INIT_LIST_HEAD(&evlist->entries); 35 INIT_LIST_HEAD(&evlist->entries);
35 perf_evlist__set_maps(evlist, cpus, threads); 36 perf_evlist__set_maps(evlist, cpus, threads);
37 evlist->workload.pid = -1;
36} 38}
37 39
38struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, 40struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
@@ -674,3 +676,97 @@ out_err:
674 676
675 return err; 677 return err;
676} 678}
679
680int perf_evlist__prepare_workload(struct perf_evlist *evlist,
681 struct perf_record_opts *opts,
682 const char *argv[])
683{
684 int child_ready_pipe[2], go_pipe[2];
685 char bf;
686
687 if (pipe(child_ready_pipe) < 0) {
688 perror("failed to create 'ready' pipe");
689 return -1;
690 }
691
692 if (pipe(go_pipe) < 0) {
693 perror("failed to create 'go' pipe");
694 goto out_close_ready_pipe;
695 }
696
697 evlist->workload.pid = fork();
698 if (evlist->workload.pid < 0) {
699 perror("failed to fork");
700 goto out_close_pipes;
701 }
702
703 if (!evlist->workload.pid) {
704 if (opts->pipe_output)
705 dup2(2, 1);
706
707 close(child_ready_pipe[0]);
708 close(go_pipe[1]);
709 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
710
711 /*
712 * Do a dummy execvp to get the PLT entry resolved,
713 * so we avoid the resolver overhead on the real
714 * execvp call.
715 */
716 execvp("", (char **)argv);
717
718 /*
719 * Tell the parent we're ready to go
720 */
721 close(child_ready_pipe[1]);
722
723 /*
724 * Wait until the parent tells us to go.
725 */
726 if (read(go_pipe[0], &bf, 1) == -1)
727 perror("unable to read pipe");
728
729 execvp(argv[0], (char **)argv);
730
731 perror(argv[0]);
732 kill(getppid(), SIGUSR1);
733 exit(-1);
734 }
735
736 if (!opts->system_wide && opts->target_tid == -1 && opts->target_pid == -1)
737 evlist->threads->map[0] = evlist->workload.pid;
738
739 close(child_ready_pipe[1]);
740 close(go_pipe[0]);
741 /*
742 * wait for child to settle
743 */
744 if (read(child_ready_pipe[0], &bf, 1) == -1) {
745 perror("unable to read pipe");
746 goto out_close_pipes;
747 }
748
749 evlist->workload.cork_fd = go_pipe[1];
750 close(child_ready_pipe[0]);
751 return 0;
752
753out_close_pipes:
754 close(go_pipe[0]);
755 close(go_pipe[1]);
756out_close_ready_pipe:
757 close(child_ready_pipe[0]);
758 close(child_ready_pipe[1]);
759 return -1;
760}
761
762int perf_evlist__start_workload(struct perf_evlist *evlist)
763{
764 if (evlist->workload.cork_fd > 0) {
765 /*
766 * Remove the cork, let it rip!
767 */
768 return close(evlist->workload.cork_fd);
769 }
770
771 return 0;
772}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 231c06f8286b..07d56b3e6d61 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -6,6 +6,7 @@
6#include "../perf.h" 6#include "../perf.h"
7#include "event.h" 7#include "event.h"
8#include "util.h" 8#include "util.h"
9#include <unistd.h>
9 10
10struct pollfd; 11struct pollfd;
11struct thread_map; 12struct thread_map;
@@ -22,6 +23,10 @@ struct perf_evlist {
22 int nr_fds; 23 int nr_fds;
23 int nr_mmaps; 24 int nr_mmaps;
24 int mmap_len; 25 int mmap_len;
26 struct {
27 int cork_fd;
28 pid_t pid;
29 } workload;
25 bool overwrite; 30 bool overwrite;
26 union perf_event event_copy; 31 union perf_event event_copy;
27 struct perf_mmap *mmap; 32 struct perf_mmap *mmap;
@@ -68,6 +73,11 @@ int perf_evlist__open(struct perf_evlist *evlist, bool group);
68void perf_evlist__config_attrs(struct perf_evlist *evlist, 73void perf_evlist__config_attrs(struct perf_evlist *evlist,
69 struct perf_record_opts *opts); 74 struct perf_record_opts *opts);
70 75
76int perf_evlist__prepare_workload(struct perf_evlist *evlist,
77 struct perf_record_opts *opts,
78 const char *argv[]);
79int perf_evlist__start_workload(struct perf_evlist *evlist);
80
71int perf_evlist__alloc_mmap(struct perf_evlist *evlist); 81int perf_evlist__alloc_mmap(struct perf_evlist *evlist);
72int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); 82int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
73void perf_evlist__munmap(struct perf_evlist *evlist); 83void perf_evlist__munmap(struct perf_evlist *evlist);