aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/perf_counter/builtin-top.c303
1 files changed, 117 insertions, 186 deletions
diff --git a/Documentation/perf_counter/builtin-top.c b/Documentation/perf_counter/builtin-top.c
index a890872638c1..52ba9f4216cf 100644
--- a/Documentation/perf_counter/builtin-top.c
+++ b/Documentation/perf_counter/builtin-top.c
@@ -44,8 +44,9 @@
44 44
45#include "perf.h" 45#include "perf.h"
46#include "builtin.h" 46#include "builtin.h"
47#include "util/symbol.h"
47#include "util/util.h" 48#include "util/util.h"
48#include "util/util.h" 49#include "util/rbtree.h"
49#include "util/parse-options.h" 50#include "util/parse-options.h"
50#include "util/parse-events.h" 51#include "util/parse-events.h"
51 52
@@ -125,19 +126,21 @@ static uint64_t min_ip;
125static uint64_t max_ip = -1ll; 126static uint64_t max_ip = -1ll;
126 127
127struct sym_entry { 128struct sym_entry {
128 unsigned long long addr; 129 struct rb_node rb_node;
129 char *sym; 130 struct list_head node;
130 unsigned long count[MAX_COUNTERS]; 131 unsigned long count[MAX_COUNTERS];
131 int skip; 132 int skip;
132}; 133};
133 134
134#define MAX_SYMS 100000
135
136static int sym_table_count;
137
138struct sym_entry *sym_filter_entry; 135struct sym_entry *sym_filter_entry;
139 136
140static struct sym_entry sym_table[MAX_SYMS]; 137struct dso *kernel_dso;
138
139/*
140 * Symbols will be added here in record_ip and will get out
141 * after decayed.
142 */
143static LIST_HEAD(active_symbols);
141 144
142/* 145/*
143 * Ordering weight: count-1 * count-2 * ... / count-n 146 * Ordering weight: count-1 * count-2 * ... / count-n
@@ -157,42 +160,60 @@ static double sym_weight(const struct sym_entry *sym)
157 return weight; 160 return weight;
158} 161}
159 162
160static int compare(const void *__sym1, const void *__sym2)
161{
162 const struct sym_entry *sym1 = __sym1, *sym2 = __sym2;
163
164 return sym_weight(sym1) < sym_weight(sym2);
165}
166
167static long events; 163static long events;
168static long userspace_events; 164static long userspace_events;
169static const char CONSOLE_CLEAR[] = ""; 165static const char CONSOLE_CLEAR[] = "";
170 166
171static struct sym_entry tmp[MAX_SYMS]; 167static void list_insert_active_sym(struct sym_entry *syme)
168{
169 list_add(&syme->node, &active_symbols);
170}
171
172static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
173{
174 struct rb_node **p = &tree->rb_node;
175 struct rb_node *parent = NULL;
176 struct sym_entry *iter;
177
178 while (*p != NULL) {
179 parent = *p;
180 iter = rb_entry(parent, struct sym_entry, rb_node);
181
182 if (sym_weight(se) > sym_weight(iter))
183 p = &(*p)->rb_left;
184 else
185 p = &(*p)->rb_right;
186 }
187
188 rb_link_node(&se->rb_node, parent, p);
189 rb_insert_color(&se->rb_node, tree);
190}
172 191
173static void print_sym_table(void) 192static void print_sym_table(void)
174{ 193{
175 int i, j, active_count, printed; 194 int printed, j;
176 int counter; 195 int counter;
177 float events_per_sec = events/delay_secs; 196 float events_per_sec = events/delay_secs;
178 float kevents_per_sec = (events-userspace_events)/delay_secs; 197 float kevents_per_sec = (events-userspace_events)/delay_secs;
179 float sum_kevents = 0.0; 198 float sum_kevents = 0.0;
199 struct sym_entry *syme, *n;
200 struct rb_root tmp = RB_ROOT;
201 struct rb_node *nd;
180 202
181 events = userspace_events = 0; 203 events = userspace_events = 0;
182 204
183 /* Iterate over symbol table and copy/tally/decay active symbols. */ 205 /* Sort the active symbols */
184 for (i = 0, active_count = 0; i < sym_table_count; i++) { 206 list_for_each_entry_safe(syme, n, &active_symbols, node) {
185 if (sym_table[i].count[0]) { 207 if (syme->count[0] != 0) {
186 tmp[active_count++] = sym_table[i]; 208 rb_insert_active_sym(&tmp, syme);
187 sum_kevents += sym_table[i].count[0]; 209 sum_kevents += syme->count[0];
188 210
189 for (j = 0; j < nr_counters; j++) 211 for (j = 0; j < nr_counters; j++)
190 sym_table[i].count[j] = zero ? 0 : sym_table[i].count[j] * 7 / 8; 212 syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8;
191 } 213 } else
214 list_del_init(&syme->node);
192 } 215 }
193 216
194 qsort(tmp, active_count + 1, sizeof(tmp[0]), compare);
195
196 write(1, CONSOLE_CLEAR, strlen(CONSOLE_CLEAR)); 217 write(1, CONSOLE_CLEAR, strlen(CONSOLE_CLEAR));
197 218
198 printf( 219 printf(
@@ -238,23 +259,25 @@ static void print_sym_table(void)
238 " ______ ______ _____ ________________ _______________\n\n" 259 " ______ ______ _____ ________________ _______________\n\n"
239 ); 260 );
240 261
241 for (i = 0, printed = 0; i < active_count; i++) { 262 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
263 struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node);
264 struct symbol *sym = (struct symbol *)(syme + 1);
242 float pcnt; 265 float pcnt;
243 266
244 if (++printed > 18 || tmp[i].count[0] < count_filter) 267 if (++printed > 18 || syme->count[0] < count_filter)
245 break; 268 break;
246 269
247 pcnt = 100.0 - (100.0*((sum_kevents-tmp[i].count[0])/sum_kevents)); 270 pcnt = 100.0 - (100.0 * ((sum_kevents - syme->count[0]) /
271 sum_kevents));
248 272
249 if (nr_counters == 1) 273 if (nr_counters == 1)
250 printf("%19.2f - %4.1f%% - %016llx : %s\n", 274 printf("%19.2f - %4.1f%% - %016llx : %s\n",
251 sym_weight(tmp + i), 275 sym_weight(syme),
252 pcnt, tmp[i].addr, tmp[i].sym); 276 pcnt, sym->start, sym->name);
253 else 277 else
254 printf("%8.1f %10ld - %4.1f%% - %016llx : %s\n", 278 printf("%8.1f %10ld - %4.1f%% - %016llx : %s\n",
255 sym_weight(tmp + i), 279 sym_weight(syme), syme->count[0],
256 tmp[i].count[0], 280 pcnt, sym->start, sym->name);
257 pcnt, tmp[i].addr, tmp[i].sym);
258 } 281 }
259 282
260 { 283 {
@@ -277,146 +300,85 @@ static void *display_thread(void *arg)
277 return NULL; 300 return NULL;
278} 301}
279 302
280static int read_symbol(FILE *in, struct sym_entry *s) 303static int symbol_filter(struct dso *self, struct symbol *sym)
281{ 304{
282 static int filter_match = 0; 305 static int filter_match;
283 char *sym, stype; 306 struct sym_entry *syme;
284 char str[500]; 307 const char *name = sym->name;
285 int rc, pos; 308
286 309 if (!strcmp(name, "_text") ||
287 rc = fscanf(in, "%llx %c %499s", &s->addr, &stype, str); 310 !strcmp(name, "_etext") ||
288 if (rc == EOF) 311 !strcmp(name, "_sinittext") ||
289 return -1; 312 !strncmp("init_module", name, 11) ||
290 313 !strncmp("cleanup_module", name, 14) ||
291 assert(rc == 3); 314 strstr(name, "_text_start") ||
292 315 strstr(name, "_text_end"))
293 /* skip until end of line: */
294 pos = strlen(str);
295 do {
296 rc = fgetc(in);
297 if (rc == '\n' || rc == EOF || pos >= 499)
298 break;
299 str[pos] = rc;
300 pos++;
301 } while (1);
302 str[pos] = 0;
303
304 sym = str;
305
306 /* Filter out known duplicates and non-text symbols. */
307 if (!strcmp(sym, "_text"))
308 return 1;
309 if (!min_ip && !strcmp(sym, "_stext"))
310 return 1;
311 if (!strcmp(sym, "_etext") || !strcmp(sym, "_sinittext"))
312 return 1;
313 if (stype != 'T' && stype != 't')
314 return 1;
315 if (!strncmp("init_module", sym, 11) || !strncmp("cleanup_module", sym, 14))
316 return 1;
317 if (strstr(sym, "_text_start") || strstr(sym, "_text_end"))
318 return 1; 316 return 1;
319 317
320 s->sym = malloc(strlen(str)+1); 318 syme = dso__sym_priv(self, sym);
321 assert(s->sym);
322
323 strcpy((char *)s->sym, str);
324 s->skip = 0;
325
326 /* Tag events to be skipped. */ 319 /* Tag events to be skipped. */
327 if (!strcmp("default_idle", s->sym) || !strcmp("cpu_idle", s->sym)) 320 if (!strcmp("default_idle", name) ||
328 s->skip = 1; 321 !strcmp("cpu_idle", name) ||
329 else if (!strcmp("enter_idle", s->sym) || !strcmp("exit_idle", s->sym)) 322 !strcmp("enter_idle", name) ||
330 s->skip = 1; 323 !strcmp("exit_idle", name) ||
331 else if (!strcmp("mwait_idle", s->sym)) 324 !strcmp("mwait_idle", name))
332 s->skip = 1; 325 syme->skip = 1;
333 326
334 if (filter_match == 1) { 327 if (filter_match == 1) {
335 filter_end = s->addr; 328 filter_end = sym->start;
336 filter_match = -1; 329 filter_match = -1;
337 if (filter_end - filter_start > 10000) { 330 if (filter_end - filter_start > 10000) {
338 printf("hm, too large filter symbol <%s> - skipping.\n", 331 fprintf(stderr,
332 "hm, too large filter symbol <%s> - skipping.\n",
339 sym_filter); 333 sym_filter);
340 printf("symbol filter start: %016lx\n", filter_start); 334 fprintf(stderr, "symbol filter start: %016lx\n",
341 printf(" end: %016lx\n", filter_end); 335 filter_start);
336 fprintf(stderr, " end: %016lx\n",
337 filter_end);
342 filter_end = filter_start = 0; 338 filter_end = filter_start = 0;
343 sym_filter = NULL; 339 sym_filter = NULL;
344 sleep(1); 340 sleep(1);
345 } 341 }
346 } 342 }
347 if (filter_match == 0 && sym_filter && !strcmp(s->sym, sym_filter)) { 343
344 if (filter_match == 0 && sym_filter && !strcmp(name, sym_filter)) {
348 filter_match = 1; 345 filter_match = 1;
349 filter_start = s->addr; 346 filter_start = sym->start;
350 } 347 }
351 348
349
352 return 0; 350 return 0;
353} 351}
354 352
355static int compare_addr(const void *__sym1, const void *__sym2) 353static int parse_symbols(void)
356{ 354{
357 const struct sym_entry *sym1 = __sym1, *sym2 = __sym2; 355 struct rb_node *node;
356 struct symbol *sym;
358 357
359 return sym1->addr > sym2->addr; 358 kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
360} 359 if (kernel_dso == NULL)
361 360 return -1;
362static void sort_symbol_table(void)
363{
364 int i, dups;
365
366 do {
367 qsort(sym_table, sym_table_count, sizeof(sym_table[0]), compare_addr);
368 for (i = 0, dups = 0; i < sym_table_count; i++) {
369 if (sym_table[i].addr == sym_table[i+1].addr) {
370 sym_table[i+1].addr = -1ll;
371 dups++;
372 }
373 }
374 sym_table_count -= dups;
375 } while(dups);
376}
377
378static void parse_symbols(void)
379{
380 struct sym_entry *last;
381 361
382 FILE *kallsyms = fopen("/proc/kallsyms", "r"); 362 if (dso__load_kernel(kernel_dso, NULL, symbol_filter) != 0)
363 goto out_delete_dso;
383 364
384 if (!kallsyms) { 365 node = rb_first(&kernel_dso->syms);
385 printf("Could not open /proc/kallsyms - no CONFIG_KALLSYMS_ALL=y?\n"); 366 sym = rb_entry(node, struct symbol, rb_node);
386 exit(-1); 367 min_ip = sym->start;
387 }
388 368
389 while (!feof(kallsyms)) { 369 node = rb_last(&kernel_dso->syms);
390 if (read_symbol(kallsyms, &sym_table[sym_table_count]) == 0) { 370 sym = rb_entry(node, struct symbol, rb_node);
391 sym_table_count++; 371 max_ip = sym->start;
392 assert(sym_table_count <= MAX_SYMS);
393 }
394 }
395 372
396 sort_symbol_table(); 373 if (dump_symtab)
397 min_ip = sym_table[0].addr; 374 dso__fprintf(kernel_dso, stdout);
398 max_ip = sym_table[sym_table_count-1].addr;
399 last = sym_table + sym_table_count++;
400 375
401 last->addr = -1ll; 376 return 0;
402 last->sym = "<end>";
403
404 if (filter_end) {
405 int count;
406 for (count=0; count < sym_table_count; count ++) {
407 if (!strcmp(sym_table[count].sym, sym_filter)) {
408 sym_filter_entry = &sym_table[count];
409 break;
410 }
411 }
412 }
413 if (dump_symtab) {
414 int i;
415 377
416 for (i = 0; i < sym_table_count; i++) 378out_delete_dso:
417 fprintf(stderr, "%llx %s\n", 379 dso__delete(kernel_dso);
418 sym_table[i].addr, sym_table[i].sym); 380 kernel_dso = NULL;
419 } 381 return -1;
420} 382}
421 383
422#define TRACE_COUNT 3 384#define TRACE_COUNT 3
@@ -426,51 +388,20 @@ static void parse_symbols(void)
426 */ 388 */
427static void record_ip(uint64_t ip, int counter) 389static void record_ip(uint64_t ip, int counter)
428{ 390{
429 int left_idx, middle_idx, right_idx, idx; 391 struct symbol *sym = dso__find_symbol(kernel_dso, ip);
430 unsigned long left, middle, right;
431
432 left_idx = 0;
433 right_idx = sym_table_count-1;
434 assert(ip <= max_ip && ip >= min_ip);
435
436 while (left_idx + 1 < right_idx) {
437 middle_idx = (left_idx + right_idx) / 2;
438 392
439 left = sym_table[ left_idx].addr; 393 if (sym != NULL) {
440 middle = sym_table[middle_idx].addr; 394 struct sym_entry *syme = dso__sym_priv(kernel_dso, sym);
441 right = sym_table[ right_idx].addr;
442 395
443 if (!(left <= middle && middle <= right)) { 396 if (!syme->skip) {
444 printf("%016lx...\n%016lx...\n%016lx\n", left, middle, right); 397 syme->count[counter]++;
445 printf("%d %d %d\n", left_idx, middle_idx, right_idx); 398 if (list_empty(&syme->node) || !syme->node.next)
399 list_insert_active_sym(syme);
400 return;
446 } 401 }
447 assert(left <= middle && middle <= right);
448 if (!(left <= ip && ip <= right)) {
449 printf(" left: %016lx\n", left);
450 printf(" ip: %016lx\n", (unsigned long)ip);
451 printf("right: %016lx\n", right);
452 }
453 assert(left <= ip && ip <= right);
454 /*
455 * [ left .... target .... middle .... right ]
456 * => right := middle
457 */
458 if (ip < middle) {
459 right_idx = middle_idx;
460 continue;
461 }
462 /*
463 * [ left .... middle ... target ... right ]
464 * => left := middle
465 */
466 left_idx = middle_idx;
467 } 402 }
468 403
469 idx = left_idx; 404 events--;
470
471 if (!sym_table[idx].skip)
472 sym_table[idx].count[counter]++;
473 else events--;
474} 405}
475 406
476static void process_event(uint64_t ip, int counter) 407static void process_event(uint64_t ip, int counter)