diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-06-05 14:22:46 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-06 07:14:47 -0400 |
commit | 8326f44da090d6d304d29b9fdc7fb3e20889e329 (patch) | |
tree | a15b2a2155c64a327b3cdf1da0997755d49390eb /Documentation/perf_counter | |
parent | a21ca2cac582886a3e95c8bb84ff7c52d4d15e54 (diff) |
perf_counter: Implement generalized cache event types
Extend generic event enumeration with the PERF_TYPE_HW_CACHE
method.
This is a 3-dimensional space:
{ L1-D, L1-I, L2, ITLB, DTLB, BPU } x
{ load, store, prefetch } x
{ accesses, misses }
User-space passes in the 3 coordinates and the kernel provides
a counter. (if the hardware supports that type and if the
combination makes sense.)
Combinations that make no sense produce a -EINVAL.
Combinations that are not supported by the hardware produce -ENOTSUP.
Extend the tools to deal with this, and rewrite the event symbol
parsing code with various popular aliases for the units and
access methods above. So 'l1-cache-miss' and 'l1d-read-ops' are
both valid aliases.
( x86 is supported for now, with the Nehalem event table filled in,
and with Core2 and Atom having placeholder tables. )
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'Documentation/perf_counter')
-rw-r--r-- | Documentation/perf_counter/util/parse-events.c | 104 |
1 files changed, 101 insertions, 3 deletions
diff --git a/Documentation/perf_counter/util/parse-events.c b/Documentation/perf_counter/util/parse-events.c index eb56bd996573..de9a77c47151 100644 --- a/Documentation/perf_counter/util/parse-events.c +++ b/Documentation/perf_counter/util/parse-events.c | |||
@@ -6,6 +6,8 @@ | |||
6 | #include "exec_cmd.h" | 6 | #include "exec_cmd.h" |
7 | #include "string.h" | 7 | #include "string.h" |
8 | 8 | ||
9 | extern char *strcasestr(const char *haystack, const char *needle); | ||
10 | |||
9 | int nr_counters; | 11 | int nr_counters; |
10 | 12 | ||
11 | struct perf_counter_attr attrs[MAX_COUNTERS]; | 13 | struct perf_counter_attr attrs[MAX_COUNTERS]; |
@@ -17,6 +19,7 @@ struct event_symbol { | |||
17 | }; | 19 | }; |
18 | 20 | ||
19 | #define C(x, y) .type = PERF_TYPE_##x, .config = PERF_COUNT_##y | 21 | #define C(x, y) .type = PERF_TYPE_##x, .config = PERF_COUNT_##y |
22 | #define CR(x, y) .type = PERF_TYPE_##x, .config = y | ||
20 | 23 | ||
21 | static struct event_symbol event_symbols[] = { | 24 | static struct event_symbol event_symbols[] = { |
22 | { C(HARDWARE, CPU_CYCLES), "cpu-cycles", }, | 25 | { C(HARDWARE, CPU_CYCLES), "cpu-cycles", }, |
@@ -69,6 +72,28 @@ static char *sw_event_names[] = { | |||
69 | "major faults", | 72 | "major faults", |
70 | }; | 73 | }; |
71 | 74 | ||
75 | #define MAX_ALIASES 8 | ||
76 | |||
77 | static char *hw_cache [][MAX_ALIASES] = { | ||
78 | { "l1-d" , "l1d" , "l1", "l1-data-cache" }, | ||
79 | { "l1-i" , "l1i" , "l1-instruction-cache" }, | ||
80 | { "l2" , }, | ||
81 | { "dtlb", }, | ||
82 | { "itlb", }, | ||
83 | { "bpu" , "btb", "branch-cache", NULL }, | ||
84 | }; | ||
85 | |||
86 | static char *hw_cache_op [][MAX_ALIASES] = { | ||
87 | { "read" , "load" }, | ||
88 | { "write" , "store" }, | ||
89 | { "prefetch" , "speculative-read", "speculative-load" }, | ||
90 | }; | ||
91 | |||
92 | static char *hw_cache_result [][MAX_ALIASES] = { | ||
93 | { "access", "ops" }, | ||
94 | { "miss", }, | ||
95 | }; | ||
96 | |||
72 | char *event_name(int counter) | 97 | char *event_name(int counter) |
73 | { | 98 | { |
74 | __u64 config = attrs[counter].config; | 99 | __u64 config = attrs[counter].config; |
@@ -86,6 +111,30 @@ char *event_name(int counter) | |||
86 | return hw_event_names[config]; | 111 | return hw_event_names[config]; |
87 | return "unknown-hardware"; | 112 | return "unknown-hardware"; |
88 | 113 | ||
114 | case PERF_TYPE_HW_CACHE: { | ||
115 | __u8 cache_type, cache_op, cache_result; | ||
116 | static char name[100]; | ||
117 | |||
118 | cache_type = (config >> 0) & 0xff; | ||
119 | if (cache_type > PERF_COUNT_HW_CACHE_MAX) | ||
120 | return "unknown-ext-hardware-cache-type"; | ||
121 | |||
122 | cache_op = (config >> 8) & 0xff; | ||
123 | if (cache_type > PERF_COUNT_HW_CACHE_OP_MAX) | ||
124 | return "unknown-ext-hardware-cache-op-type"; | ||
125 | |||
126 | cache_result = (config >> 16) & 0xff; | ||
127 | if (cache_type > PERF_COUNT_HW_CACHE_RESULT_MAX) | ||
128 | return "unknown-ext-hardware-cache-result-type"; | ||
129 | |||
130 | sprintf(name, "%s:%s:%s", | ||
131 | hw_cache[cache_type][0], | ||
132 | hw_cache_op[cache_op][0], | ||
133 | hw_cache_result[cache_result][0]); | ||
134 | |||
135 | return name; | ||
136 | } | ||
137 | |||
89 | case PERF_TYPE_SOFTWARE: | 138 | case PERF_TYPE_SOFTWARE: |
90 | if (config < PERF_SW_EVENTS_MAX) | 139 | if (config < PERF_SW_EVENTS_MAX) |
91 | return sw_event_names[config]; | 140 | return sw_event_names[config]; |
@@ -98,11 +147,60 @@ char *event_name(int counter) | |||
98 | return "unknown"; | 147 | return "unknown"; |
99 | } | 148 | } |
100 | 149 | ||
150 | static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size) | ||
151 | { | ||
152 | int i, j; | ||
153 | |||
154 | for (i = 0; i < size; i++) { | ||
155 | for (j = 0; j < MAX_ALIASES; j++) { | ||
156 | if (!names[i][j]) | ||
157 | break; | ||
158 | if (strcasestr(str, names[i][j])) | ||
159 | return i; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr) | ||
167 | { | ||
168 | __u8 cache_type = -1, cache_op = 0, cache_result = 0; | ||
169 | |||
170 | cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX); | ||
171 | /* | ||
172 | * No fallback - if we cannot get a clear cache type | ||
173 | * then bail out: | ||
174 | */ | ||
175 | if (cache_type == -1) | ||
176 | return -EINVAL; | ||
177 | |||
178 | cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX); | ||
179 | /* | ||
180 | * Fall back to reads: | ||
181 | */ | ||
182 | if (cache_type == -1) | ||
183 | cache_type = PERF_COUNT_HW_CACHE_OP_READ; | ||
184 | |||
185 | cache_result = parse_aliases(str, hw_cache_result, | ||
186 | PERF_COUNT_HW_CACHE_RESULT_MAX); | ||
187 | /* | ||
188 | * Fall back to accesses: | ||
189 | */ | ||
190 | if (cache_result == -1) | ||
191 | cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS; | ||
192 | |||
193 | attr->config = cache_type | (cache_op << 8) | (cache_result << 16); | ||
194 | attr->type = PERF_TYPE_HW_CACHE; | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
101 | /* | 199 | /* |
102 | * Each event can have multiple symbolic names. | 200 | * Each event can have multiple symbolic names. |
103 | * Symbolic names are (almost) exactly matched. | 201 | * Symbolic names are (almost) exactly matched. |
104 | */ | 202 | */ |
105 | static int match_event_symbols(const char *str, struct perf_counter_attr *attr) | 203 | static int parse_event_symbols(const char *str, struct perf_counter_attr *attr) |
106 | { | 204 | { |
107 | __u64 config, id; | 205 | __u64 config, id; |
108 | int type; | 206 | int type; |
@@ -147,7 +245,7 @@ static int match_event_symbols(const char *str, struct perf_counter_attr *attr) | |||
147 | } | 245 | } |
148 | } | 246 | } |
149 | 247 | ||
150 | return -EINVAL; | 248 | return parse_generic_hw_symbols(str, attr); |
151 | } | 249 | } |
152 | 250 | ||
153 | int parse_events(const struct option *opt, const char *str, int unset) | 251 | int parse_events(const struct option *opt, const char *str, int unset) |
@@ -160,7 +258,7 @@ again: | |||
160 | if (nr_counters == MAX_COUNTERS) | 258 | if (nr_counters == MAX_COUNTERS) |
161 | return -1; | 259 | return -1; |
162 | 260 | ||
163 | ret = match_event_symbols(str, &attr); | 261 | ret = parse_event_symbols(str, &attr); |
164 | if (ret < 0) | 262 | if (ret < 0) |
165 | return ret; | 263 | return ret; |
166 | 264 | ||