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 | ||
