Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2dd6d8a1 authored by Adrian Hunter's avatar Adrian Hunter Committed by Arnaldo Carvalho de Melo
Browse files

perf record: Add AUX area tracing Snapshot Mode support



Add a new option and support for Instruction Tracing Snapshot Mode.
When the new option is selected, no AUX area tracing data is captured
until a signal (SIGUSR2) is received.

Signed-off-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Acked-by: default avatarJiri Olsa <jolsa@kernel.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1430404667-10593-10-git-send-email-adrian.hunter@intel.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent d20031bb
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -259,6 +259,13 @@ records. See clock_gettime(). In particular CLOCK_MONOTONIC and
CLOCK_MONOTONIC_RAW are supported, some events might also allow
CLOCK_BOOTTIME, CLOCK_REALTIME and CLOCK_TAI.

-S::
--snapshot::
Select AUX area tracing Snapshot Mode. This option is valid only with an
AUX area tracing event. Optionally the number of bytes to capture per
snapshot can be specified. In Snapshot Mode, trace data is captured only when
signal SIGUSR2 is received.

SEE ALSO
--------
linkperf:perf-stat[1], linkperf:perf-list[1]
+123 −21
Original line number Diff line number Diff line
@@ -112,6 +112,32 @@ static int record__mmap_read(struct record *rec, int idx)
	return rc;
}

static volatile int done;
static volatile int signr = -1;
static volatile int child_finished;
static volatile int auxtrace_snapshot_enabled;
static volatile int auxtrace_snapshot_err;
static volatile int auxtrace_record__snapshot_started;

static void sig_handler(int sig)
{
	if (sig == SIGCHLD)
		child_finished = 1;
	else
		signr = sig;

	done = 1;
}

static void record__sig_exit(void)
{
	if (signr == -1)
		return;

	signal(signr, SIG_DFL);
	raise(signr);
}

#ifdef HAVE_AUXTRACE_SUPPORT

static int record__process_auxtrace(struct perf_tool *tool,
@@ -167,6 +193,56 @@ static int record__auxtrace_mmap_read(struct record *rec,
	return 0;
}

static int record__auxtrace_mmap_read_snapshot(struct record *rec,
					       struct auxtrace_mmap *mm)
{
	int ret;

	ret = auxtrace_mmap__read_snapshot(mm, rec->itr, &rec->tool,
					   record__process_auxtrace,
					   rec->opts.auxtrace_snapshot_size);
	if (ret < 0)
		return ret;

	if (ret)
		rec->samples++;

	return 0;
}

static int record__auxtrace_read_snapshot_all(struct record *rec)
{
	int i;
	int rc = 0;

	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
		struct auxtrace_mmap *mm =
				&rec->evlist->mmap[i].auxtrace_mmap;

		if (!mm->base)
			continue;

		if (record__auxtrace_mmap_read_snapshot(rec, mm) != 0) {
			rc = -1;
			goto out;
		}
	}
out:
	return rc;
}

static void record__read_auxtrace_snapshot(struct record *rec)
{
	pr_debug("Recording AUX area tracing snapshot\n");
	if (record__auxtrace_read_snapshot_all(rec) < 0) {
		auxtrace_snapshot_err = -1;
	} else {
		auxtrace_snapshot_err = auxtrace_record__snapshot_finish(rec->itr);
		if (!auxtrace_snapshot_err)
			auxtrace_snapshot_enabled = 1;
	}
}

#else

static inline
@@ -176,31 +252,19 @@ int record__auxtrace_mmap_read(struct record *rec __maybe_unused,
	return 0;
}

#endif

static volatile int done = 0;
static volatile int signr = -1;
static volatile int child_finished = 0;

static void sig_handler(int sig)
static inline
void record__read_auxtrace_snapshot(struct record *rec __maybe_unused)
{
	if (sig == SIGCHLD)
		child_finished = 1;
	else
		signr = sig;

	done = 1;
}

static void record__sig_exit(void)
static inline
int auxtrace_record__snapshot_start(struct auxtrace_record *itr __maybe_unused)
{
	if (signr == -1)
		return;

	signal(signr, SIG_DFL);
	raise(signr);
	return 0;
}

#endif

