mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-15 05:11:32 +00:00
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: Adrian Hunter <adrian.hunter@intel.com> Acked-by: Jiri 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: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
d20031bb63
commit
2dd6d8a10a
@ -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]
|
||||
|
@ -112,6 +112,32 @@ out:
|
||||
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;
|
||||
}
|
||||
|
||||
static inline
|
||||
void record__read_auxtrace_snapshot(struct record *rec __maybe_unused)
|
||||
{
|
||||
}
|
||||
|
||||
static inline
|
||||
int auxtrace_record__snapshot_start(struct auxtrace_record *itr __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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
static int record__open(struct record *rec)
|
||||
{
|
||||
char msg[512];
|
||||
@ -238,7 +302,8 @@ try_again:
|
||||
}
|
||||
|
||||
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,14 +634,27 @@ 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)
|
||||
break;
|
||||
@ -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 @@ out_symbol_exit:
|
||||
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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 }
|
||||
|
Loading…
Reference in New Issue
Block a user