lkml.org 
[lkml]   [2011]   [Apr]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: [PATCH 1/1] perf tools: Add missing user space support for config1/config2
On Fri, Apr 22, 2011 at 08:34:29AM +0200, Ingo Molnar wrote:
> This needs to be a *lot* more user friendly. Users do not want to type in
> stupid hexa magic numbers to get profiling. We have moved beyond the oprofile
> era really.

I agree that the raw events are quite user unfriendly.

Unfortunately they are the way of life in perf -- unlike oprofile -- currently
if you want any CPU specific events like this.

Really to make sense out of all this you need per CPU full event lists.

I have an own wrapper to make it more user friendly, but its functionality
should arguably migrate into perf.

I did a patch to add a mapping file some time ago, but it likely
needs some improvements before it can be merged (aka not .39), like
auto selecting a suitable mapping file and backtranslating raw
mappings on output.

BTW the new perf lat code needs the raw events config1 specification
internally, so this is needed in some form anyways.

Short of that the extended raw events is the best we can get short term I
think. So I would prefer to have it for .39 to make this feature
usable at all.

I attached the old mapping file patch for your reference.
I also put up a few mapping files for Intel CPUs at
ftp://ftp.kernel.org/pub/linux/kernel/people/ak/pmu/*
e.g. to use it with Nehalem offcore events and this patch you would
use today

wget ftp://ftp.kernel.org/pub/linux/kernel/people/ak/pmu/nhm-ep.map
perf --map-file nhm-ep.map top -e offcore_response_0.any_data.local_cache_dram

-Andi

commit 37323c19ceb57101cc2160059c567ee14055b7c8
Author: Andi Kleen <ak@linux.intel.com>
Date: Mon Nov 8 04:52:18 2010 +0100

mapping file support

diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index a91f9f9..63bdbbb 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -120,6 +120,9 @@ Do not update the builid cache. This saves some overhead in situations
where the information in the perf.data file (which includes buildids)
is sufficient.

+--map-events=file
+Use file as event mapping file.
+
SEE ALSO
--------
linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 4b3a2d4..4f20af3 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -53,6 +53,9 @@ comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2
In per-thread mode, this option is ignored. The -a option is still necessary
to activate system-wide monitoring. Default is to count on all CPUs.

+--map-events=file
+Use file as event mapping file.
+
EXAMPLES
--------

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 93bd2ff..6fdf892 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -794,6 +794,9 @@ const struct option record_options[] = {
OPT_CALLBACK('e', "event", NULL, "event",
"event selector. use 'perf list' to list available events",
parse_events),
+ OPT_CALLBACK(0, "map-events", NULL, "map-events",
+ "specify mapping file for events",
+ map_events),
OPT_CALLBACK(0, "filter", NULL, "filter",
"event filter", parse_filter),
OPT_INTEGER('p', "pid", &target_pid,
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index a6b4d44..f21f307 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -525,6 +525,9 @@ static const struct option options[] = {
OPT_CALLBACK('e', "event", NULL, "event",
"event selector. use 'perf list' to list available events",
parse_events),
+ OPT_CALLBACK(0, "map-events", NULL, "map-events",
+ "specify mapping file for events",
+ map_events),
OPT_BOOLEAN('i', "no-inherit", &no_inherit,
"child tasks do not inherit counters"),
OPT_INTEGER('p', "pid", &target_pid,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 4af5bd5..2cc7b3d 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -83,6 +83,14 @@ static const char *sw_event_names[] = {
"emulation-faults",
};

+struct mapping {
+ const char *str;
+ const char *res;
+};
+
+static int mapping_max;
+static struct mapping *mappings;
+
#define MAX_ALIASES 8

static const char *hw_cache[][MAX_ALIASES] = {
@@ -731,12 +739,28 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
return 0;
}

+static int cmp_mapping(const void *a, const void *b)
+{
+ const struct mapping *am = a;
+ const struct mapping *bm = b;
+ return strcmp(am->str, bm->str);
+}
+
+static const char *
+get_event_mapping(const char *str)
+{
+ struct mapping key = { .str = str };
+ struct mapping *r = bsearch(&key, mappings, mapping_max,
+ sizeof(struct mapping), cmp_mapping);
+ return r ? r->res : NULL;
+}
+
/*
* Each event can have multiple symbolic names.
* Symbolic names are (almost) exactly matched.
*/
static enum event_result
-parse_event_symbols(const char **str, struct perf_event_attr *attr)
+do_parse_event_symbols(const char **str, struct perf_event_attr *attr)
{
enum event_result ret;

@@ -774,6 +798,15 @@ modifier:
return ret;
}

+static enum event_result
+parse_event_symbols(const char **str, struct perf_event_attr *attr)
+{
+ const char *map = get_event_mapping(*str);
+ if (map)
+ *str = map;
+ return do_parse_event_symbols(str, attr);
+}
+
static int store_event_type(const char *orgname)
{
char filename[PATH_MAX], *c;
@@ -963,3 +996,54 @@ void print_events(void)

exit(129);
}
+
+int map_events(const struct option *opt __used, const char *str,
+ int unset __used)
+{
+ FILE *f;
+ char *line = NULL;
+ size_t linelen = 0;
+ char *p;
+ int lineno = 0;
+ static int mapping_size;
+ struct mapping *map;
+
+ f = fopen(str, "r");
+ if (!f) {
+ pr_err("Cannot open event map file");
+ return -1;
+ }
+ while (getline(&line, &linelen, f) > 0) {
+ lineno++;
+ p = strpbrk(line, "\n#");
+ if (p)
+ *p = 0;
+ p = line + strspn(line, " \t");
+ if (*p == 0)
+ continue;
+ if (mapping_max >= mapping_size) {
+ if (!mapping_size)
+ mapping_size = 2048;
+ mapping_size *= 2;
+ mappings = realloc(mappings,
+ mapping_size * sizeof(struct mapping));
+ if (!mappings) {
+ pr_err("Out of memory\n");
+ exit(ENOMEM);
+ }
+ }
+ map = &mappings[mapping_max++];
+ map->str = strsep(&p, " \t");
+ map->res = strsep(&p, " \t");
+ if (!map->str || !map->res) {
+ fprintf(stderr, "%s:%d: Invalid line in map file\n",
+ str, lineno);
+ }
+ line = NULL;
+ linelen = 0;
+ }
+ fclose(f);
+ qsort(mappings, mapping_max, sizeof(struct mapping),
+ cmp_mapping);
+ return 0;
+}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index fc4ab3f..1d6df9c 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -33,5 +33,6 @@ extern void print_events(void);
extern char debugfs_path[];
extern int valid_debugfs_mount(const char *debugfs);

+extern int map_events(const struct option *opt, const char *str, int unset);

#endif /* __PERF_PARSE_EVENTS_H */

\
 
 \ /
  Last update: 2011-04-22 18:25    [from the cache]
©2003-2011 Jasper Spaans