diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2014-01-02 13:11:25 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2014-01-13 08:06:21 -0500 |
commit | f33cbe72e6166b97d6fa2400cb00a885b47999d7 (patch) | |
tree | 838b627d593e8ddc2b26db819bda78ec88d00a9c /tools | |
parent | 6af206fd911c825b83dd4efb2534a3a34ce77072 (diff) |
perf evlist: Send the errno in the signal when workload fails
When a tool uses perf_evlist__start_workload and the supplied workload
fails (e.g.: its binary wasn't found), perror was being used to print
the error reason.
This is undesirable, as the caller may be a GUI, when it wants to have
total control of the error reporting process.
So move to using sigaction(SA_SIGINFO) + siginfo_t->sa_value->sival_int
to communicate to the caller the errno and let it print it using the UI
of its choosing.
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-epgcv7kjq8ll2udqfken92pz@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-record.c | 39 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 21 | ||||
-rw-r--r-- | tools/perf/util/evlist.c | 11 |
3 files changed, 60 insertions, 11 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 6ec0cbc2a5d5..f987d385c6f0 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -341,6 +341,22 @@ static void record__init_features(struct record *rec) | |||
341 | perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); | 341 | perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); |
342 | } | 342 | } |
343 | 343 | ||
344 | static volatile int workload_exec_errno; | ||
345 | |||
346 | /* | ||
347 | * perf_evlist__prepare_workload will send a SIGUSR1 | ||
348 | * if the fork fails, since we asked by setting its | ||
349 | * want_signal to true. | ||
350 | */ | ||
351 | static void workload_exec_failed_signal(int signo, siginfo_t *info, | ||
352 | void *ucontext __maybe_unused) | ||
353 | { | ||
354 | workload_exec_errno = info->si_value.sival_int; | ||
355 | done = 1; | ||
356 | signr = signo; | ||
357 | child_finished = 1; | ||
358 | } | ||
359 | |||
344 | static int __cmd_record(struct record *rec, int argc, const char **argv) | 360 | static int __cmd_record(struct record *rec, int argc, const char **argv) |
345 | { | 361 | { |
346 | int err; | 362 | int err; |
@@ -359,7 +375,6 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
359 | on_exit(record__sig_exit, rec); | 375 | on_exit(record__sig_exit, rec); |
360 | signal(SIGCHLD, sig_handler); | 376 | signal(SIGCHLD, sig_handler); |
361 | signal(SIGINT, sig_handler); | 377 | signal(SIGINT, sig_handler); |
362 | signal(SIGUSR1, sig_handler); | ||
363 | signal(SIGTERM, sig_handler); | 378 | signal(SIGTERM, sig_handler); |
364 | 379 | ||
365 | session = perf_session__new(file, false, NULL); | 380 | session = perf_session__new(file, false, NULL); |
@@ -492,8 +507,20 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
492 | /* | 507 | /* |
493 | * Let the child rip | 508 | * Let the child rip |
494 | */ | 509 | */ |
495 | if (forks) | 510 | if (forks) { |
511 | struct sigaction act = { | ||
512 | .sa_flags = SA_SIGINFO, | ||
513 | .sa_sigaction = workload_exec_failed_signal, | ||
514 | }; | ||
515 | /* | ||
516 | * perf_evlist__prepare_workload will, after we call | ||
517 | * perf_evlist__start_Workload, send a SIGUSR1 if the exec call | ||
518 | * fails, that we will catch in workload_signal to flip | ||
519 | * workload_exec_errno. | ||
520 | */ | ||
521 | sigaction(SIGUSR1, &act, NULL); | ||
496 | perf_evlist__start_workload(evsel_list); | 522 | perf_evlist__start_workload(evsel_list); |
523 | } | ||
497 | 524 | ||
498 | for (;;) { | 525 | for (;;) { |
499 | int hits = rec->samples; | 526 | int hits = rec->samples; |
@@ -521,6 +548,14 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
521 | } | 548 | } |
522 | } | 549 | } |
523 | 550 | ||
551 | if (forks && workload_exec_errno) { | ||
552 | char msg[512]; | ||
553 | const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); | ||
554 | pr_err("Workload failed: %s\n", emsg); | ||
555 | err = -1; | ||
556 | goto out_delete_session; | ||
557 | } | ||
558 | |||
524 | if (quiet || signr == SIGUSR1) | 559 | if (quiet || signr == SIGUSR1) |
525 | return 0; | 560 | return 0; |
526 | 561 | ||
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 1c76c7a66f78..9d0d52d55ee6 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -58,6 +58,7 @@ | |||
58 | #include "util/thread.h" | 58 | #include "util/thread.h" |
59 | #include "util/thread_map.h" | 59 | #include "util/thread_map.h" |
60 | 60 | ||
61 | #include <signal.h> | ||
61 | #include <stdlib.h> | 62 | #include <stdlib.h> |
62 | #include <sys/prctl.h> | 63 | #include <sys/prctl.h> |
63 | #include <locale.h> | 64 | #include <locale.h> |
@@ -509,16 +510,17 @@ static void handle_initial_delay(void) | |||
509 | } | 510 | } |
510 | } | 511 | } |
511 | 512 | ||
512 | static volatile bool workload_exec_failed; | 513 | static volatile int workload_exec_errno; |
513 | 514 | ||
514 | /* | 515 | /* |
515 | * perf_evlist__prepare_workload will send a SIGUSR1 | 516 | * perf_evlist__prepare_workload will send a SIGUSR1 |
516 | * if the fork fails, since we asked by setting its | 517 | * if the fork fails, since we asked by setting its |
517 | * want_signal to true. | 518 | * want_signal to true. |
518 | */ | 519 | */ |
519 | static void workload_exec_failed_signal(int signo __maybe_unused) | 520 | static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *info, |
521 | void *ucontext __maybe_unused) | ||
520 | { | 522 | { |
521 | workload_exec_failed = true; | 523 | workload_exec_errno = info->si_value.sival_int; |
522 | } | 524 | } |
523 | 525 | ||
524 | static int __run_perf_stat(int argc, const char **argv) | 526 | static int __run_perf_stat(int argc, const char **argv) |
@@ -596,13 +598,17 @@ static int __run_perf_stat(int argc, const char **argv) | |||
596 | clock_gettime(CLOCK_MONOTONIC, &ref_time); | 598 | clock_gettime(CLOCK_MONOTONIC, &ref_time); |
597 | 599 | ||
598 | if (forks) { | 600 | if (forks) { |
601 | struct sigaction act = { | ||
602 | .sa_flags = SA_SIGINFO, | ||
603 | .sa_sigaction = workload_exec_failed_signal, | ||
604 | }; | ||
599 | /* | 605 | /* |
600 | * perf_evlist__prepare_workload will, after we call | 606 | * perf_evlist__prepare_workload will, after we call |
601 | * perf_evlist__start_Workload, send a SIGUSR1 if the exec call | 607 | * perf_evlist__start_Workload, send a SIGUSR1 if the exec call |
602 | * fails, that we will catch in workload_signal to flip | 608 | * fails, that we will catch in workload_signal to flip |
603 | * workload_exec_failed. | 609 | * workload_exec_errno. |
604 | */ | 610 | */ |
605 | signal(SIGUSR1, workload_exec_failed_signal); | 611 | sigaction(SIGUSR1, &act, NULL); |
606 | 612 | ||
607 | perf_evlist__start_workload(evsel_list); | 613 | perf_evlist__start_workload(evsel_list); |
608 | handle_initial_delay(); | 614 | handle_initial_delay(); |
@@ -615,8 +621,11 @@ static int __run_perf_stat(int argc, const char **argv) | |||
615 | } | 621 | } |
616 | wait(&status); | 622 | wait(&status); |
617 | 623 | ||
618 | if (workload_exec_failed) | 624 | if (workload_exec_errno) { |
625 | const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); | ||
626 | pr_err("Workload failed: %s\n", emsg); | ||
619 | return -1; | 627 | return -1; |
628 | } | ||
620 | 629 | ||
621 | if (WIFSIGNALED(status)) | 630 | if (WIFSIGNALED(status)) |
622 | psignal(WTERMSIG(status), argv[0]); | 631 | psignal(WTERMSIG(status), argv[0]); |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index b08a7ecdcea1..4a30c87d24ec 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -1073,9 +1073,14 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar | |||
1073 | 1073 | ||
1074 | execvp(argv[0], (char **)argv); | 1074 | execvp(argv[0], (char **)argv); |
1075 | 1075 | ||
1076 | perror(argv[0]); | 1076 | if (want_signal) { |
1077 | if (want_signal) | 1077 | union sigval val; |
1078 | kill(getppid(), SIGUSR1); | 1078 | |
1079 | val.sival_int = errno; | ||
1080 | if (sigqueue(getppid(), SIGUSR1, val)) | ||
1081 | perror(argv[0]); | ||
1082 | } else | ||
1083 | perror(argv[0]); | ||
1079 | exit(-1); | 1084 | exit(-1); |
1080 | } | 1085 | } |
1081 | 1086 | ||