Commit bcc84ec6 authored by Stephane Eranian's avatar Stephane Eranian Committed by Arnaldo Carvalho de Melo

perf record: Add ability to name registers to record

This patch modifies the -I/--int-regs option to enablepassing the name
of the registers to sample on interrupt. Registers can be specified by
their symbolic names. For instance on x86, --intr-regs=ax,si.

The motivation is to reduce the size of the perf.data file and the
overhead of sampling by only collecting the registers useful to a
specific analysis. For instance, for value profiling, sampling only the
registers used to passed arguements to functions.

With no parameter, the --intr-regs still records all possible registers
based on the architecture.

To name registers, it is necessary to use the long form of the option,
i.e., --intr-regs:

  $ perf record --intr-regs=si,di,r8,r9 .....

To record any possible registers:

  $ perf record -I .....
  $ perf report --intr-regs ...

To display the register, one can use perf report -D

To list the available registers:

  $ perf record --intr-regs=\?
  available registers: AX BX CX DX SI DI BP SP IP FLAGS CS SS R8 R9 R10 R11 R12 R13 R14 R15
Signed-off-by: default avatarStephane Eranian <eranian@google.com>
Tested-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Kan Liang <kan.liang@intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1441039273-16260-4-git-send-email-eranian@google.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent c5e991ee
...@@ -276,7 +276,11 @@ filter out the startup phase of the program, which is often very different. ...@@ -276,7 +276,11 @@ filter out the startup phase of the program, which is often very different.
--intr-regs:: --intr-regs::
Capture machine state (registers) at interrupt, i.e., on counter overflows for Capture machine state (registers) at interrupt, i.e., on counter overflows for
each sample. List of captured registers depends on the architecture. This option each sample. List of captured registers depends on the architecture. This option
is off by default. is off by default. It is possible to select the registers to sample using their
symbolic names, e.g. on x86, ax, si. To list the available registers use
--intr-regs=\?. To name registers, pass a comma separated list such as
--intr-regs=ax,bx. The list of register is architecture dependent.
--running-time:: --running-time::
Record running and enabled time for read events (:S) Record running and enabled time for read events (:S)
......
...@@ -27,8 +27,10 @@ ...@@ -27,8 +27,10 @@
#include "util/cpumap.h" #include "util/cpumap.h"
#include "util/thread_map.h" #include "util/thread_map.h"
#include "util/data.h" #include "util/data.h"
#include "util/perf_regs.h"
#include "util/auxtrace.h" #include "util/auxtrace.h"
#include "util/parse-branch-options.h" #include "util/parse-branch-options.h"
#include "util/parse-regs-options.h"
#include <unistd.h> #include <unistd.h>
#include <sched.h> #include <sched.h>
...@@ -1080,8 +1082,9 @@ struct option __record_options[] = { ...@@ -1080,8 +1082,9 @@ struct option __record_options[] = {
"sample transaction flags (special events only)"), "sample transaction flags (special events only)"),
OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread, OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
"use per-thread mmaps"), "use per-thread mmaps"),
OPT_BOOLEAN('I', "intr-regs", &record.opts.sample_intr_regs, OPT_CALLBACK_OPTARG('I', "intr-regs", &record.opts.sample_intr_regs, NULL, "any register",
"Sample machine registers on interrupt"), "sample selected machine registers on interrupt,"
" use -I ? to list register names", parse_regs),
OPT_BOOLEAN(0, "running-time", &record.opts.running_time, OPT_BOOLEAN(0, "running-time", &record.opts.running_time,
"Record running/enabled time of read (:S) events"), "Record running/enabled time of read (:S) events"),
OPT_CALLBACK('k', "clockid", &record.opts, OPT_CALLBACK('k', "clockid", &record.opts,
......
...@@ -54,7 +54,6 @@ struct record_opts { ...@@ -54,7 +54,6 @@ struct record_opts {
bool sample_time_set; bool sample_time_set;
bool callgraph_set; bool callgraph_set;
bool period; bool period;
bool sample_intr_regs;
bool running_time; bool running_time;
bool full_auxtrace; bool full_auxtrace;
bool auxtrace_snapshot_mode; bool auxtrace_snapshot_mode;
...@@ -64,6 +63,7 @@ struct record_opts { ...@@ -64,6 +63,7 @@ struct record_opts {
unsigned int auxtrace_mmap_pages; unsigned int auxtrace_mmap_pages;
unsigned int user_freq; unsigned int user_freq;
u64 branch_stack; u64 branch_stack;
u64 sample_intr_regs;
u64 default_interval; u64 default_interval;
u64 user_interval; u64 user_interval;
size_t auxtrace_snapshot_size; size_t auxtrace_snapshot_size;
......
...@@ -83,6 +83,7 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/ ...@@ -83,6 +83,7 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/
libperf-$(CONFIG_AUXTRACE) += intel-pt.o libperf-$(CONFIG_AUXTRACE) += intel-pt.o
libperf-$(CONFIG_AUXTRACE) += intel-bts.o libperf-$(CONFIG_AUXTRACE) += intel-bts.o
libperf-y += parse-branch-options.o libperf-y += parse-branch-options.o
libperf-y += parse-regs-options.o
libperf-$(CONFIG_LIBELF) += symbol-elf.o libperf-$(CONFIG_LIBELF) += symbol-elf.o
libperf-$(CONFIG_LIBELF) += probe-file.o libperf-$(CONFIG_LIBELF) += probe-file.o
......
...@@ -787,7 +787,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) ...@@ -787,7 +787,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
perf_evsel__config_callgraph(evsel, opts, &callchain_param); perf_evsel__config_callgraph(evsel, opts, &callchain_param);
if (opts->sample_intr_regs) { if (opts->sample_intr_regs) {
attr->sample_regs_intr = PERF_REGS_MASK; attr->sample_regs_intr = opts->sample_intr_regs;
perf_evsel__set_sample_bit(evsel, REGS_INTR); perf_evsel__set_sample_bit(evsel, REGS_INTR);
} }
......
#include "perf.h"
#include "util/util.h"
#include "util/debug.h"
#include "util/parse-options.h"
#include "util/parse-regs-options.h"
int
parse_regs(const struct option *opt, const char *str, int unset)
{
uint64_t *mode = (uint64_t *)opt->value;
const struct sample_reg *r;
char *s, *os = NULL, *p;
int ret = -1;
if (unset)
return 0;
/*
* cannot set it twice
*/
if (*mode)
return -1;
/* str may be NULL in case no arg is passed to -I */
if (str) {
/* because str is read-only */
s = os = strdup(str);
if (!s)
return -1;
for (;;) {
p = strchr(s, ',');
if (p)
*p = '\0';
if (!strcmp(s, "?")) {
fprintf(stderr, "available registers: ");
for (r = sample_reg_masks; r->name; r++) {
fprintf(stderr, "%s ", r->name);
}
fputc('\n', stderr);
/* just printing available regs */
return -1;
}
for (r = sample_reg_masks; r->name; r++) {
if (!strcasecmp(s, r->name))
break;
}
if (!r->name) {
ui__warning("unknown register %s,"
" check man page\n", s);
goto error;
}
*mode |= r->mask;
if (!p)
break;
s = p + 1;
}
}
ret = 0;
/* default to all possible regs */
if (*mode == 0)
*mode = PERF_REGS_MASK;
error:
free(os);
return ret;
}
#ifndef _PERF_PARSE_REGS_OPTIONS_H
#define _PERF_PARSE_REGS_OPTIONS_H 1
struct option;
int parse_regs(const struct option *opt, const char *str, int unset);
#endif /* _PERF_PARSE_REGS_OPTIONS_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment