Re: [PATCH v2 3/4] perf record: add ability to name registers to record

From: Arnaldo Carvalho de Melo
Date: Mon Aug 31 2015 - 17:02:31 EST


Em Mon, Aug 31, 2015 at 06:41:12PM +0200, Stephane Eranian escreveu:
> 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.

Applied and tested up to this one, waiting for the discussion with Andi
to proceed to the last one.

- Arnaldo

> 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: Stephane Eranian <eranian@xxxxxxxxxx>
> ---
> tools/perf/Documentation/perf-record.txt | 6 ++-
> tools/perf/builtin-record.c | 7 +++-
> tools/perf/perf.h | 2 +-
> tools/perf/util/Build | 1 +
> tools/perf/util/evsel.c | 2 +-
> tools/perf/util/parse-regs-options.c | 71 ++++++++++++++++++++++++++++++++
> tools/perf/util/parse-regs-options.h | 5 +++
> 7 files changed, 89 insertions(+), 5 deletions(-)
> create mode 100644 tools/perf/util/parse-regs-options.c
> create mode 100644 tools/perf/util/parse-regs-options.h
>
> diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
> index 347a273..2e9ce77 100644
> --- a/tools/perf/Documentation/perf-record.txt
> +++ b/tools/perf/Documentation/perf-record.txt
> @@ -276,7 +276,11 @@ filter out the startup phase of the program, which is often very different.
> --intr-regs::
> Capture machine state (registers) at interrupt, i.e., on counter overflows for
> 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::
> Record running and enabled time for read events (:S)
> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> index a660022..d3a5d91 100644
> --- a/tools/perf/builtin-record.c
> +++ b/tools/perf/builtin-record.c
> @@ -27,8 +27,10 @@
> #include "util/cpumap.h"
> #include "util/thread_map.h"
> #include "util/data.h"
> +#include "util/perf_regs.h"
> #include "util/auxtrace.h"
> #include "util/parse-branch-options.h"
> +#include "util/parse-regs-options.h"
>
> #include <unistd.h>
> #include <sched.h>
> @@ -1080,8 +1082,9 @@ struct option __record_options[] = {
> "sample transaction flags (special events only)"),
> OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
> "use per-thread mmaps"),
> - OPT_BOOLEAN('I', "intr-regs", &record.opts.sample_intr_regs,
> - "Sample machine registers on interrupt"),
> + OPT_CALLBACK_OPTARG('I', "intr-regs", &record.opts.sample_intr_regs, NULL, "any register",
> + "sample selected machine registers on interrupt,"
> + " use -I ? to list register names", parse_regs),
> OPT_BOOLEAN(0, "running-time", &record.opts.running_time,
> "Record running/enabled time of read (:S) events"),
> OPT_CALLBACK('k', "clockid", &record.opts,
> diff --git a/tools/perf/perf.h b/tools/perf/perf.h
> index cccb4cf..90129ac 100644
> --- a/tools/perf/perf.h
> +++ b/tools/perf/perf.h
> @@ -54,7 +54,6 @@ struct record_opts {
> bool sample_time_set;
> bool callgraph_set;
> bool period;
> - bool sample_intr_regs;
> bool running_time;
> bool full_auxtrace;
> bool auxtrace_snapshot_mode;
> @@ -64,6 +63,7 @@ struct record_opts {
> unsigned int auxtrace_mmap_pages;
> unsigned int user_freq;
> u64 branch_stack;
> + u64 sample_intr_regs;
> u64 default_interval;
> u64 user_interval;
> size_t auxtrace_snapshot_size;
> diff --git a/tools/perf/util/Build b/tools/perf/util/Build
> index e912856..7df4937 100644
> --- a/tools/perf/util/Build
> +++ b/tools/perf/util/Build
> @@ -82,6 +82,7 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/
> libperf-$(CONFIG_AUXTRACE) += intel-pt.o
> libperf-$(CONFIG_AUXTRACE) += intel-bts.o
> libperf-y += parse-branch-options.o
> +libperf-y += parse-regs-options.o
>
> libperf-$(CONFIG_LIBELF) += symbol-elf.o
> libperf-$(CONFIG_LIBELF) += probe-file.o
> diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
> index fd53cc2..b049633 100644
> --- a/tools/perf/util/evsel.c
> +++ b/tools/perf/util/evsel.c
> @@ -787,7 +787,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
> perf_evsel__config_callgraph(evsel, opts, &callchain_param);
>
> 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);
> }
>
> diff --git a/tools/perf/util/parse-regs-options.c b/tools/perf/util/parse-regs-options.c
> new file mode 100644
> index 0000000..4f2c1c2
> --- /dev/null
> +++ b/tools/perf/util/parse-regs-options.c
> @@ -0,0 +1,71 @@
> +#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;
> +}
> diff --git a/tools/perf/util/parse-regs-options.h b/tools/perf/util/parse-regs-options.h
> new file mode 100644
> index 0000000..7d762b1
> --- /dev/null
> +++ b/tools/perf/util/parse-regs-options.h
> @@ -0,0 +1,5 @@
> +#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 */
> --
> 1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/