static int record__open(struct record *rec)
{
	char msg[512];
@@ -238,7 +302,8 @@ static int record__open(struct record *rec)
	}

	if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false,
				 opts->auxtrace_mmap_pages, false) < 0) {
				 opts->auxtrace_mmap_pages,
				 opts->auxtrace_snapshot_mode) < 0) {
		if (errno == EPERM) {
			pr_err("Permission error mapping pages.\n"
			       "Consider increasing "
@@ -349,7 +414,7 @@ static int record__mmap_read_all(struct record *rec)
			}
		}

		if (mm->base &&
		if (mm->base && !rec->opts.auxtrace_snapshot_mode &&
		    record__auxtrace_mmap_read(rec, mm) != 0) {
			rc = -1;
			goto out;
@@ -404,6 +469,8 @@ static void workload_exec_failed_signal(int signo __maybe_unused,
	child_finished = 1;
}

static void snapshot_sig_handler(int sig);

static int __cmd_record(struct record *rec, int argc, const char **argv)
{
	int err;
@@ -424,6 +491,10 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
	signal(SIGCHLD, sig_handler);
	signal(SIGINT, sig_handler);
	signal(SIGTERM, sig_handler);
	if (rec->opts.auxtrace_snapshot_mode)
		signal(SIGUSR2, snapshot_sig_handler);
	else
		signal(SIGUSR2, SIG_IGN);

	session = perf_session__new(file, false, tool);
	if (session == NULL) {
@@ -563,13 +634,26 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
		perf_evlist__enable(rec->evlist);
	}

	auxtrace_snapshot_enabled = 1;
	for (;;) {
		int hits = rec->samples;

		if (record__mmap_read_all(rec) < 0) {
			auxtrace_snapshot_enabled = 0;
			err = -1;
			goto out_child;
		}

		if (auxtrace_record__snapshot_started) {
			auxtrace_record__snapshot_started = 0;
			if (!auxtrace_snapshot_err)
				record__read_auxtrace_snapshot(rec);
			if (auxtrace_snapshot_err) {
				pr_err("AUX area tracing snapshot failed\n");
				err = -1;
				goto out_child;
			}
		}

		if (hits == rec->samples) {
			if (done || draining)
@@ -593,10 +677,12 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
		 * disable events in this case.
		 */
		if (done && !disabled && !target__none(&opts->target)) {
			auxtrace_snapshot_enabled = 0;
			perf_evlist__disable(rec->evlist);
			disabled = true;
		}
	}
	auxtrace_snapshot_enabled = 0;

	if (forks && workload_exec_errno) {
		char msg[STRERR_BUFSIZE];
@@ -1068,6 +1154,8 @@ struct option __record_options[] = {
	OPT_CALLBACK('k', "clockid", &record.opts,
	"clockid", "clockid to use for events, see clock_gettime()",
	parse_clockid),
	OPT_STRING_OPTARG('S', "snapshot", &record.opts.auxtrace_snapshot_opts,
			  "opts", "AUX area tracing Snapshot Mode", ""),
	OPT_END()
};

@@ -1102,6 +1190,11 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
			return err;
	}

	err = auxtrace_parse_snapshot_options(rec->itr, &rec->opts,
					      rec->opts.auxtrace_snapshot_opts);
	if (err)
		return err;

	err = -ENOMEM;

	symbol__init(NULL);
@@ -1165,3 +1258,12 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
	auxtrace_record__free(rec->itr);
	return err;
}

static void snapshot_sig_handler(int sig __maybe_unused)
{
	if (!auxtrace_snapshot_enabled)
		return;
	auxtrace_snapshot_enabled = 0;
	auxtrace_snapshot_err = auxtrace_record__snapshot_start(record.itr);
	auxtrace_record__snapshot_started = 1;
}
+11 −0
Original line number Diff line number Diff line
@@ -563,6 +563,17 @@ int itrace_parse_synth_opts(const struct option *opt __maybe_unused,
	return -EINVAL;
}

static inline
int auxtrace_parse_snapshot_options(struct auxtrace_record *itr __maybe_unused,
				    struct record_opts *opts __maybe_unused,
				    const char *str)
{
	if (!str)
		return 0;
	pr_err("AUX area tracing not supported\n");
	return -EINVAL;
}

static inline
int auxtrace__process_event(struct perf_session *session __maybe_unused,
			    union perf_event *event __maybe_unused,
+4 −0
Original line number Diff line number Diff line
@@ -123,6 +123,10 @@ struct option {
#define OPT_LONG(s, l, v, h)        { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = check_vtype(v, long *), .help = (h) }
#define OPT_U64(s, l, v, h)         { .type = OPTION_U64, .short_name = (s), .long_name = (l), .value = check_vtype(v, u64 *), .help = (h) }
#define OPT_STRING(s, l, v, a, h)   { .type = OPTION_STRING,  .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h) }
#define OPT_STRING_OPTARG(s, l, v, a, h, d) \
	{ .type = OPTION_STRING,  .short_name = (s), .long_name = (l), \
	  .value = check_vtype(v, const char **), (a), .help = (h), \
	  .flags = PARSE_OPT_OPTARG, .defval = (intptr_t)(d) }
#define OPT_STRING_NOEMPTY(s, l, v, a, h)   { .type = OPTION_STRING,  .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h), .flags = PARSE_OPT_NOEMPTY}
#define OPT_DATE(s, l, v, h) \
	{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }