diff options
author | Ingo Molnar <mingo@kernel.org> | 2012-06-20 07:41:42 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2012-06-20 07:41:53 -0400 |
commit | 32c46e579b68c7ac0cd19d0803898a841d99833d (patch) | |
tree | 64a15c3b6eca5b302ef5aff0e045f52035c33eb7 /tools/perf/util/evsel.c | |
parent | 2992c542fcd40777ed253f57362c65711fb8acaf (diff) | |
parent | c0a58fb2bdf033df433cad9009c7dac4c6b872b0 (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf improvements from Arnaldo Carvalho de Melo:
* Replace event_name with perf_evsel__name, that handles the event
modifiers and doesn't use static variables.
* GTK browser improvements, from Namhyung Kim
* Fix possible NULL pointer deref in the TUI annotate browser, from
Samuel Liao
* Add sort by source file:line number, using addr2line.
* Allow printing histogram text snapshots at any point in top/report.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf/util/evsel.c')
-rw-r--r-- | tools/perf/util/evsel.c | 196 |
1 files changed, 169 insertions, 27 deletions
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 9f6cebd798ee..876f639d69ed 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -78,7 +78,7 @@ static const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = { | |||
78 | "ref-cycles", | 78 | "ref-cycles", |
79 | }; | 79 | }; |
80 | 80 | ||
81 | const char *__perf_evsel__hw_name(u64 config) | 81 | static const char *__perf_evsel__hw_name(u64 config) |
82 | { | 82 | { |
83 | if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config]) | 83 | if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config]) |
84 | return perf_evsel__hw_names[config]; | 84 | return perf_evsel__hw_names[config]; |
@@ -86,16 +86,15 @@ const char *__perf_evsel__hw_name(u64 config) | |||
86 | return "unknown-hardware"; | 86 | return "unknown-hardware"; |
87 | } | 87 | } |
88 | 88 | ||
89 | static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size) | 89 | static int perf_evsel__add_modifiers(struct perf_evsel *evsel, char *bf, size_t size) |
90 | { | 90 | { |
91 | int colon = 0; | 91 | int colon = 0, r = 0; |
92 | struct perf_event_attr *attr = &evsel->attr; | 92 | struct perf_event_attr *attr = &evsel->attr; |
93 | int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(attr->config)); | ||
94 | bool exclude_guest_default = false; | 93 | bool exclude_guest_default = false; |
95 | 94 | ||
96 | #define MOD_PRINT(context, mod) do { \ | 95 | #define MOD_PRINT(context, mod) do { \ |
97 | if (!attr->exclude_##context) { \ | 96 | if (!attr->exclude_##context) { \ |
98 | if (!colon) colon = r++; \ | 97 | if (!colon) colon = ++r; \ |
99 | r += scnprintf(bf + r, size - r, "%c", mod); \ | 98 | r += scnprintf(bf + r, size - r, "%c", mod); \ |
100 | } } while(0) | 99 | } } while(0) |
101 | 100 | ||
@@ -108,7 +107,7 @@ static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size) | |||
108 | 107 | ||
109 | if (attr->precise_ip) { | 108 | if (attr->precise_ip) { |
110 | if (!colon) | 109 | if (!colon) |
111 | colon = r++; | 110 | colon = ++r; |
112 | r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp"); | 111 | r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp"); |
113 | exclude_guest_default = true; | 112 | exclude_guest_default = true; |
114 | } | 113 | } |
@@ -119,39 +118,182 @@ static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size) | |||
119 | } | 118 | } |
120 | #undef MOD_PRINT | 119 | #undef MOD_PRINT |
121 | if (colon) | 120 | if (colon) |
122 | bf[colon] = ':'; | 121 | bf[colon - 1] = ':'; |
123 | return r; | 122 | return r; |
124 | } | 123 | } |
125 | 124 | ||
126 | int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size) | 125 | static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size) |
126 | { | ||
127 | int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(evsel->attr.config)); | ||
128 | return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); | ||
129 | } | ||
130 | |||
131 | static const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = { | ||
132 | "cpu-clock", | ||
133 | "task-clock", | ||
134 | "page-faults", | ||
135 | "context-switches", | ||
136 | "CPU-migrations", | ||
137 | "minor-faults", | ||
138 | "major-faults", | ||
139 | "alignment-faults", | ||
140 | "emulation-faults", | ||
141 | }; | ||
142 | |||
143 | static const char *__perf_evsel__sw_name(u64 config) | ||
144 | { | ||
145 | if (config < PERF_COUNT_SW_MAX && perf_evsel__sw_names[config]) | ||
146 | return perf_evsel__sw_names[config]; | ||
147 | return "unknown-software"; | ||
148 | } | ||
149 | |||
150 | static int perf_evsel__sw_name(struct perf_evsel *evsel, char *bf, size_t size) | ||
151 | { | ||
152 | int r = scnprintf(bf, size, "%s", __perf_evsel__sw_name(evsel->attr.config)); | ||
153 | return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); | ||
154 | } | ||
155 | |||
156 | const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX] | ||
157 | [PERF_EVSEL__MAX_ALIASES] = { | ||
158 | { "L1-dcache", "l1-d", "l1d", "L1-data", }, | ||
159 | { "L1-icache", "l1-i", "l1i", "L1-instruction", }, | ||
160 | { "LLC", "L2", }, | ||
161 | { "dTLB", "d-tlb", "Data-TLB", }, | ||
162 | { "iTLB", "i-tlb", "Instruction-TLB", }, | ||
163 | { "branch", "branches", "bpu", "btb", "bpc", }, | ||
164 | { "node", }, | ||
165 | }; | ||
166 | |||
167 | const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX] | ||
168 | [PERF_EVSEL__MAX_ALIASES] = { | ||
169 | { "load", "loads", "read", }, | ||
170 | { "store", "stores", "write", }, | ||
171 | { "prefetch", "prefetches", "speculative-read", "speculative-load", }, | ||
172 | }; | ||
173 | |||
174 | const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX] | ||
175 | [PERF_EVSEL__MAX_ALIASES] = { | ||
176 | { "refs", "Reference", "ops", "access", }, | ||
177 | { "misses", "miss", }, | ||
178 | }; | ||
179 | |||
180 | #define C(x) PERF_COUNT_HW_CACHE_##x | ||
181 | #define CACHE_READ (1 << C(OP_READ)) | ||
182 | #define CACHE_WRITE (1 << C(OP_WRITE)) | ||
183 | #define CACHE_PREFETCH (1 << C(OP_PREFETCH)) | ||
184 | #define COP(x) (1 << x) | ||
185 | |||
186 | /* | ||
187 | * cache operartion stat | ||
188 | * L1I : Read and prefetch only | ||
189 | * ITLB and BPU : Read-only | ||
190 | */ | ||
191 | static unsigned long perf_evsel__hw_cache_stat[C(MAX)] = { | ||
192 | [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), | ||
193 | [C(L1I)] = (CACHE_READ | CACHE_PREFETCH), | ||
194 | [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), | ||
195 | [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), | ||
196 | [C(ITLB)] = (CACHE_READ), | ||
197 | [C(BPU)] = (CACHE_READ), | ||
198 | [C(NODE)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), | ||
199 | }; | ||
200 | |||
201 | bool perf_evsel__is_cache_op_valid(u8 type, u8 op) | ||
202 | { | ||
203 | if (perf_evsel__hw_cache_stat[type] & COP(op)) | ||
204 | return true; /* valid */ | ||
205 | else | ||
206 | return false; /* invalid */ | ||
207 | } | ||
208 | |||
209 | int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, | ||
210 | char *bf, size_t size) | ||
211 | { | ||
212 | if (result) { | ||
213 | return scnprintf(bf, size, "%s-%s-%s", perf_evsel__hw_cache[type][0], | ||
214 | perf_evsel__hw_cache_op[op][0], | ||
215 | perf_evsel__hw_cache_result[result][0]); | ||
216 | } | ||
217 | |||
218 | return scnprintf(bf, size, "%s-%s", perf_evsel__hw_cache[type][0], | ||
219 | perf_evsel__hw_cache_op[op][1]); | ||
220 | } | ||
221 | |||
222 | static int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size) | ||
127 | { | 223 | { |
128 | int ret; | 224 | u8 op, result, type = (config >> 0) & 0xff; |
225 | const char *err = "unknown-ext-hardware-cache-type"; | ||
226 | |||
227 | if (type > PERF_COUNT_HW_CACHE_MAX) | ||
228 | goto out_err; | ||
229 | |||
230 | op = (config >> 8) & 0xff; | ||
231 | err = "unknown-ext-hardware-cache-op"; | ||
232 | if (op > PERF_COUNT_HW_CACHE_OP_MAX) | ||
233 | goto out_err; | ||
234 | |||
235 | result = (config >> 16) & 0xff; | ||
236 | err = "unknown-ext-hardware-cache-result"; | ||
237 | if (result > PERF_COUNT_HW_CACHE_RESULT_MAX) | ||
238 | goto out_err; | ||
239 | |||
240 | err = "invalid-cache"; | ||
241 | if (!perf_evsel__is_cache_op_valid(type, op)) | ||
242 | goto out_err; | ||
243 | |||
244 | return __perf_evsel__hw_cache_type_op_res_name(type, op, result, bf, size); | ||
245 | out_err: | ||
246 | return scnprintf(bf, size, "%s", err); | ||
247 | } | ||
248 | |||
249 | static int perf_evsel__hw_cache_name(struct perf_evsel *evsel, char *bf, size_t size) | ||
250 | { | ||
251 | int ret = __perf_evsel__hw_cache_name(evsel->attr.config, bf, size); | ||
252 | return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret); | ||
253 | } | ||
254 | |||
255 | static int perf_evsel__raw_name(struct perf_evsel *evsel, char *bf, size_t size) | ||
256 | { | ||
257 | int ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config); | ||
258 | return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret); | ||
259 | } | ||
260 | |||
261 | const char *perf_evsel__name(struct perf_evsel *evsel) | ||
262 | { | ||
263 | char bf[128]; | ||
264 | |||
265 | if (evsel->name) | ||
266 | return evsel->name; | ||
129 | 267 | ||
130 | switch (evsel->attr.type) { | 268 | switch (evsel->attr.type) { |
131 | case PERF_TYPE_RAW: | 269 | case PERF_TYPE_RAW: |
132 | ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config); | 270 | perf_evsel__raw_name(evsel, bf, sizeof(bf)); |
133 | break; | 271 | break; |
134 | 272 | ||
135 | case PERF_TYPE_HARDWARE: | 273 | case PERF_TYPE_HARDWARE: |
136 | ret = perf_evsel__hw_name(evsel, bf, size); | 274 | perf_evsel__hw_name(evsel, bf, sizeof(bf)); |
275 | break; | ||
276 | |||
277 | case PERF_TYPE_HW_CACHE: | ||
278 | perf_evsel__hw_cache_name(evsel, bf, sizeof(bf)); | ||
279 | break; | ||
280 | |||
281 | case PERF_TYPE_SOFTWARE: | ||
282 | perf_evsel__sw_name(evsel, bf, sizeof(bf)); | ||
137 | break; | 283 | break; |
284 | |||
285 | case PERF_TYPE_TRACEPOINT: | ||
286 | scnprintf(bf, sizeof(bf), "%s", "unknown tracepoint"); | ||
287 | break; | ||
288 | |||
138 | default: | 289 | default: |
139 | /* | 290 | scnprintf(bf, sizeof(bf), "%s", "unknown attr type"); |
140 | * FIXME | 291 | break; |
141 | * | 292 | } |
142 | * This is the minimal perf_evsel__name so that we can | 293 | |
143 | * reconstruct event names taking into account event modifiers. | 294 | evsel->name = strdup(bf); |
144 | * | 295 | |
145 | * The old event_name uses it now for raw anr hw events, so that | 296 | return evsel->name ?: "unknown"; |
146 | * we don't drag all the parsing stuff into the python binding. | ||
147 | * | ||
148 | * On the next devel cycle the rest of the event naming will be | ||
149 | * brought here. | ||
150 | */ | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | return ret; | ||
155 | } | 297 | } |
156 | 298 | ||
157 | void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, | 299 | void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, |