From: Jiri Olsa <jolsa@kernel.org>
To: Ingo Molnar <mingo@kernel.org>
Cc: linux-kernel@vger.kernel.org, Namhyung Kim <namhyung@kernel.org>,
Jiri Olsa <jolsa@kernel.org>
Subject: [PATCH 4/6] perf record: Propagate exit status of a command line workload
Date: Mon, 12 May 2014 11:27:11 +0200 [thread overview]
Message-ID: <1399886833-15472-5-git-send-email-jolsa@kernel.org> (raw)
In-Reply-To: <1399886833-15472-1-git-send-email-jolsa@kernel.org>
From: Namhyung Kim <namhyung@kernel.org>
Currently perf record doesn't propagate the exit status of a workload
given by the command line. But sometimes it'd useful if it's
propagated so that a monitoring script can handle errors
appropriately.
To do that, it moves most of logic out of the exit handlers and run
them directly in the __cmd_record(). The only thing needs to be done
in the handler is propagating terminating signal so that the shell can
terminate its loop properly when Ctrl-C was pressed. Also it cleaned
up the resource management code in record__exit().
With this change, perf record returns the child exit status in case of
normal termination and send signal to itself when terminated by signal.
Example run of Stephane's case:
$ perf record true && echo yes || echo no
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.013 MB perf.data (~589 samples) ]
yes
$ perf record false && echo yes || echo no
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.013 MB perf.data (~589 samples) ]
no
Jiri's case (error in parent):
$ perf record -m 10G true && echo yes || echo no
rounding mmap pages size to 17179869184 bytes (4194304 pages)
failed to mmap with 12 (Cannot allocate memory)
no
$ ulimit -n 6
$ perf record sleep 1 && echo yes || echo no
failed to create 'go' pipe: Too many open files
Couldn't run the workload!
no
And Peter's case (interrupted by signal):
$ while :; do perf record sleep 1; done
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.014 MB perf.data (~593 samples) ]
Reported-by: Stephane Eranian <eranian@google.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Stephane Eranian <eranian@google.com>
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Acked-by: Ingo Molnar <mingo@kernel.org>
Link: http://lkml.kernel.org/r/1399855645-25815-1-git-send-email-namhyung@kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
tools/perf/builtin-record.c | 127 +++++++++++++++++++++-----------------------
1 file changed, 60 insertions(+), 67 deletions(-)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 8ce62ef..2e0d484 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -147,29 +147,19 @@ static void sig_handler(int sig)
{
if (sig == SIGCHLD)
child_finished = 1;
+ else
+ signr = sig;
done = 1;
- signr = sig;
}
-static void record__sig_exit(int exit_status __maybe_unused, void *arg)
+static void record__sig_exit(void)
{
- struct record *rec = arg;
- int status;
-
- if (rec->evlist->workload.pid > 0) {
- if (!child_finished)
- kill(rec->evlist->workload.pid, SIGTERM);
-
- wait(&status);
- if (WIFSIGNALED(status))
- psignal(WTERMSIG(status), rec->progname);
- }
-
- if (signr == -1 || signr == SIGUSR1)
+ if (signr == -1)
return;
signal(signr, SIG_DFL);
+ raise(signr);
}
static int record__open(struct record *rec)
@@ -243,27 +233,6 @@ static int process_buildids(struct record *rec)
size, &build_id__mark_dso_hit_ops);
}
-static void record__exit(int status, void *arg)
-{
- struct record *rec = arg;
- struct perf_data_file *file = &rec->file;
-
- if (status != 0)
- return;
-
- if (!file->is_pipe) {
- rec->session->header.data_size += rec->bytes_written;
-
- if (!rec->no_buildid)
- process_buildids(rec);
- perf_session__write_header(rec->session, rec->evlist,
- file->fd, true);
- perf_session__delete(rec->session);
- perf_evlist__delete(rec->evlist);
- symbol__exit();
- }
-}
-
static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
{
int err;
@@ -344,18 +313,19 @@ static volatile int workload_exec_errno;
* if the fork fails, since we asked by setting its
* want_signal to true.
*/
-static void workload_exec_failed_signal(int signo, siginfo_t *info,
+static void workload_exec_failed_signal(int signo __maybe_unused,
+ siginfo_t *info,
void *ucontext __maybe_unused)
{
workload_exec_errno = info->si_value.sival_int;
done = 1;
- signr = signo;
child_finished = 1;
}
static int __cmd_record(struct record *rec, int argc, const char **argv)
{
int err;
+ int status = 0;
unsigned long waking = 0;
const bool forks = argc > 0;
struct machine *machine;
@@ -367,7 +337,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
rec->progname = argv[0];
- on_exit(record__sig_exit, rec);
+ atexit(record__sig_exit);
signal(SIGCHLD, sig_handler);
signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler);
@@ -388,32 +358,28 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
workload_exec_failed_signal);
if (err < 0) {
pr_err("Couldn't run the workload!\n");
+ status = err;
goto out_delete_session;
}
}
if (record__open(rec) != 0) {
err = -1;
- goto out_delete_session;
+ goto out_child;
}
if (!rec->evlist->nr_groups)
perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
- /*
- * perf_session__delete(session) will be called at record__exit()
- */
- on_exit(record__exit, rec);
-
if (file->is_pipe) {
err = perf_header__write_pipe(file->fd);
if (err < 0)
- goto out_delete_session;
+ goto out_child;
} else {
err = perf_session__write_header(session, rec->evlist,
file->fd, false);
if (err < 0)
- goto out_delete_session;
+ goto out_child;
}
if (!rec->no_buildid
@@ -421,7 +387,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
pr_err("Couldn't generate buildids. "
"Use --no-buildid to profile anyway.\n");
err = -1;
- goto out_delete_session;
+ goto out_child;
}
machine = &session->machines.host;
@@ -431,7 +397,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
process_synthesized_event);
if (err < 0) {
pr_err("Couldn't synthesize attrs.\n");
- goto out_delete_session;
+ goto out_child;
}
if (have_tracepoints(&rec->evlist->entries)) {
@@ -447,7 +413,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
process_synthesized_event);
if (err <= 0) {
pr_err("Couldn't record tracing data.\n");
- goto out_delete_session;
+ goto out_child;
}
rec->bytes_written += err;
}
@@ -475,7 +441,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
process_synthesized_event, opts->sample_address);
if (err != 0)
- goto out_delete_session;
+ goto out_child;
if (rec->realtime_prio) {
struct sched_param param;
@@ -484,7 +450,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
if (sched_setscheduler(0, SCHED_FIFO, ¶m)) {
pr_err("Could not set realtime priority.\n");
err = -1;
- goto out_delete_session;
+ goto out_child;
}
}
@@ -512,13 +478,15 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
if (record__mmap_read_all(rec) < 0) {
err = -1;
- goto out_delete_session;
+ goto out_child;
}
if (hits == rec->samples) {
if (done)
break;
err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1);
+ if (err < 0 && errno == EINTR)
+ err = 0;
waking++;
}
@@ -538,28 +506,52 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
pr_err("Workload failed: %s\n", emsg);
err = -1;
- goto out_delete_session;
+ goto out_child;
}
- if (quiet || signr == SIGUSR1)
- return 0;
+ if (!quiet) {
+ fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
- fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
+ /*
+ * Approximate RIP event size: 24 bytes.
+ */
+ fprintf(stderr,
+ "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
+ (double)rec->bytes_written / 1024.0 / 1024.0,
+ file->path,
+ rec->bytes_written / 24);
+ }
- /*
- * Approximate RIP event size: 24 bytes.
- */
- fprintf(stderr,
- "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
- (double)rec->bytes_written / 1024.0 / 1024.0,
- file->path,
- rec->bytes_written / 24);
+out_child:
+ if (forks) {
+ int exit_status;
- return 0;
+ if (!child_finished)
+ kill(rec->evlist->workload.pid, SIGTERM);
+
+ wait(&exit_status);
+
+ if (err < 0)
+ status = err;
+ else if (WIFEXITED(exit_status))
+ status = WEXITSTATUS(exit_status);
+ else if (WIFSIGNALED(exit_status))
+ signr = WTERMSIG(exit_status);
+ } else
+ status = err;
+
+ if (!err && !file->is_pipe) {
+ rec->session->header.data_size += rec->bytes_written;
+
+ if (!rec->no_buildid)
+ process_buildids(rec);
+ perf_session__write_header(rec->session, rec->evlist,
+ file->fd, true);
+ }
out_delete_session:
perf_session__delete(session);
- return err;
+ return status;
}
#define BRANCH_OPT(n, m) \
@@ -988,6 +980,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
err = __cmd_record(&record, argc, argv);
out_symbol_exit:
+ perf_evlist__delete(rec->evlist);
symbol__exit();
return err;
}
--
1.8.3.1
next prev parent reply other threads:[~2014-05-12 9:27 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-05-12 9:27 [GIT PULL 0/6] perf/core improvements and fixes Jiri Olsa
2014-05-12 9:27 ` [PATCH 1/6] perf tools: Add missing event for perf sched record Jiri Olsa
2014-05-12 9:27 ` [PATCH 2/6] perf tools: Adapt the TASK_STATE_TO_CHAR_STR to new value in kernel space Jiri Olsa
2014-05-12 9:27 ` [PATCH 3/6] perf tools: Clarify the output of perf sched map Jiri Olsa
2014-05-12 9:27 ` Jiri Olsa [this message]
2014-05-12 9:27 ` [PATCH 5/6] perf tools: Get rid of on_exit() feature test Jiri Olsa
2014-05-12 9:27 ` [PATCH 6/6] perf tools: Use tid for finding thread Jiri Olsa
2014-05-12 15:59 ` [GIT PULL 0/6] perf/core improvements and fixes Ingo Molnar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1399886833-15472-5-git-send-email-jolsa@kernel.org \
--to=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@kernel.org \
--cc=namhyung@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.