diff options
Diffstat (limited to 'tools/perf/util')
83 files changed, 2022 insertions, 948 deletions
diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c index e6d134773d0a..c0b43ee40d95 100644 --- a/tools/perf/util/alias.c +++ b/tools/perf/util/alias.c | |||
@@ -55,8 +55,7 @@ int split_cmdline(char *cmdline, const char ***argv) | |||
55 | src++; | 55 | src++; |
56 | c = cmdline[src]; | 56 | c = cmdline[src]; |
57 | if (!c) { | 57 | if (!c) { |
58 | free(*argv); | 58 | zfree(argv); |
59 | *argv = NULL; | ||
60 | return error("cmdline ends with \\"); | 59 | return error("cmdline ends with \\"); |
61 | } | 60 | } |
62 | } | 61 | } |
@@ -68,8 +67,7 @@ int split_cmdline(char *cmdline, const char ***argv) | |||
68 | cmdline[dst] = 0; | 67 | cmdline[dst] = 0; |
69 | 68 | ||
70 | if (quoted) { | 69 | if (quoted) { |
71 | free(*argv); | 70 | zfree(argv); |
72 | *argv = NULL; | ||
73 | return error("unclosed quote"); | 71 | return error("unclosed quote"); |
74 | } | 72 | } |
75 | 73 | ||
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index cf6242c92ee2..3aa555ff9d89 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -8,6 +8,8 @@ | |||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include "util.h" | 10 | #include "util.h" |
11 | #include "ui/ui.h" | ||
12 | #include "sort.h" | ||
11 | #include "build-id.h" | 13 | #include "build-id.h" |
12 | #include "color.h" | 14 | #include "color.h" |
13 | #include "cache.h" | 15 | #include "cache.h" |
@@ -26,10 +28,10 @@ static int disasm_line__parse(char *line, char **namep, char **rawp); | |||
26 | 28 | ||
27 | static void ins__delete(struct ins_operands *ops) | 29 | static void ins__delete(struct ins_operands *ops) |
28 | { | 30 | { |
29 | free(ops->source.raw); | 31 | zfree(&ops->source.raw); |
30 | free(ops->source.name); | 32 | zfree(&ops->source.name); |
31 | free(ops->target.raw); | 33 | zfree(&ops->target.raw); |
32 | free(ops->target.name); | 34 | zfree(&ops->target.name); |
33 | } | 35 | } |
34 | 36 | ||
35 | static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, | 37 | static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, |
@@ -185,8 +187,7 @@ static int lock__parse(struct ins_operands *ops) | |||
185 | return 0; | 187 | return 0; |
186 | 188 | ||
187 | out_free_ops: | 189 | out_free_ops: |
188 | free(ops->locked.ops); | 190 | zfree(&ops->locked.ops); |
189 | ops->locked.ops = NULL; | ||
190 | return 0; | 191 | return 0; |
191 | } | 192 | } |
192 | 193 | ||
@@ -205,9 +206,9 @@ static int lock__scnprintf(struct ins *ins, char *bf, size_t size, | |||
205 | 206 | ||
206 | static void lock__delete(struct ins_operands *ops) | 207 | static void lock__delete(struct ins_operands *ops) |
207 | { | 208 | { |
208 | free(ops->locked.ops); | 209 | zfree(&ops->locked.ops); |
209 | free(ops->target.raw); | 210 | zfree(&ops->target.raw); |
210 | free(ops->target.name); | 211 | zfree(&ops->target.name); |
211 | } | 212 | } |
212 | 213 | ||
213 | static struct ins_ops lock_ops = { | 214 | static struct ins_ops lock_ops = { |
@@ -256,8 +257,7 @@ static int mov__parse(struct ins_operands *ops) | |||
256 | return 0; | 257 | return 0; |
257 | 258 | ||
258 | out_free_source: | 259 | out_free_source: |
259 | free(ops->source.raw); | 260 | zfree(&ops->source.raw); |
260 | ops->source.raw = NULL; | ||
261 | return -1; | 261 | return -1; |
262 | } | 262 | } |
263 | 263 | ||
@@ -464,17 +464,12 @@ void symbol__annotate_zero_histograms(struct symbol *sym) | |||
464 | pthread_mutex_unlock(¬es->lock); | 464 | pthread_mutex_unlock(¬es->lock); |
465 | } | 465 | } |
466 | 466 | ||
467 | int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | 467 | static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, |
468 | int evidx, u64 addr) | 468 | struct annotation *notes, int evidx, u64 addr) |
469 | { | 469 | { |
470 | unsigned offset; | 470 | unsigned offset; |
471 | struct annotation *notes; | ||
472 | struct sym_hist *h; | 471 | struct sym_hist *h; |
473 | 472 | ||
474 | notes = symbol__annotation(sym); | ||
475 | if (notes->src == NULL) | ||
476 | return -ENOMEM; | ||
477 | |||
478 | pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); | 473 | pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); |
479 | 474 | ||
480 | if (addr < sym->start || addr > sym->end) | 475 | if (addr < sym->start || addr > sym->end) |
@@ -491,6 +486,33 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | |||
491 | return 0; | 486 | return 0; |
492 | } | 487 | } |
493 | 488 | ||
489 | static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | ||
490 | int evidx, u64 addr) | ||
491 | { | ||
492 | struct annotation *notes; | ||
493 | |||
494 | if (sym == NULL) | ||
495 | return 0; | ||
496 | |||
497 | notes = symbol__annotation(sym); | ||
498 | if (notes->src == NULL) { | ||
499 | if (symbol__alloc_hist(sym) < 0) | ||
500 | return -ENOMEM; | ||
501 | } | ||
502 | |||
503 | return __symbol__inc_addr_samples(sym, map, notes, evidx, addr); | ||
504 | } | ||
505 | |||
506 | int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx) | ||
507 | { | ||
508 | return symbol__inc_addr_samples(ams->sym, ams->map, evidx, ams->al_addr); | ||
509 | } | ||
510 | |||
511 | int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) | ||
512 | { | ||
513 | return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); | ||
514 | } | ||
515 | |||
494 | static void disasm_line__init_ins(struct disasm_line *dl) | 516 | static void disasm_line__init_ins(struct disasm_line *dl) |
495 | { | 517 | { |
496 | dl->ins = ins__find(dl->name); | 518 | dl->ins = ins__find(dl->name); |
@@ -538,8 +560,7 @@ static int disasm_line__parse(char *line, char **namep, char **rawp) | |||
538 | return 0; | 560 | return 0; |
539 | 561 | ||
540 | out_free_name: | 562 | out_free_name: |
541 | free(*namep); | 563 | zfree(namep); |
542 | *namep = NULL; | ||
543 | return -1; | 564 | return -1; |
544 | } | 565 | } |
545 | 566 | ||
@@ -564,7 +585,7 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privs | |||
564 | return dl; | 585 | return dl; |
565 | 586 | ||
566 | out_free_line: | 587 | out_free_line: |
567 | free(dl->line); | 588 | zfree(&dl->line); |
568 | out_delete: | 589 | out_delete: |
569 | free(dl); | 590 | free(dl); |
570 | return NULL; | 591 | return NULL; |
@@ -572,8 +593,8 @@ out_delete: | |||
572 | 593 | ||
573 | void disasm_line__free(struct disasm_line *dl) | 594 | void disasm_line__free(struct disasm_line *dl) |
574 | { | 595 | { |
575 | free(dl->line); | 596 | zfree(&dl->line); |
576 | free(dl->name); | 597 | zfree(&dl->name); |
577 | if (dl->ins && dl->ins->ops->free) | 598 | if (dl->ins && dl->ins->ops->free) |
578 | dl->ins->ops->free(&dl->ops); | 599 | dl->ins->ops->free(&dl->ops); |
579 | else | 600 | else |
@@ -900,7 +921,7 @@ fallback: | |||
900 | * cache, or is just a kallsyms file, well, lets hope that this | 921 | * cache, or is just a kallsyms file, well, lets hope that this |
901 | * DSO is the same as when 'perf record' ran. | 922 | * DSO is the same as when 'perf record' ran. |
902 | */ | 923 | */ |
903 | filename = dso->long_name; | 924 | filename = (char *)dso->long_name; |
904 | snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", | 925 | snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", |
905 | symbol_conf.symfs, filename); | 926 | symbol_conf.symfs, filename); |
906 | free_filename = false; | 927 | free_filename = false; |
@@ -1091,8 +1112,7 @@ static void symbol__free_source_line(struct symbol *sym, int len) | |||
1091 | src_line = (void *)src_line + sizeof_src_line; | 1112 | src_line = (void *)src_line + sizeof_src_line; |
1092 | } | 1113 | } |
1093 | 1114 | ||
1094 | free(notes->src->lines); | 1115 | zfree(¬es->src->lines); |
1095 | notes->src->lines = NULL; | ||
1096 | } | 1116 | } |
1097 | 1117 | ||
1098 | /* Get the filename:line for the colored entries */ | 1118 | /* Get the filename:line for the colored entries */ |
@@ -1376,3 +1396,13 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, | |||
1376 | 1396 | ||
1377 | return 0; | 1397 | return 0; |
1378 | } | 1398 | } |
1399 | |||
1400 | int hist_entry__annotate(struct hist_entry *he, size_t privsize) | ||
1401 | { | ||
1402 | return symbol__annotate(he->ms.sym, he->ms.map, privsize); | ||
1403 | } | ||
1404 | |||
1405 | bool ui__has_annotation(void) | ||
1406 | { | ||
1407 | return use_browser == 1 && sort__has_sym; | ||
1408 | } | ||
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 834b7b57b788..56ad4f5287de 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -132,12 +132,17 @@ static inline struct annotation *symbol__annotation(struct symbol *sym) | |||
132 | return &a->annotation; | 132 | return &a->annotation; |
133 | } | 133 | } |
134 | 134 | ||
135 | int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | 135 | int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx); |
136 | int evidx, u64 addr); | 136 | |
137 | int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr); | ||
138 | |||
137 | int symbol__alloc_hist(struct symbol *sym); | 139 | int symbol__alloc_hist(struct symbol *sym); |
138 | void symbol__annotate_zero_histograms(struct symbol *sym); | 140 | void symbol__annotate_zero_histograms(struct symbol *sym); |
139 | 141 | ||
140 | int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); | 142 | int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); |
143 | |||
144 | int hist_entry__annotate(struct hist_entry *he, size_t privsize); | ||
145 | |||
141 | int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); | 146 | int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); |
142 | int symbol__annotate_printf(struct symbol *sym, struct map *map, | 147 | int symbol__annotate_printf(struct symbol *sym, struct map *map, |
143 | struct perf_evsel *evsel, bool full_paths, | 148 | struct perf_evsel *evsel, bool full_paths, |
@@ -146,6 +151,8 @@ void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); | |||
146 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); | 151 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); |
147 | void disasm__purge(struct list_head *head); | 152 | void disasm__purge(struct list_head *head); |
148 | 153 | ||
154 | bool ui__has_annotation(void); | ||
155 | |||
149 | int symbol__tty_annotate(struct symbol *sym, struct map *map, | 156 | int symbol__tty_annotate(struct symbol *sym, struct map *map, |
150 | struct perf_evsel *evsel, bool print_lines, | 157 | struct perf_evsel *evsel, bool print_lines, |
151 | bool full_paths, int min_pcnt, int max_lines); | 158 | bool full_paths, int min_pcnt, int max_lines); |
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index a92770c98cc7..6baabe63182b 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c | |||
@@ -89,7 +89,7 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf) | |||
89 | return raw - build_id; | 89 | return raw - build_id; |
90 | } | 90 | } |
91 | 91 | ||
92 | char *dso__build_id_filename(struct dso *dso, char *bf, size_t size) | 92 | char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size) |
93 | { | 93 | { |
94 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | 94 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; |
95 | 95 | ||
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index 929f28a7c14d..845ef865eced 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h | |||
@@ -10,7 +10,7 @@ extern struct perf_tool build_id__mark_dso_hit_ops; | |||
10 | struct dso; | 10 | struct dso; |
11 | 11 | ||
12 | int build_id__sprintf(const u8 *build_id, int len, char *bf); | 12 | int build_id__sprintf(const u8 *build_id, int len, char *bf); |
13 | char *dso__build_id_filename(struct dso *dso, char *bf, size_t size); | 13 | char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size); |
14 | 14 | ||
15 | int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, | 15 | int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, |
16 | struct perf_sample *sample, struct perf_evsel *evsel, | 16 | struct perf_sample *sample, struct perf_evsel *evsel, |
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index e3970e3eaacf..8d9db454f1a9 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -15,8 +15,12 @@ | |||
15 | #include <errno.h> | 15 | #include <errno.h> |
16 | #include <math.h> | 16 | #include <math.h> |
17 | 17 | ||
18 | #include "asm/bug.h" | ||
19 | |||
18 | #include "hist.h" | 20 | #include "hist.h" |
19 | #include "util.h" | 21 | #include "util.h" |
22 | #include "sort.h" | ||
23 | #include "machine.h" | ||
20 | #include "callchain.h" | 24 | #include "callchain.h" |
21 | 25 | ||
22 | __thread struct callchain_cursor callchain_cursor; | 26 | __thread struct callchain_cursor callchain_cursor; |
@@ -356,19 +360,14 @@ append_chain_children(struct callchain_node *root, | |||
356 | /* lookup in childrens */ | 360 | /* lookup in childrens */ |
357 | while (*p) { | 361 | while (*p) { |
358 | s64 ret; | 362 | s64 ret; |
359 | struct callchain_list *cnode; | ||
360 | 363 | ||
361 | parent = *p; | 364 | parent = *p; |
362 | rnode = rb_entry(parent, struct callchain_node, rb_node_in); | 365 | rnode = rb_entry(parent, struct callchain_node, rb_node_in); |
363 | cnode = list_first_entry(&rnode->val, struct callchain_list, | ||
364 | list); | ||
365 | 366 | ||
366 | /* just check first entry */ | 367 | /* If at least first entry matches, rely to children */ |
367 | ret = match_chain(node, cnode); | 368 | ret = append_chain(rnode, cursor, period); |
368 | if (ret == 0) { | 369 | if (ret == 0) |
369 | append_chain(rnode, cursor, period); | ||
370 | goto inc_children_hit; | 370 | goto inc_children_hit; |
371 | } | ||
372 | 371 | ||
373 | if (ret < 0) | 372 | if (ret < 0) |
374 | p = &parent->rb_left; | 373 | p = &parent->rb_left; |
@@ -389,11 +388,11 @@ append_chain(struct callchain_node *root, | |||
389 | struct callchain_cursor *cursor, | 388 | struct callchain_cursor *cursor, |
390 | u64 period) | 389 | u64 period) |
391 | { | 390 | { |
392 | struct callchain_cursor_node *curr_snap = cursor->curr; | ||
393 | struct callchain_list *cnode; | 391 | struct callchain_list *cnode; |
394 | u64 start = cursor->pos; | 392 | u64 start = cursor->pos; |
395 | bool found = false; | 393 | bool found = false; |
396 | u64 matches; | 394 | u64 matches; |
395 | int cmp = 0; | ||
397 | 396 | ||
398 | /* | 397 | /* |
399 | * Lookup in the current node | 398 | * Lookup in the current node |
@@ -408,7 +407,8 @@ append_chain(struct callchain_node *root, | |||
408 | if (!node) | 407 | if (!node) |
409 | break; | 408 | break; |
410 | 409 | ||
411 | if (match_chain(node, cnode) != 0) | 410 | cmp = match_chain(node, cnode); |
411 | if (cmp) | ||
412 | break; | 412 | break; |
413 | 413 | ||
414 | found = true; | 414 | found = true; |
@@ -418,9 +418,8 @@ append_chain(struct callchain_node *root, | |||
418 | 418 | ||
419 | /* matches not, relay no the parent */ | 419 | /* matches not, relay no the parent */ |
420 | if (!found) { | 420 | if (!found) { |
421 | cursor->curr = curr_snap; | 421 | WARN_ONCE(!cmp, "Chain comparison error\n"); |
422 | cursor->pos = start; | 422 | return cmp; |
423 | return -1; | ||
424 | } | 423 | } |
425 | 424 | ||
426 | matches = cursor->pos - start; | 425 | matches = cursor->pos - start; |
@@ -531,3 +530,24 @@ int callchain_cursor_append(struct callchain_cursor *cursor, | |||
531 | 530 | ||
532 | return 0; | 531 | return 0; |
533 | } | 532 | } |
533 | |||
534 | int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent, | ||
535 | struct perf_evsel *evsel, struct addr_location *al, | ||
536 | int max_stack) | ||
537 | { | ||
538 | if (sample->callchain == NULL) | ||
539 | return 0; | ||
540 | |||
541 | if (symbol_conf.use_callchain || sort__has_parent) { | ||
542 | return machine__resolve_callchain(al->machine, evsel, al->thread, | ||
543 | sample, parent, al, max_stack); | ||
544 | } | ||
545 | return 0; | ||
546 | } | ||
547 | |||
548 | int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample) | ||
549 | { | ||
550 | if (!symbol_conf.use_callchain) | ||
551 | return 0; | ||
552 | return callchain_append(he->callchain, &callchain_cursor, sample->period); | ||
553 | } | ||
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 4f7f989876ec..8ad97e9b119f 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -145,10 +145,16 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor) | |||
145 | } | 145 | } |
146 | 146 | ||
147 | struct option; | 147 | struct option; |
148 | struct hist_entry; | ||
148 | 149 | ||
149 | int record_parse_callchain(const char *arg, struct perf_record_opts *opts); | 150 | int record_parse_callchain(const char *arg, struct record_opts *opts); |
150 | int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); | 151 | int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); |
151 | int record_callchain_opt(const struct option *opt, const char *arg, int unset); | 152 | int record_callchain_opt(const struct option *opt, const char *arg, int unset); |
152 | 153 | ||
154 | int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent, | ||
155 | struct perf_evsel *evsel, struct addr_location *al, | ||
156 | int max_stack); | ||
157 | int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample); | ||
158 | |||
153 | extern const char record_callchain_help[]; | 159 | extern const char record_callchain_help[]; |
154 | #endif /* __PERF_CALLCHAIN_H */ | 160 | #endif /* __PERF_CALLCHAIN_H */ |
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c index 96bbda1ddb83..88f7be399432 100644 --- a/tools/perf/util/cgroup.c +++ b/tools/perf/util/cgroup.c | |||
@@ -81,7 +81,7 @@ static int add_cgroup(struct perf_evlist *evlist, char *str) | |||
81 | /* | 81 | /* |
82 | * check if cgrp is already defined, if so we reuse it | 82 | * check if cgrp is already defined, if so we reuse it |
83 | */ | 83 | */ |
84 | list_for_each_entry(counter, &evlist->entries, node) { | 84 | evlist__for_each(evlist, counter) { |
85 | cgrp = counter->cgrp; | 85 | cgrp = counter->cgrp; |
86 | if (!cgrp) | 86 | if (!cgrp) |
87 | continue; | 87 | continue; |
@@ -110,7 +110,7 @@ static int add_cgroup(struct perf_evlist *evlist, char *str) | |||
110 | * if add cgroup N, then need to find event N | 110 | * if add cgroup N, then need to find event N |
111 | */ | 111 | */ |
112 | n = 0; | 112 | n = 0; |
113 | list_for_each_entry(counter, &evlist->entries, node) { | 113 | evlist__for_each(evlist, counter) { |
114 | if (n == nr_cgroups) | 114 | if (n == nr_cgroups) |
115 | goto found; | 115 | goto found; |
116 | n++; | 116 | n++; |
@@ -133,7 +133,7 @@ void close_cgroup(struct cgroup_sel *cgrp) | |||
133 | /* XXX: not reentrant */ | 133 | /* XXX: not reentrant */ |
134 | if (--cgrp->refcnt == 0) { | 134 | if (--cgrp->refcnt == 0) { |
135 | close(cgrp->fd); | 135 | close(cgrp->fd); |
136 | free(cgrp->name); | 136 | zfree(&cgrp->name); |
137 | free(cgrp); | 137 | free(cgrp); |
138 | } | 138 | } |
139 | } | 139 | } |
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index 66e44a5019d5..87b8672eb413 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include <linux/kernel.h> | 1 | #include <linux/kernel.h> |
2 | #include "cache.h" | 2 | #include "cache.h" |
3 | #include "color.h" | 3 | #include "color.h" |
4 | #include <math.h> | ||
4 | 5 | ||
5 | int perf_use_color_default = -1; | 6 | int perf_use_color_default = -1; |
6 | 7 | ||
@@ -298,10 +299,10 @@ const char *get_percent_color(double percent) | |||
298 | * entries in green - and keep the low overhead places | 299 | * entries in green - and keep the low overhead places |
299 | * normal: | 300 | * normal: |
300 | */ | 301 | */ |
301 | if (percent >= MIN_RED) | 302 | if (fabs(percent) >= MIN_RED) |
302 | color = PERF_COLOR_RED; | 303 | color = PERF_COLOR_RED; |
303 | else { | 304 | else { |
304 | if (percent > MIN_GREEN) | 305 | if (fabs(percent) > MIN_GREEN) |
305 | color = PERF_COLOR_GREEN; | 306 | color = PERF_COLOR_GREEN; |
306 | } | 307 | } |
307 | return color; | 308 | return color; |
@@ -318,15 +319,19 @@ int percent_color_fprintf(FILE *fp, const char *fmt, double percent) | |||
318 | return r; | 319 | return r; |
319 | } | 320 | } |
320 | 321 | ||
322 | int value_color_snprintf(char *bf, size_t size, const char *fmt, double value) | ||
323 | { | ||
324 | const char *color = get_percent_color(value); | ||
325 | return color_snprintf(bf, size, color, fmt, value); | ||
326 | } | ||
327 | |||
321 | int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...) | 328 | int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...) |
322 | { | 329 | { |
323 | va_list args; | 330 | va_list args; |
324 | double percent; | 331 | double percent; |
325 | const char *color; | ||
326 | 332 | ||
327 | va_start(args, fmt); | 333 | va_start(args, fmt); |
328 | percent = va_arg(args, double); | 334 | percent = va_arg(args, double); |
329 | va_end(args); | 335 | va_end(args); |
330 | color = get_percent_color(percent); | 336 | return value_color_snprintf(bf, size, fmt, percent); |
331 | return color_snprintf(bf, size, color, fmt, percent); | ||
332 | } | 337 | } |
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h index fced3840e99c..7ff30a62a132 100644 --- a/tools/perf/util/color.h +++ b/tools/perf/util/color.h | |||
@@ -39,6 +39,7 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); | |||
39 | int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...); | 39 | int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...); |
40 | int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); | 40 | int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); |
41 | int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); | 41 | int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); |
42 | int value_color_snprintf(char *bf, size_t size, const char *fmt, double value); | ||
42 | int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...); | 43 | int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...); |
43 | int percent_color_fprintf(FILE *fp, const char *fmt, double percent); | 44 | int percent_color_fprintf(FILE *fp, const char *fmt, double percent); |
44 | const char *get_percent_color(double percent); | 45 | const char *get_percent_color(double percent); |
diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c index ee0df0e24cdb..f9e777629e21 100644 --- a/tools/perf/util/comm.c +++ b/tools/perf/util/comm.c | |||
@@ -21,7 +21,7 @@ static void comm_str__put(struct comm_str *cs) | |||
21 | { | 21 | { |
22 | if (!--cs->ref) { | 22 | if (!--cs->ref) { |
23 | rb_erase(&cs->rb_node, &comm_str_root); | 23 | rb_erase(&cs->rb_node, &comm_str_root); |
24 | free(cs->str); | 24 | zfree(&cs->str); |
25 | free(cs); | 25 | free(cs); |
26 | } | 26 | } |
27 | } | 27 | } |
@@ -94,19 +94,20 @@ struct comm *comm__new(const char *str, u64 timestamp) | |||
94 | return comm; | 94 | return comm; |
95 | } | 95 | } |
96 | 96 | ||
97 | void comm__override(struct comm *comm, const char *str, u64 timestamp) | 97 | int comm__override(struct comm *comm, const char *str, u64 timestamp) |
98 | { | 98 | { |
99 | struct comm_str *old = comm->comm_str; | 99 | struct comm_str *new, *old = comm->comm_str; |
100 | 100 | ||
101 | comm->comm_str = comm_str__findnew(str, &comm_str_root); | 101 | new = comm_str__findnew(str, &comm_str_root); |
102 | if (!comm->comm_str) { | 102 | if (!new) |
103 | comm->comm_str = old; | 103 | return -ENOMEM; |
104 | return; | ||
105 | } | ||
106 | 104 | ||
107 | comm->start = timestamp; | 105 | comm_str__get(new); |
108 | comm_str__get(comm->comm_str); | ||
109 | comm_str__put(old); | 106 | comm_str__put(old); |
107 | comm->comm_str = new; | ||
108 | comm->start = timestamp; | ||
109 | |||
110 | return 0; | ||
110 | } | 111 | } |
111 | 112 | ||
112 | void comm__free(struct comm *comm) | 113 | void comm__free(struct comm *comm) |
diff --git a/tools/perf/util/comm.h b/tools/perf/util/comm.h index 7a86e5656710..fac5bd51befc 100644 --- a/tools/perf/util/comm.h +++ b/tools/perf/util/comm.h | |||
@@ -16,6 +16,6 @@ struct comm { | |||
16 | void comm__free(struct comm *comm); | 16 | void comm__free(struct comm *comm); |
17 | struct comm *comm__new(const char *str, u64 timestamp); | 17 | struct comm *comm__new(const char *str, u64 timestamp); |
18 | const char *comm__str(const struct comm *comm); | 18 | const char *comm__str(const struct comm *comm); |
19 | void comm__override(struct comm *comm, const char *str, u64 timestamp); | 19 | int comm__override(struct comm *comm, const char *str, u64 timestamp); |
20 | 20 | ||
21 | #endif /* __PERF_COMM_H */ | 21 | #endif /* __PERF_COMM_H */ |
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c index 7d09faf85cf1..1fbcd8bdc11b 100644 --- a/tools/perf/util/data.c +++ b/tools/perf/util/data.c | |||
@@ -118,3 +118,9 @@ void perf_data_file__close(struct perf_data_file *file) | |||
118 | { | 118 | { |
119 | close(file->fd); | 119 | close(file->fd); |
120 | } | 120 | } |
121 | |||
122 | ssize_t perf_data_file__write(struct perf_data_file *file, | ||
123 | void *buf, size_t size) | ||
124 | { | ||
125 | return writen(file->fd, buf, size); | ||
126 | } | ||
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h index 8c2df80152a5..2b15d0c95c7f 100644 --- a/tools/perf/util/data.h +++ b/tools/perf/util/data.h | |||
@@ -9,12 +9,12 @@ enum perf_data_mode { | |||
9 | }; | 9 | }; |
10 | 10 | ||
11 | struct perf_data_file { | 11 | struct perf_data_file { |
12 | const char *path; | 12 | const char *path; |
13 | int fd; | 13 | int fd; |
14 | bool is_pipe; | 14 | bool is_pipe; |
15 | bool force; | 15 | bool force; |
16 | unsigned long size; | 16 | unsigned long size; |
17 | enum perf_data_mode mode; | 17 | enum perf_data_mode mode; |
18 | }; | 18 | }; |
19 | 19 | ||
20 | static inline bool perf_data_file__is_read(struct perf_data_file *file) | 20 | static inline bool perf_data_file__is_read(struct perf_data_file *file) |
@@ -44,5 +44,7 @@ static inline unsigned long perf_data_file__size(struct perf_data_file *file) | |||
44 | 44 | ||
45 | int perf_data_file__open(struct perf_data_file *file); | 45 | int perf_data_file__open(struct perf_data_file *file); |
46 | void perf_data_file__close(struct perf_data_file *file); | 46 | void perf_data_file__close(struct perf_data_file *file); |
47 | ssize_t perf_data_file__write(struct perf_data_file *file, | ||
48 | void *buf, size_t size); | ||
47 | 49 | ||
48 | #endif /* __PERF_DATA_H */ | 50 | #endif /* __PERF_DATA_H */ |
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 399e74c34c1a..299b55586502 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
@@ -16,23 +16,46 @@ | |||
16 | int verbose; | 16 | int verbose; |
17 | bool dump_trace = false, quiet = false; | 17 | bool dump_trace = false, quiet = false; |
18 | 18 | ||
19 | int eprintf(int level, const char *fmt, ...) | 19 | static int _eprintf(int level, const char *fmt, va_list args) |
20 | { | 20 | { |
21 | va_list args; | ||
22 | int ret = 0; | 21 | int ret = 0; |
23 | 22 | ||
24 | if (verbose >= level) { | 23 | if (verbose >= level) { |
25 | va_start(args, fmt); | ||
26 | if (use_browser >= 1) | 24 | if (use_browser >= 1) |
27 | ui_helpline__vshow(fmt, args); | 25 | ui_helpline__vshow(fmt, args); |
28 | else | 26 | else |
29 | ret = vfprintf(stderr, fmt, args); | 27 | ret = vfprintf(stderr, fmt, args); |
30 | va_end(args); | ||
31 | } | 28 | } |
32 | 29 | ||
33 | return ret; | 30 | return ret; |
34 | } | 31 | } |
35 | 32 | ||
33 | int eprintf(int level, const char *fmt, ...) | ||
34 | { | ||
35 | va_list args; | ||
36 | int ret; | ||
37 | |||
38 | va_start(args, fmt); | ||
39 | ret = _eprintf(level, fmt, args); | ||
40 | va_end(args); | ||
41 | |||
42 | return ret; | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * Overloading libtraceevent standard info print | ||
47 | * function, display with -v in perf. | ||
48 | */ | ||
49 | void pr_stat(const char *fmt, ...) | ||
50 | { | ||
51 | va_list args; | ||
52 | |||
53 | va_start(args, fmt); | ||
54 | _eprintf(1, fmt, args); | ||
55 | va_end(args); | ||
56 | eprintf(1, "\n"); | ||
57 | } | ||
58 | |||
36 | int dump_printf(const char *fmt, ...) | 59 | int dump_printf(const char *fmt, ...) |
37 | { | 60 | { |
38 | va_list args; | 61 | va_list args; |
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index efbd98805ad0..443694c36b03 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
@@ -17,4 +17,6 @@ void trace_event(union perf_event *event); | |||
17 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | 17 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); |
18 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | 18 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); |
19 | 19 | ||
20 | void pr_stat(const char *fmt, ...); | ||
21 | |||
20 | #endif /* __PERF_DEBUG_H */ | 22 | #endif /* __PERF_DEBUG_H */ |
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index af4c687cc49b..4045d086d9d9 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
@@ -28,8 +28,9 @@ char dso__symtab_origin(const struct dso *dso) | |||
28 | return origin[dso->symtab_type]; | 28 | return origin[dso->symtab_type]; |
29 | } | 29 | } |
30 | 30 | ||
31 | int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | 31 | int dso__read_binary_type_filename(const struct dso *dso, |
32 | char *root_dir, char *file, size_t size) | 32 | enum dso_binary_type type, |
33 | char *root_dir, char *filename, size_t size) | ||
33 | { | 34 | { |
34 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | 35 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; |
35 | int ret = 0; | 36 | int ret = 0; |
@@ -38,36 +39,36 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | |||
38 | case DSO_BINARY_TYPE__DEBUGLINK: { | 39 | case DSO_BINARY_TYPE__DEBUGLINK: { |
39 | char *debuglink; | 40 | char *debuglink; |
40 | 41 | ||
41 | strncpy(file, dso->long_name, size); | 42 | strncpy(filename, dso->long_name, size); |
42 | debuglink = file + dso->long_name_len; | 43 | debuglink = filename + dso->long_name_len; |
43 | while (debuglink != file && *debuglink != '/') | 44 | while (debuglink != filename && *debuglink != '/') |
44 | debuglink--; | 45 | debuglink--; |
45 | if (*debuglink == '/') | 46 | if (*debuglink == '/') |
46 | debuglink++; | 47 | debuglink++; |
47 | filename__read_debuglink(dso->long_name, debuglink, | 48 | filename__read_debuglink(dso->long_name, debuglink, |
48 | size - (debuglink - file)); | 49 | size - (debuglink - filename)); |
49 | } | 50 | } |
50 | break; | 51 | break; |
51 | case DSO_BINARY_TYPE__BUILD_ID_CACHE: | 52 | case DSO_BINARY_TYPE__BUILD_ID_CACHE: |
52 | /* skip the locally configured cache if a symfs is given */ | 53 | /* skip the locally configured cache if a symfs is given */ |
53 | if (symbol_conf.symfs[0] || | 54 | if (symbol_conf.symfs[0] || |
54 | (dso__build_id_filename(dso, file, size) == NULL)) | 55 | (dso__build_id_filename(dso, filename, size) == NULL)) |
55 | ret = -1; | 56 | ret = -1; |
56 | break; | 57 | break; |
57 | 58 | ||
58 | case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: | 59 | case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: |
59 | snprintf(file, size, "%s/usr/lib/debug%s.debug", | 60 | snprintf(filename, size, "%s/usr/lib/debug%s.debug", |
60 | symbol_conf.symfs, dso->long_name); | 61 | symbol_conf.symfs, dso->long_name); |
61 | break; | 62 | break; |
62 | 63 | ||
63 | case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: | 64 | case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: |
64 | snprintf(file, size, "%s/usr/lib/debug%s", | 65 | snprintf(filename, size, "%s/usr/lib/debug%s", |
65 | symbol_conf.symfs, dso->long_name); | 66 | symbol_conf.symfs, dso->long_name); |
66 | break; | 67 | break; |
67 | 68 | ||
68 | case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: | 69 | case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: |
69 | { | 70 | { |
70 | char *last_slash; | 71 | const char *last_slash; |
71 | size_t len; | 72 | size_t len; |
72 | size_t dir_size; | 73 | size_t dir_size; |
73 | 74 | ||
@@ -75,14 +76,14 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | |||
75 | while (last_slash != dso->long_name && *last_slash != '/') | 76 | while (last_slash != dso->long_name && *last_slash != '/') |
76 | last_slash--; | 77 | last_slash--; |
77 | 78 | ||
78 | len = scnprintf(file, size, "%s", symbol_conf.symfs); | 79 | len = scnprintf(filename, size, "%s", symbol_conf.symfs); |
79 | dir_size = last_slash - dso->long_name + 2; | 80 | dir_size = last_slash - dso->long_name + 2; |
80 | if (dir_size > (size - len)) { | 81 | if (dir_size > (size - len)) { |
81 | ret = -1; | 82 | ret = -1; |
82 | break; | 83 | break; |
83 | } | 84 | } |
84 | len += scnprintf(file + len, dir_size, "%s", dso->long_name); | 85 | len += scnprintf(filename + len, dir_size, "%s", dso->long_name); |
85 | len += scnprintf(file + len , size - len, ".debug%s", | 86 | len += scnprintf(filename + len , size - len, ".debug%s", |
86 | last_slash); | 87 | last_slash); |
87 | break; | 88 | break; |
88 | } | 89 | } |
@@ -96,7 +97,7 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | |||
96 | build_id__sprintf(dso->build_id, | 97 | build_id__sprintf(dso->build_id, |
97 | sizeof(dso->build_id), | 98 | sizeof(dso->build_id), |
98 | build_id_hex); | 99 | build_id_hex); |
99 | snprintf(file, size, | 100 | snprintf(filename, size, |
100 | "%s/usr/lib/debug/.build-id/%.2s/%s.debug", | 101 | "%s/usr/lib/debug/.build-id/%.2s/%s.debug", |
101 | symbol_conf.symfs, build_id_hex, build_id_hex + 2); | 102 | symbol_conf.symfs, build_id_hex, build_id_hex + 2); |
102 | break; | 103 | break; |
@@ -104,23 +105,23 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | |||
104 | case DSO_BINARY_TYPE__VMLINUX: | 105 | case DSO_BINARY_TYPE__VMLINUX: |
105 | case DSO_BINARY_TYPE__GUEST_VMLINUX: | 106 | case DSO_BINARY_TYPE__GUEST_VMLINUX: |
106 | case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: | 107 | case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: |
107 | snprintf(file, size, "%s%s", | 108 | snprintf(filename, size, "%s%s", |
108 | symbol_conf.symfs, dso->long_name); | 109 | symbol_conf.symfs, dso->long_name); |
109 | break; | 110 | break; |
110 | 111 | ||
111 | case DSO_BINARY_TYPE__GUEST_KMODULE: | 112 | case DSO_BINARY_TYPE__GUEST_KMODULE: |
112 | snprintf(file, size, "%s%s%s", symbol_conf.symfs, | 113 | snprintf(filename, size, "%s%s%s", symbol_conf.symfs, |
113 | root_dir, dso->long_name); | 114 | root_dir, dso->long_name); |
114 | break; | 115 | break; |
115 | 116 | ||
116 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: | 117 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: |
117 | snprintf(file, size, "%s%s", symbol_conf.symfs, | 118 | snprintf(filename, size, "%s%s", symbol_conf.symfs, |
118 | dso->long_name); | 119 | dso->long_name); |
119 | break; | 120 | break; |
120 | 121 | ||
121 | case DSO_BINARY_TYPE__KCORE: | 122 | case DSO_BINARY_TYPE__KCORE: |
122 | case DSO_BINARY_TYPE__GUEST_KCORE: | 123 | case DSO_BINARY_TYPE__GUEST_KCORE: |
123 | snprintf(file, size, "%s", dso->long_name); | 124 | snprintf(filename, size, "%s", dso->long_name); |
124 | break; | 125 | break; |
125 | 126 | ||
126 | default: | 127 | default: |
@@ -137,19 +138,18 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | |||
137 | 138 | ||
138 | static int open_dso(struct dso *dso, struct machine *machine) | 139 | static int open_dso(struct dso *dso, struct machine *machine) |
139 | { | 140 | { |
140 | char *root_dir = (char *) ""; | ||
141 | char *name; | ||
142 | int fd; | 141 | int fd; |
142 | char *root_dir = (char *)""; | ||
143 | char *name = malloc(PATH_MAX); | ||
143 | 144 | ||
144 | name = malloc(PATH_MAX); | ||
145 | if (!name) | 145 | if (!name) |
146 | return -ENOMEM; | 146 | return -ENOMEM; |
147 | 147 | ||
148 | if (machine) | 148 | if (machine) |
149 | root_dir = machine->root_dir; | 149 | root_dir = machine->root_dir; |
150 | 150 | ||
151 | if (dso__binary_type_file(dso, dso->data_type, | 151 | if (dso__read_binary_type_filename(dso, dso->binary_type, |
152 | root_dir, name, PATH_MAX)) { | 152 | root_dir, name, PATH_MAX)) { |
153 | free(name); | 153 | free(name); |
154 | return -EINVAL; | 154 | return -EINVAL; |
155 | } | 155 | } |
@@ -161,26 +161,26 @@ static int open_dso(struct dso *dso, struct machine *machine) | |||
161 | 161 | ||
162 | int dso__data_fd(struct dso *dso, struct machine *machine) | 162 | int dso__data_fd(struct dso *dso, struct machine *machine) |
163 | { | 163 | { |
164 | static enum dso_binary_type binary_type_data[] = { | 164 | enum dso_binary_type binary_type_data[] = { |
165 | DSO_BINARY_TYPE__BUILD_ID_CACHE, | 165 | DSO_BINARY_TYPE__BUILD_ID_CACHE, |
166 | DSO_BINARY_TYPE__SYSTEM_PATH_DSO, | 166 | DSO_BINARY_TYPE__SYSTEM_PATH_DSO, |
167 | DSO_BINARY_TYPE__NOT_FOUND, | 167 | DSO_BINARY_TYPE__NOT_FOUND, |
168 | }; | 168 | }; |
169 | int i = 0; | 169 | int i = 0; |
170 | 170 | ||
171 | if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND) | 171 | if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) |
172 | return open_dso(dso, machine); | 172 | return open_dso(dso, machine); |
173 | 173 | ||
174 | do { | 174 | do { |
175 | int fd; | 175 | int fd; |
176 | 176 | ||
177 | dso->data_type = binary_type_data[i++]; | 177 | dso->binary_type = binary_type_data[i++]; |
178 | 178 | ||
179 | fd = open_dso(dso, machine); | 179 | fd = open_dso(dso, machine); |
180 | if (fd >= 0) | 180 | if (fd >= 0) |
181 | return fd; | 181 | return fd; |
182 | 182 | ||
183 | } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND); | 183 | } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND); |
184 | 184 | ||
185 | return -EINVAL; | 185 | return -EINVAL; |
186 | } | 186 | } |
@@ -200,11 +200,10 @@ dso_cache__free(struct rb_root *root) | |||
200 | } | 200 | } |
201 | } | 201 | } |
202 | 202 | ||
203 | static struct dso_cache* | 203 | static struct dso_cache *dso_cache__find(const struct rb_root *root, u64 offset) |
204 | dso_cache__find(struct rb_root *root, u64 offset) | ||
205 | { | 204 | { |
206 | struct rb_node **p = &root->rb_node; | 205 | struct rb_node * const *p = &root->rb_node; |
207 | struct rb_node *parent = NULL; | 206 | const struct rb_node *parent = NULL; |
208 | struct dso_cache *cache; | 207 | struct dso_cache *cache; |
209 | 208 | ||
210 | while (*p != NULL) { | 209 | while (*p != NULL) { |
@@ -379,32 +378,63 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name, | |||
379 | * processing we had no idea this was the kernel dso. | 378 | * processing we had no idea this was the kernel dso. |
380 | */ | 379 | */ |
381 | if (dso != NULL) { | 380 | if (dso != NULL) { |
382 | dso__set_short_name(dso, short_name); | 381 | dso__set_short_name(dso, short_name, false); |
383 | dso->kernel = dso_type; | 382 | dso->kernel = dso_type; |
384 | } | 383 | } |
385 | 384 | ||
386 | return dso; | 385 | return dso; |
387 | } | 386 | } |
388 | 387 | ||
389 | void dso__set_long_name(struct dso *dso, char *name) | 388 | void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) |
390 | { | 389 | { |
391 | if (name == NULL) | 390 | if (name == NULL) |
392 | return; | 391 | return; |
393 | dso->long_name = name; | 392 | |
394 | dso->long_name_len = strlen(name); | 393 | if (dso->long_name_allocated) |
394 | free((char *)dso->long_name); | ||
395 | |||
396 | dso->long_name = name; | ||
397 | dso->long_name_len = strlen(name); | ||
398 | dso->long_name_allocated = name_allocated; | ||
395 | } | 399 | } |
396 | 400 | ||
397 | void dso__set_short_name(struct dso *dso, const char *name) | 401 | void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated) |
398 | { | 402 | { |
399 | if (name == NULL) | 403 | if (name == NULL) |
400 | return; | 404 | return; |
401 | dso->short_name = name; | 405 | |
402 | dso->short_name_len = strlen(name); | 406 | if (dso->short_name_allocated) |
407 | free((char *)dso->short_name); | ||
408 | |||
409 | dso->short_name = name; | ||
410 | dso->short_name_len = strlen(name); | ||
411 | dso->short_name_allocated = name_allocated; | ||
403 | } | 412 | } |
404 | 413 | ||
405 | static void dso__set_basename(struct dso *dso) | 414 | static void dso__set_basename(struct dso *dso) |
406 | { | 415 | { |
407 | dso__set_short_name(dso, basename(dso->long_name)); | 416 | /* |
417 | * basename() may modify path buffer, so we must pass | ||
418 | * a copy. | ||
419 | */ | ||
420 | char *base, *lname = strdup(dso->long_name); | ||
421 | |||
422 | if (!lname) | ||
423 | return; | ||
424 | |||
425 | /* | ||
426 | * basename() may return a pointer to internal | ||
427 | * storage which is reused in subsequent calls | ||
428 | * so copy the result. | ||
429 | */ | ||
430 | base = strdup(basename(lname)); | ||
431 | |||
432 | free(lname); | ||
433 | |||
434 | if (!base) | ||
435 | return; | ||
436 | |||
437 | dso__set_short_name(dso, base, true); | ||
408 | } | 438 | } |
409 | 439 | ||
410 | int dso__name_len(const struct dso *dso) | 440 | int dso__name_len(const struct dso *dso) |
@@ -439,18 +469,19 @@ struct dso *dso__new(const char *name) | |||
439 | if (dso != NULL) { | 469 | if (dso != NULL) { |
440 | int i; | 470 | int i; |
441 | strcpy(dso->name, name); | 471 | strcpy(dso->name, name); |
442 | dso__set_long_name(dso, dso->name); | 472 | dso__set_long_name(dso, dso->name, false); |
443 | dso__set_short_name(dso, dso->name); | 473 | dso__set_short_name(dso, dso->name, false); |
444 | for (i = 0; i < MAP__NR_TYPES; ++i) | 474 | for (i = 0; i < MAP__NR_TYPES; ++i) |
445 | dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; | 475 | dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; |
446 | dso->cache = RB_ROOT; | 476 | dso->cache = RB_ROOT; |
447 | dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; | 477 | dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; |
448 | dso->data_type = DSO_BINARY_TYPE__NOT_FOUND; | 478 | dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; |
449 | dso->loaded = 0; | 479 | dso->loaded = 0; |
450 | dso->rel = 0; | 480 | dso->rel = 0; |
451 | dso->sorted_by_name = 0; | 481 | dso->sorted_by_name = 0; |
452 | dso->has_build_id = 0; | 482 | dso->has_build_id = 0; |
453 | dso->has_srcline = 1; | 483 | dso->has_srcline = 1; |
484 | dso->a2l_fails = 1; | ||
454 | dso->kernel = DSO_TYPE_USER; | 485 | dso->kernel = DSO_TYPE_USER; |
455 | dso->needs_swap = DSO_SWAP__UNSET; | 486 | dso->needs_swap = DSO_SWAP__UNSET; |
456 | INIT_LIST_HEAD(&dso->node); | 487 | INIT_LIST_HEAD(&dso->node); |
@@ -464,11 +495,20 @@ void dso__delete(struct dso *dso) | |||
464 | int i; | 495 | int i; |
465 | for (i = 0; i < MAP__NR_TYPES; ++i) | 496 | for (i = 0; i < MAP__NR_TYPES; ++i) |
466 | symbols__delete(&dso->symbols[i]); | 497 | symbols__delete(&dso->symbols[i]); |
467 | if (dso->sname_alloc) | 498 | |
468 | free((char *)dso->short_name); | 499 | if (dso->short_name_allocated) { |
469 | if (dso->lname_alloc) | 500 | zfree((char **)&dso->short_name); |
470 | free(dso->long_name); | 501 | dso->short_name_allocated = false; |
502 | } | ||
503 | |||
504 | if (dso->long_name_allocated) { | ||
505 | zfree((char **)&dso->long_name); | ||
506 | dso->long_name_allocated = false; | ||
507 | } | ||
508 | |||
471 | dso_cache__free(&dso->cache); | 509 | dso_cache__free(&dso->cache); |
510 | dso__free_a2l(dso); | ||
511 | zfree(&dso->symsrc_filename); | ||
472 | free(dso); | 512 | free(dso); |
473 | } | 513 | } |
474 | 514 | ||
@@ -543,7 +583,7 @@ void dsos__add(struct list_head *head, struct dso *dso) | |||
543 | list_add_tail(&dso->node, head); | 583 | list_add_tail(&dso->node, head); |
544 | } | 584 | } |
545 | 585 | ||
546 | struct dso *dsos__find(struct list_head *head, const char *name, bool cmp_short) | 586 | struct dso *dsos__find(const struct list_head *head, const char *name, bool cmp_short) |
547 | { | 587 | { |
548 | struct dso *pos; | 588 | struct dso *pos; |
549 | 589 | ||
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 9ac666abbe7e..cd7d6f078cdd 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h | |||
@@ -77,23 +77,26 @@ struct dso { | |||
77 | struct rb_root symbols[MAP__NR_TYPES]; | 77 | struct rb_root symbols[MAP__NR_TYPES]; |
78 | struct rb_root symbol_names[MAP__NR_TYPES]; | 78 | struct rb_root symbol_names[MAP__NR_TYPES]; |
79 | struct rb_root cache; | 79 | struct rb_root cache; |
80 | void *a2l; | ||
81 | char *symsrc_filename; | ||
82 | unsigned int a2l_fails; | ||
80 | enum dso_kernel_type kernel; | 83 | enum dso_kernel_type kernel; |
81 | enum dso_swap_type needs_swap; | 84 | enum dso_swap_type needs_swap; |
82 | enum dso_binary_type symtab_type; | 85 | enum dso_binary_type symtab_type; |
83 | enum dso_binary_type data_type; | 86 | enum dso_binary_type binary_type; |
84 | u8 adjust_symbols:1; | 87 | u8 adjust_symbols:1; |
85 | u8 has_build_id:1; | 88 | u8 has_build_id:1; |
86 | u8 has_srcline:1; | 89 | u8 has_srcline:1; |
87 | u8 hit:1; | 90 | u8 hit:1; |
88 | u8 annotate_warned:1; | 91 | u8 annotate_warned:1; |
89 | u8 sname_alloc:1; | 92 | u8 short_name_allocated:1; |
90 | u8 lname_alloc:1; | 93 | u8 long_name_allocated:1; |
91 | u8 sorted_by_name; | 94 | u8 sorted_by_name; |
92 | u8 loaded; | 95 | u8 loaded; |
93 | u8 rel; | 96 | u8 rel; |
94 | u8 build_id[BUILD_ID_SIZE]; | 97 | u8 build_id[BUILD_ID_SIZE]; |
95 | const char *short_name; | 98 | const char *short_name; |
96 | char *long_name; | 99 | const char *long_name; |
97 | u16 long_name_len; | 100 | u16 long_name_len; |
98 | u16 short_name_len; | 101 | u16 short_name_len; |
99 | char name[0]; | 102 | char name[0]; |
@@ -107,8 +110,8 @@ static inline void dso__set_loaded(struct dso *dso, enum map_type type) | |||
107 | struct dso *dso__new(const char *name); | 110 | struct dso *dso__new(const char *name); |
108 | void dso__delete(struct dso *dso); | 111 | void dso__delete(struct dso *dso); |
109 | 112 | ||
110 | void dso__set_short_name(struct dso *dso, const char *name); | 113 | void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated); |
111 | void dso__set_long_name(struct dso *dso, char *name); | 114 | void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated); |
112 | 115 | ||
113 | int dso__name_len(const struct dso *dso); | 116 | int dso__name_len(const struct dso *dso); |
114 | 117 | ||
@@ -125,8 +128,8 @@ void dso__read_running_kernel_build_id(struct dso *dso, | |||
125 | int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir); | 128 | int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir); |
126 | 129 | ||
127 | char dso__symtab_origin(const struct dso *dso); | 130 | char dso__symtab_origin(const struct dso *dso); |
128 | int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | 131 | int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type, |
129 | char *root_dir, char *file, size_t size); | 132 | char *root_dir, char *filename, size_t size); |
130 | 133 | ||
131 | int dso__data_fd(struct dso *dso, struct machine *machine); | 134 | int dso__data_fd(struct dso *dso, struct machine *machine); |
132 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, | 135 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, |
@@ -140,7 +143,7 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name, | |||
140 | const char *short_name, int dso_type); | 143 | const char *short_name, int dso_type); |
141 | 144 | ||
142 | void dsos__add(struct list_head *head, struct dso *dso); | 145 | void dsos__add(struct list_head *head, struct dso *dso); |
143 | struct dso *dsos__find(struct list_head *head, const char *name, | 146 | struct dso *dsos__find(const struct list_head *head, const char *name, |
144 | bool cmp_short); | 147 | bool cmp_short); |
145 | struct dso *__dsos__findnew(struct list_head *head, const char *name); | 148 | struct dso *__dsos__findnew(struct list_head *head, const char *name); |
146 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits); | 149 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits); |
@@ -156,14 +159,16 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp); | |||
156 | 159 | ||
157 | static inline bool dso__is_vmlinux(struct dso *dso) | 160 | static inline bool dso__is_vmlinux(struct dso *dso) |
158 | { | 161 | { |
159 | return dso->data_type == DSO_BINARY_TYPE__VMLINUX || | 162 | return dso->binary_type == DSO_BINARY_TYPE__VMLINUX || |
160 | dso->data_type == DSO_BINARY_TYPE__GUEST_VMLINUX; | 163 | dso->binary_type == DSO_BINARY_TYPE__GUEST_VMLINUX; |
161 | } | 164 | } |
162 | 165 | ||
163 | static inline bool dso__is_kcore(struct dso *dso) | 166 | static inline bool dso__is_kcore(struct dso *dso) |
164 | { | 167 | { |
165 | return dso->data_type == DSO_BINARY_TYPE__KCORE || | 168 | return dso->binary_type == DSO_BINARY_TYPE__KCORE || |
166 | dso->data_type == DSO_BINARY_TYPE__GUEST_KCORE; | 169 | dso->binary_type == DSO_BINARY_TYPE__GUEST_KCORE; |
167 | } | 170 | } |
168 | 171 | ||
172 | void dso__free_a2l(struct dso *dso); | ||
173 | |||
169 | #endif /* __PERF_DSO */ | 174 | #endif /* __PERF_DSO */ |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index bb788c109fe6..b0f3ca850e9e 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include "strlist.h" | 7 | #include "strlist.h" |
8 | #include "thread.h" | 8 | #include "thread.h" |
9 | #include "thread_map.h" | 9 | #include "thread_map.h" |
10 | #include "symbol/kallsyms.h" | ||
10 | 11 | ||
11 | static const char *perf_event__names[] = { | 12 | static const char *perf_event__names[] = { |
12 | [0] = "TOTAL", | 13 | [0] = "TOTAL", |
@@ -105,8 +106,12 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool, | |||
105 | 106 | ||
106 | memset(&event->comm, 0, sizeof(event->comm)); | 107 | memset(&event->comm, 0, sizeof(event->comm)); |
107 | 108 | ||
108 | tgid = perf_event__get_comm_tgid(pid, event->comm.comm, | 109 | if (machine__is_host(machine)) |
109 | sizeof(event->comm.comm)); | 110 | tgid = perf_event__get_comm_tgid(pid, event->comm.comm, |
111 | sizeof(event->comm.comm)); | ||
112 | else | ||
113 | tgid = machine->pid; | ||
114 | |||
110 | if (tgid < 0) | 115 | if (tgid < 0) |
111 | goto out; | 116 | goto out; |
112 | 117 | ||
@@ -128,7 +133,11 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool, | |||
128 | goto out; | 133 | goto out; |
129 | } | 134 | } |
130 | 135 | ||
131 | snprintf(filename, sizeof(filename), "/proc/%d/task", pid); | 136 | if (machine__is_default_guest(machine)) |
137 | return 0; | ||
138 | |||
139 | snprintf(filename, sizeof(filename), "%s/proc/%d/task", | ||
140 | machine->root_dir, pid); | ||
132 | 141 | ||
133 | tasks = opendir(filename); | 142 | tasks = opendir(filename); |
134 | if (tasks == NULL) { | 143 | if (tasks == NULL) { |
@@ -166,18 +175,22 @@ out: | |||
166 | return tgid; | 175 | return tgid; |
167 | } | 176 | } |
168 | 177 | ||
169 | static int perf_event__synthesize_mmap_events(struct perf_tool *tool, | 178 | int perf_event__synthesize_mmap_events(struct perf_tool *tool, |
170 | union perf_event *event, | 179 | union perf_event *event, |
171 | pid_t pid, pid_t tgid, | 180 | pid_t pid, pid_t tgid, |
172 | perf_event__handler_t process, | 181 | perf_event__handler_t process, |
173 | struct machine *machine, | 182 | struct machine *machine, |
174 | bool mmap_data) | 183 | bool mmap_data) |
175 | { | 184 | { |
176 | char filename[PATH_MAX]; | 185 | char filename[PATH_MAX]; |
177 | FILE *fp; | 186 | FILE *fp; |
178 | int rc = 0; | 187 | int rc = 0; |
179 | 188 | ||
180 | snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); | 189 | if (machine__is_default_guest(machine)) |
190 | return 0; | ||
191 | |||
192 | snprintf(filename, sizeof(filename), "%s/proc/%d/maps", | ||
193 | machine->root_dir, pid); | ||
181 | 194 | ||
182 | fp = fopen(filename, "r"); | 195 | fp = fopen(filename, "r"); |
183 | if (fp == NULL) { | 196 | if (fp == NULL) { |
@@ -217,7 +230,10 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, | |||
217 | /* | 230 | /* |
218 | * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c | 231 | * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c |
219 | */ | 232 | */ |
220 | event->header.misc = PERF_RECORD_MISC_USER; | 233 | if (machine__is_host(machine)) |
234 | event->header.misc = PERF_RECORD_MISC_USER; | ||
235 | else | ||
236 | event->header.misc = PERF_RECORD_MISC_GUEST_USER; | ||
221 | 237 | ||
222 | if (prot[2] != 'x') { | 238 | if (prot[2] != 'x') { |
223 | if (!mmap_data || prot[0] != 'r') | 239 | if (!mmap_data || prot[0] != 'r') |
@@ -386,6 +402,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
386 | struct machine *machine, bool mmap_data) | 402 | struct machine *machine, bool mmap_data) |
387 | { | 403 | { |
388 | DIR *proc; | 404 | DIR *proc; |
405 | char proc_path[PATH_MAX]; | ||
389 | struct dirent dirent, *next; | 406 | struct dirent dirent, *next; |
390 | union perf_event *comm_event, *mmap_event; | 407 | union perf_event *comm_event, *mmap_event; |
391 | int err = -1; | 408 | int err = -1; |
@@ -398,7 +415,12 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
398 | if (mmap_event == NULL) | 415 | if (mmap_event == NULL) |
399 | goto out_free_comm; | 416 | goto out_free_comm; |
400 | 417 | ||
401 | proc = opendir("/proc"); | 418 | if (machine__is_default_guest(machine)) |
419 | return 0; | ||
420 | |||
421 | snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir); | ||
422 | proc = opendir(proc_path); | ||
423 | |||
402 | if (proc == NULL) | 424 | if (proc == NULL) |
403 | goto out_free_mmap; | 425 | goto out_free_mmap; |
404 | 426 | ||
@@ -448,23 +470,32 @@ static int find_symbol_cb(void *arg, const char *name, char type, | |||
448 | return 1; | 470 | return 1; |
449 | } | 471 | } |
450 | 472 | ||
473 | u64 kallsyms__get_function_start(const char *kallsyms_filename, | ||
474 | const char *symbol_name) | ||
475 | { | ||
476 | struct process_symbol_args args = { .name = symbol_name, }; | ||
477 | |||
478 | if (kallsyms__parse(kallsyms_filename, &args, find_symbol_cb) <= 0) | ||
479 | return 0; | ||
480 | |||
481 | return args.start; | ||
482 | } | ||
483 | |||
451 | int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, | 484 | int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, |
452 | perf_event__handler_t process, | 485 | perf_event__handler_t process, |
453 | struct machine *machine, | 486 | struct machine *machine) |
454 | const char *symbol_name) | ||
455 | { | 487 | { |
456 | size_t size; | 488 | size_t size; |
457 | const char *filename, *mmap_name; | 489 | const char *mmap_name; |
458 | char path[PATH_MAX]; | ||
459 | char name_buff[PATH_MAX]; | 490 | char name_buff[PATH_MAX]; |
460 | struct map *map; | 491 | struct map *map; |
492 | struct kmap *kmap; | ||
461 | int err; | 493 | int err; |
462 | /* | 494 | /* |
463 | * We should get this from /sys/kernel/sections/.text, but till that is | 495 | * We should get this from /sys/kernel/sections/.text, but till that is |
464 | * available use this, and after it is use this as a fallback for older | 496 | * available use this, and after it is use this as a fallback for older |
465 | * kernels. | 497 | * kernels. |
466 | */ | 498 | */ |
467 | struct process_symbol_args args = { .name = symbol_name, }; | ||
468 | union perf_event *event = zalloc((sizeof(event->mmap) + | 499 | union perf_event *event = zalloc((sizeof(event->mmap) + |
469 | machine->id_hdr_size)); | 500 | machine->id_hdr_size)); |
470 | if (event == NULL) { | 501 | if (event == NULL) { |
@@ -480,30 +511,19 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, | |||
480 | * see kernel/perf_event.c __perf_event_mmap | 511 | * see kernel/perf_event.c __perf_event_mmap |
481 | */ | 512 | */ |
482 | event->header.misc = PERF_RECORD_MISC_KERNEL; | 513 | event->header.misc = PERF_RECORD_MISC_KERNEL; |
483 | filename = "/proc/kallsyms"; | ||
484 | } else { | 514 | } else { |
485 | event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; | 515 | event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; |
486 | if (machine__is_default_guest(machine)) | ||
487 | filename = (char *) symbol_conf.default_guest_kallsyms; | ||
488 | else { | ||
489 | sprintf(path, "%s/proc/kallsyms", machine->root_dir); | ||
490 | filename = path; | ||
491 | } | ||
492 | } | ||
493 | |||
494 | if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) { | ||
495 | free(event); | ||
496 | return -ENOENT; | ||
497 | } | 516 | } |
498 | 517 | ||
499 | map = machine->vmlinux_maps[MAP__FUNCTION]; | 518 | map = machine->vmlinux_maps[MAP__FUNCTION]; |
519 | kmap = map__kmap(map); | ||
500 | size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), | 520 | size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), |
501 | "%s%s", mmap_name, symbol_name) + 1; | 521 | "%s%s", mmap_name, kmap->ref_reloc_sym->name) + 1; |
502 | size = PERF_ALIGN(size, sizeof(u64)); | 522 | size = PERF_ALIGN(size, sizeof(u64)); |
503 | event->mmap.header.type = PERF_RECORD_MMAP; | 523 | event->mmap.header.type = PERF_RECORD_MMAP; |
504 | event->mmap.header.size = (sizeof(event->mmap) - | 524 | event->mmap.header.size = (sizeof(event->mmap) - |
505 | (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); | 525 | (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); |
506 | event->mmap.pgoff = args.start; | 526 | event->mmap.pgoff = kmap->ref_reloc_sym->addr; |
507 | event->mmap.start = map->start; | 527 | event->mmap.start = map->start; |
508 | event->mmap.len = map->end - event->mmap.start; | 528 | event->mmap.len = map->end - event->mmap.start; |
509 | event->mmap.pid = machine->pid; | 529 | event->mmap.pid = machine->pid; |
@@ -637,6 +657,7 @@ void thread__find_addr_map(struct thread *thread, | |||
637 | struct map_groups *mg = &thread->mg; | 657 | struct map_groups *mg = &thread->mg; |
638 | bool load_map = false; | 658 | bool load_map = false; |
639 | 659 | ||
660 | al->machine = machine; | ||
640 | al->thread = thread; | 661 | al->thread = thread; |
641 | al->addr = addr; | 662 | al->addr = addr; |
642 | al->cpumode = cpumode; | 663 | al->cpumode = cpumode; |
@@ -657,15 +678,10 @@ void thread__find_addr_map(struct thread *thread, | |||
657 | al->level = 'g'; | 678 | al->level = 'g'; |
658 | mg = &machine->kmaps; | 679 | mg = &machine->kmaps; |
659 | load_map = true; | 680 | load_map = true; |
681 | } else if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) { | ||
682 | al->level = 'u'; | ||
660 | } else { | 683 | } else { |
661 | /* | 684 | al->level = 'H'; |
662 | * 'u' means guest os user space. | ||
663 | * TODO: We don't support guest user space. Might support late. | ||
664 | */ | ||
665 | if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) | ||
666 | al->level = 'u'; | ||
667 | else | ||
668 | al->level = 'H'; | ||
669 | al->map = NULL; | 685 | al->map = NULL; |
670 | 686 | ||
671 | if ((cpumode == PERF_RECORD_MISC_GUEST_USER || | 687 | if ((cpumode == PERF_RECORD_MISC_GUEST_USER || |
@@ -732,8 +748,7 @@ int perf_event__preprocess_sample(const union perf_event *event, | |||
732 | if (thread == NULL) | 748 | if (thread == NULL) |
733 | return -1; | 749 | return -1; |
734 | 750 | ||
735 | if (symbol_conf.comm_list && | 751 | if (thread__is_filtered(thread)) |
736 | !strlist__has_entry(symbol_conf.comm_list, thread__comm_str(thread))) | ||
737 | goto out_filtered; | 752 | goto out_filtered; |
738 | 753 | ||
739 | dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid); | 754 | dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid); |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 30fec9901e44..851fa06f4a42 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -214,8 +214,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
214 | struct machine *machine, bool mmap_data); | 214 | struct machine *machine, bool mmap_data); |
215 | int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, | 215 | int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, |
216 | perf_event__handler_t process, | 216 | perf_event__handler_t process, |
217 | struct machine *machine, | 217 | struct machine *machine); |
218 | const char *symbol_name); | ||
219 | 218 | ||
220 | int perf_event__synthesize_modules(struct perf_tool *tool, | 219 | int perf_event__synthesize_modules(struct perf_tool *tool, |
221 | perf_event__handler_t process, | 220 | perf_event__handler_t process, |
@@ -266,10 +265,20 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, | |||
266 | const struct perf_sample *sample, | 265 | const struct perf_sample *sample, |
267 | bool swapped); | 266 | bool swapped); |
268 | 267 | ||
268 | int perf_event__synthesize_mmap_events(struct perf_tool *tool, | ||
269 | union perf_event *event, | ||
270 | pid_t pid, pid_t tgid, | ||
271 | perf_event__handler_t process, | ||
272 | struct machine *machine, | ||
273 | bool mmap_data); | ||
274 | |||
269 | size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); | 275 | size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); |
270 | size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); | 276 | size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); |
271 | size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp); | 277 | size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp); |
272 | size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); | 278 | size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); |
273 | size_t perf_event__fprintf(union perf_event *event, FILE *fp); | 279 | size_t perf_event__fprintf(union perf_event *event, FILE *fp); |
274 | 280 | ||
281 | u64 kallsyms__get_function_start(const char *kallsyms_filename, | ||
282 | const char *symbol_name); | ||
283 | |||
275 | #endif /* __PERF_RECORD_H */ | 284 | #endif /* __PERF_RECORD_H */ |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index bbc746aa5716..59ef2802fcf6 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * Released under the GPL v2. (and only v2, not any later version) | 7 | * Released under the GPL v2. (and only v2, not any later version) |
8 | */ | 8 | */ |
9 | #include "util.h" | 9 | #include "util.h" |
10 | #include <lk/debugfs.h> | 10 | #include <api/fs/debugfs.h> |
11 | #include <poll.h> | 11 | #include <poll.h> |
12 | #include "cpumap.h" | 12 | #include "cpumap.h" |
13 | #include "thread_map.h" | 13 | #include "thread_map.h" |
@@ -81,7 +81,7 @@ static void perf_evlist__update_id_pos(struct perf_evlist *evlist) | |||
81 | { | 81 | { |
82 | struct perf_evsel *evsel; | 82 | struct perf_evsel *evsel; |
83 | 83 | ||
84 | list_for_each_entry(evsel, &evlist->entries, node) | 84 | evlist__for_each(evlist, evsel) |
85 | perf_evsel__calc_id_pos(evsel); | 85 | perf_evsel__calc_id_pos(evsel); |
86 | 86 | ||
87 | perf_evlist__set_id_pos(evlist); | 87 | perf_evlist__set_id_pos(evlist); |
@@ -91,7 +91,7 @@ static void perf_evlist__purge(struct perf_evlist *evlist) | |||
91 | { | 91 | { |
92 | struct perf_evsel *pos, *n; | 92 | struct perf_evsel *pos, *n; |
93 | 93 | ||
94 | list_for_each_entry_safe(pos, n, &evlist->entries, node) { | 94 | evlist__for_each_safe(evlist, n, pos) { |
95 | list_del_init(&pos->node); | 95 | list_del_init(&pos->node); |
96 | perf_evsel__delete(pos); | 96 | perf_evsel__delete(pos); |
97 | } | 97 | } |
@@ -101,14 +101,18 @@ static void perf_evlist__purge(struct perf_evlist *evlist) | |||
101 | 101 | ||
102 | void perf_evlist__exit(struct perf_evlist *evlist) | 102 | void perf_evlist__exit(struct perf_evlist *evlist) |
103 | { | 103 | { |
104 | free(evlist->mmap); | 104 | zfree(&evlist->mmap); |
105 | free(evlist->pollfd); | 105 | zfree(&evlist->pollfd); |
106 | evlist->mmap = NULL; | ||
107 | evlist->pollfd = NULL; | ||
108 | } | 106 | } |
109 | 107 | ||
110 | void perf_evlist__delete(struct perf_evlist *evlist) | 108 | void perf_evlist__delete(struct perf_evlist *evlist) |
111 | { | 109 | { |
110 | perf_evlist__munmap(evlist); | ||
111 | perf_evlist__close(evlist); | ||
112 | cpu_map__delete(evlist->cpus); | ||
113 | thread_map__delete(evlist->threads); | ||
114 | evlist->cpus = NULL; | ||
115 | evlist->threads = NULL; | ||
112 | perf_evlist__purge(evlist); | 116 | perf_evlist__purge(evlist); |
113 | perf_evlist__exit(evlist); | 117 | perf_evlist__exit(evlist); |
114 | free(evlist); | 118 | free(evlist); |
@@ -144,7 +148,7 @@ void __perf_evlist__set_leader(struct list_head *list) | |||
144 | 148 | ||
145 | leader->nr_members = evsel->idx - leader->idx + 1; | 149 | leader->nr_members = evsel->idx - leader->idx + 1; |
146 | 150 | ||
147 | list_for_each_entry(evsel, list, node) { | 151 | __evlist__for_each(list, evsel) { |
148 | evsel->leader = leader; | 152 | evsel->leader = leader; |
149 | } | 153 | } |
150 | } | 154 | } |
@@ -203,7 +207,7 @@ static int perf_evlist__add_attrs(struct perf_evlist *evlist, | |||
203 | return 0; | 207 | return 0; |
204 | 208 | ||
205 | out_delete_partial_list: | 209 | out_delete_partial_list: |
206 | list_for_each_entry_safe(evsel, n, &head, node) | 210 | __evlist__for_each_safe(&head, n, evsel) |
207 | perf_evsel__delete(evsel); | 211 | perf_evsel__delete(evsel); |
208 | return -1; | 212 | return -1; |
209 | } | 213 | } |
@@ -224,7 +228,7 @@ perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) | |||
224 | { | 228 | { |
225 | struct perf_evsel *evsel; | 229 | struct perf_evsel *evsel; |
226 | 230 | ||
227 | list_for_each_entry(evsel, &evlist->entries, node) { | 231 | evlist__for_each(evlist, evsel) { |
228 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT && | 232 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT && |
229 | (int)evsel->attr.config == id) | 233 | (int)evsel->attr.config == id) |
230 | return evsel; | 234 | return evsel; |
@@ -239,7 +243,7 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist, | |||
239 | { | 243 | { |
240 | struct perf_evsel *evsel; | 244 | struct perf_evsel *evsel; |
241 | 245 | ||
242 | list_for_each_entry(evsel, &evlist->entries, node) { | 246 | evlist__for_each(evlist, evsel) { |
243 | if ((evsel->attr.type == PERF_TYPE_TRACEPOINT) && | 247 | if ((evsel->attr.type == PERF_TYPE_TRACEPOINT) && |
244 | (strcmp(evsel->name, name) == 0)) | 248 | (strcmp(evsel->name, name) == 0)) |
245 | return evsel; | 249 | return evsel; |
@@ -269,7 +273,7 @@ void perf_evlist__disable(struct perf_evlist *evlist) | |||
269 | int nr_threads = thread_map__nr(evlist->threads); | 273 | int nr_threads = thread_map__nr(evlist->threads); |
270 | 274 | ||
271 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 275 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
272 | list_for_each_entry(pos, &evlist->entries, node) { | 276 | evlist__for_each(evlist, pos) { |
273 | if (!perf_evsel__is_group_leader(pos) || !pos->fd) | 277 | if (!perf_evsel__is_group_leader(pos) || !pos->fd) |
274 | continue; | 278 | continue; |
275 | for (thread = 0; thread < nr_threads; thread++) | 279 | for (thread = 0; thread < nr_threads; thread++) |
@@ -287,7 +291,7 @@ void perf_evlist__enable(struct perf_evlist *evlist) | |||
287 | int nr_threads = thread_map__nr(evlist->threads); | 291 | int nr_threads = thread_map__nr(evlist->threads); |
288 | 292 | ||
289 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 293 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
290 | list_for_each_entry(pos, &evlist->entries, node) { | 294 | evlist__for_each(evlist, pos) { |
291 | if (!perf_evsel__is_group_leader(pos) || !pos->fd) | 295 | if (!perf_evsel__is_group_leader(pos) || !pos->fd) |
292 | continue; | 296 | continue; |
293 | for (thread = 0; thread < nr_threads; thread++) | 297 | for (thread = 0; thread < nr_threads; thread++) |
@@ -584,11 +588,13 @@ void perf_evlist__munmap(struct perf_evlist *evlist) | |||
584 | { | 588 | { |
585 | int i; | 589 | int i; |
586 | 590 | ||
591 | if (evlist->mmap == NULL) | ||
592 | return; | ||
593 | |||
587 | for (i = 0; i < evlist->nr_mmaps; i++) | 594 | for (i = 0; i < evlist->nr_mmaps; i++) |
588 | __perf_evlist__munmap(evlist, i); | 595 | __perf_evlist__munmap(evlist, i); |
589 | 596 | ||
590 | free(evlist->mmap); | 597 | zfree(&evlist->mmap); |
591 | evlist->mmap = NULL; | ||
592 | } | 598 | } |
593 | 599 | ||
594 | static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) | 600 | static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) |
@@ -624,7 +630,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, | |||
624 | { | 630 | { |
625 | struct perf_evsel *evsel; | 631 | struct perf_evsel *evsel; |
626 | 632 | ||
627 | list_for_each_entry(evsel, &evlist->entries, node) { | 633 | evlist__for_each(evlist, evsel) { |
628 | int fd = FD(evsel, cpu, thread); | 634 | int fd = FD(evsel, cpu, thread); |
629 | 635 | ||
630 | if (*output == -1) { | 636 | if (*output == -1) { |
@@ -732,11 +738,13 @@ static long parse_pages_arg(const char *str, unsigned long min, | |||
732 | return -EINVAL; | 738 | return -EINVAL; |
733 | } | 739 | } |
734 | 740 | ||
735 | if ((pages == 0) && (min == 0)) { | 741 | if (pages == 0 && min == 0) { |
736 | /* leave number of pages at 0 */ | 742 | /* leave number of pages at 0 */ |
737 | } else if (pages < (1UL << 31) && !is_power_of_2(pages)) { | 743 | } else if (!is_power_of_2(pages)) { |
738 | /* round pages up to next power of 2 */ | 744 | /* round pages up to next power of 2 */ |
739 | pages = next_pow2(pages); | 745 | pages = next_pow2_l(pages); |
746 | if (!pages) | ||
747 | return -EINVAL; | ||
740 | pr_info("rounding mmap pages size to %lu bytes (%lu pages)\n", | 748 | pr_info("rounding mmap pages size to %lu bytes (%lu pages)\n", |
741 | pages * page_size, pages); | 749 | pages * page_size, pages); |
742 | } | 750 | } |
@@ -754,7 +762,7 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str, | |||
754 | unsigned long max = UINT_MAX; | 762 | unsigned long max = UINT_MAX; |
755 | long pages; | 763 | long pages; |
756 | 764 | ||
757 | if (max < SIZE_MAX / page_size) | 765 | if (max > SIZE_MAX / page_size) |
758 | max = SIZE_MAX / page_size; | 766 | max = SIZE_MAX / page_size; |
759 | 767 | ||
760 | pages = parse_pages_arg(str, 1, max); | 768 | pages = parse_pages_arg(str, 1, max); |
@@ -798,7 +806,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, | |||
798 | pr_debug("mmap size %zuB\n", evlist->mmap_len); | 806 | pr_debug("mmap size %zuB\n", evlist->mmap_len); |
799 | mask = evlist->mmap_len - page_size - 1; | 807 | mask = evlist->mmap_len - page_size - 1; |
800 | 808 | ||
801 | list_for_each_entry(evsel, &evlist->entries, node) { | 809 | evlist__for_each(evlist, evsel) { |
802 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && | 810 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && |
803 | evsel->sample_id == NULL && | 811 | evsel->sample_id == NULL && |
804 | perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0) | 812 | perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0) |
@@ -819,11 +827,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) | |||
819 | if (evlist->threads == NULL) | 827 | if (evlist->threads == NULL) |
820 | return -1; | 828 | return -1; |
821 | 829 | ||
822 | if (target->force_per_cpu) | 830 | if (target__uses_dummy_map(target)) |
823 | evlist->cpus = cpu_map__new(target->cpu_list); | ||
824 | else if (target__has_task(target)) | ||
825 | evlist->cpus = cpu_map__dummy_new(); | ||
826 | else if (!target__has_cpu(target) && !target->uses_mmap) | ||
827 | evlist->cpus = cpu_map__dummy_new(); | 831 | evlist->cpus = cpu_map__dummy_new(); |
828 | else | 832 | else |
829 | evlist->cpus = cpu_map__new(target->cpu_list); | 833 | evlist->cpus = cpu_map__new(target->cpu_list); |
@@ -838,14 +842,6 @@ out_delete_threads: | |||
838 | return -1; | 842 | return -1; |
839 | } | 843 | } |
840 | 844 | ||
841 | void perf_evlist__delete_maps(struct perf_evlist *evlist) | ||
842 | { | ||
843 | cpu_map__delete(evlist->cpus); | ||
844 | thread_map__delete(evlist->threads); | ||
845 | evlist->cpus = NULL; | ||
846 | evlist->threads = NULL; | ||
847 | } | ||
848 | |||
849 | int perf_evlist__apply_filters(struct perf_evlist *evlist) | 845 | int perf_evlist__apply_filters(struct perf_evlist *evlist) |
850 | { | 846 | { |
851 | struct perf_evsel *evsel; | 847 | struct perf_evsel *evsel; |
@@ -853,7 +849,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist) | |||
853 | const int ncpus = cpu_map__nr(evlist->cpus), | 849 | const int ncpus = cpu_map__nr(evlist->cpus), |
854 | nthreads = thread_map__nr(evlist->threads); | 850 | nthreads = thread_map__nr(evlist->threads); |
855 | 851 | ||
856 | list_for_each_entry(evsel, &evlist->entries, node) { | 852 | evlist__for_each(evlist, evsel) { |
857 | if (evsel->filter == NULL) | 853 | if (evsel->filter == NULL) |
858 | continue; | 854 | continue; |
859 | 855 | ||
@@ -872,7 +868,7 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter) | |||
872 | const int ncpus = cpu_map__nr(evlist->cpus), | 868 | const int ncpus = cpu_map__nr(evlist->cpus), |
873 | nthreads = thread_map__nr(evlist->threads); | 869 | nthreads = thread_map__nr(evlist->threads); |
874 | 870 | ||
875 | list_for_each_entry(evsel, &evlist->entries, node) { | 871 | evlist__for_each(evlist, evsel) { |
876 | err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter); | 872 | err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter); |
877 | if (err) | 873 | if (err) |
878 | break; | 874 | break; |
@@ -891,7 +887,7 @@ bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) | |||
891 | if (evlist->id_pos < 0 || evlist->is_pos < 0) | 887 | if (evlist->id_pos < 0 || evlist->is_pos < 0) |
892 | return false; | 888 | return false; |
893 | 889 | ||
894 | list_for_each_entry(pos, &evlist->entries, node) { | 890 | evlist__for_each(evlist, pos) { |
895 | if (pos->id_pos != evlist->id_pos || | 891 | if (pos->id_pos != evlist->id_pos || |
896 | pos->is_pos != evlist->is_pos) | 892 | pos->is_pos != evlist->is_pos) |
897 | return false; | 893 | return false; |
@@ -907,7 +903,7 @@ u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist) | |||
907 | if (evlist->combined_sample_type) | 903 | if (evlist->combined_sample_type) |
908 | return evlist->combined_sample_type; | 904 | return evlist->combined_sample_type; |
909 | 905 | ||
910 | list_for_each_entry(evsel, &evlist->entries, node) | 906 | evlist__for_each(evlist, evsel) |
911 | evlist->combined_sample_type |= evsel->attr.sample_type; | 907 | evlist->combined_sample_type |= evsel->attr.sample_type; |
912 | 908 | ||
913 | return evlist->combined_sample_type; | 909 | return evlist->combined_sample_type; |
@@ -925,7 +921,7 @@ bool perf_evlist__valid_read_format(struct perf_evlist *evlist) | |||
925 | u64 read_format = first->attr.read_format; | 921 | u64 read_format = first->attr.read_format; |
926 | u64 sample_type = first->attr.sample_type; | 922 | u64 sample_type = first->attr.sample_type; |
927 | 923 | ||
928 | list_for_each_entry_continue(pos, &evlist->entries, node) { | 924 | evlist__for_each(evlist, pos) { |
929 | if (read_format != pos->attr.read_format) | 925 | if (read_format != pos->attr.read_format) |
930 | return false; | 926 | return false; |
931 | } | 927 | } |
@@ -982,7 +978,7 @@ bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist) | |||
982 | { | 978 | { |
983 | struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; | 979 | struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; |
984 | 980 | ||
985 | list_for_each_entry_continue(pos, &evlist->entries, node) { | 981 | evlist__for_each_continue(evlist, pos) { |
986 | if (first->attr.sample_id_all != pos->attr.sample_id_all) | 982 | if (first->attr.sample_id_all != pos->attr.sample_id_all) |
987 | return false; | 983 | return false; |
988 | } | 984 | } |
@@ -1007,9 +1003,12 @@ void perf_evlist__close(struct perf_evlist *evlist) | |||
1007 | struct perf_evsel *evsel; | 1003 | struct perf_evsel *evsel; |
1008 | int ncpus = cpu_map__nr(evlist->cpus); | 1004 | int ncpus = cpu_map__nr(evlist->cpus); |
1009 | int nthreads = thread_map__nr(evlist->threads); | 1005 | int nthreads = thread_map__nr(evlist->threads); |
1006 | int n; | ||
1010 | 1007 | ||
1011 | list_for_each_entry_reverse(evsel, &evlist->entries, node) | 1008 | evlist__for_each_reverse(evlist, evsel) { |
1012 | perf_evsel__close(evsel, ncpus, nthreads); | 1009 | n = evsel->cpus ? evsel->cpus->nr : ncpus; |
1010 | perf_evsel__close(evsel, n, nthreads); | ||
1011 | } | ||
1013 | } | 1012 | } |
1014 | 1013 | ||
1015 | int perf_evlist__open(struct perf_evlist *evlist) | 1014 | int perf_evlist__open(struct perf_evlist *evlist) |
@@ -1019,7 +1018,7 @@ int perf_evlist__open(struct perf_evlist *evlist) | |||
1019 | 1018 | ||
1020 | perf_evlist__update_id_pos(evlist); | 1019 | perf_evlist__update_id_pos(evlist); |
1021 | 1020 | ||
1022 | list_for_each_entry(evsel, &evlist->entries, node) { | 1021 | evlist__for_each(evlist, evsel) { |
1023 | err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); | 1022 | err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); |
1024 | if (err < 0) | 1023 | if (err < 0) |
1025 | goto out_err; | 1024 | goto out_err; |
@@ -1034,7 +1033,7 @@ out_err: | |||
1034 | 1033 | ||
1035 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *target, | 1034 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *target, |
1036 | const char *argv[], bool pipe_output, | 1035 | const char *argv[], bool pipe_output, |
1037 | bool want_signal) | 1036 | void (*exec_error)(int signo, siginfo_t *info, void *ucontext)) |
1038 | { | 1037 | { |
1039 | int child_ready_pipe[2], go_pipe[2]; | 1038 | int child_ready_pipe[2], go_pipe[2]; |
1040 | char bf; | 1039 | char bf; |
@@ -1078,12 +1077,25 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar | |||
1078 | 1077 | ||
1079 | execvp(argv[0], (char **)argv); | 1078 | execvp(argv[0], (char **)argv); |
1080 | 1079 | ||
1081 | perror(argv[0]); | 1080 | if (exec_error) { |
1082 | if (want_signal) | 1081 | union sigval val; |
1083 | kill(getppid(), SIGUSR1); | 1082 | |
1083 | val.sival_int = errno; | ||
1084 | if (sigqueue(getppid(), SIGUSR1, val)) | ||
1085 | perror(argv[0]); | ||
1086 | } else | ||
1087 | perror(argv[0]); | ||
1084 | exit(-1); | 1088 | exit(-1); |
1085 | } | 1089 | } |
1086 | 1090 | ||
1091 | if (exec_error) { | ||
1092 | struct sigaction act = { | ||
1093 | .sa_flags = SA_SIGINFO, | ||
1094 | .sa_sigaction = exec_error, | ||
1095 | }; | ||
1096 | sigaction(SIGUSR1, &act, NULL); | ||
1097 | } | ||
1098 | |||
1087 | if (target__none(target)) | 1099 | if (target__none(target)) |
1088 | evlist->threads->map[0] = evlist->workload.pid; | 1100 | evlist->threads->map[0] = evlist->workload.pid; |
1089 | 1101 | ||
@@ -1145,7 +1157,7 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp) | |||
1145 | struct perf_evsel *evsel; | 1157 | struct perf_evsel *evsel; |
1146 | size_t printed = 0; | 1158 | size_t printed = 0; |
1147 | 1159 | ||
1148 | list_for_each_entry(evsel, &evlist->entries, node) { | 1160 | evlist__for_each(evlist, evsel) { |
1149 | printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "", | 1161 | printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "", |
1150 | perf_evsel__name(evsel)); | 1162 | perf_evsel__name(evsel)); |
1151 | } | 1163 | } |
@@ -1193,8 +1205,7 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, | |||
1193 | "Error:\t%s.\n" | 1205 | "Error:\t%s.\n" |
1194 | "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg); | 1206 | "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg); |
1195 | 1207 | ||
1196 | if (filename__read_int("/proc/sys/kernel/perf_event_paranoid", &value)) | 1208 | value = perf_event_paranoid(); |
1197 | break; | ||
1198 | 1209 | ||
1199 | printed += scnprintf(buf + printed, size - printed, "\nHint:\t"); | 1210 | printed += scnprintf(buf + printed, size - printed, "\nHint:\t"); |
1200 | 1211 | ||
@@ -1215,3 +1226,20 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, | |||
1215 | 1226 | ||
1216 | return 0; | 1227 | return 0; |
1217 | } | 1228 | } |
1229 | |||
1230 | void perf_evlist__to_front(struct perf_evlist *evlist, | ||
1231 | struct perf_evsel *move_evsel) | ||
1232 | { | ||
1233 | struct perf_evsel *evsel, *n; | ||
1234 | LIST_HEAD(move); | ||
1235 | |||
1236 | if (move_evsel == perf_evlist__first(evlist)) | ||
1237 | return; | ||
1238 | |||
1239 | evlist__for_each_safe(evlist, n, evsel) { | ||
1240 | if (evsel->leader == move_evsel->leader) | ||
1241 | list_move_tail(&evsel->node, &move); | ||
1242 | } | ||
1243 | |||
1244 | list_splice(&move, &evlist->entries); | ||
1245 | } | ||
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 649d6ea98a84..f5173cd63693 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -12,7 +12,7 @@ | |||
12 | struct pollfd; | 12 | struct pollfd; |
13 | struct thread_map; | 13 | struct thread_map; |
14 | struct cpu_map; | 14 | struct cpu_map; |
15 | struct perf_record_opts; | 15 | struct record_opts; |
16 | 16 | ||
17 | #define PERF_EVLIST__HLIST_BITS 8 | 17 | #define PERF_EVLIST__HLIST_BITS 8 |
18 | #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) | 18 | #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) |
@@ -97,14 +97,14 @@ void perf_evlist__close(struct perf_evlist *evlist); | |||
97 | 97 | ||
98 | void perf_evlist__set_id_pos(struct perf_evlist *evlist); | 98 | void perf_evlist__set_id_pos(struct perf_evlist *evlist); |
99 | bool perf_can_sample_identifier(void); | 99 | bool perf_can_sample_identifier(void); |
100 | void perf_evlist__config(struct perf_evlist *evlist, | 100 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts); |
101 | struct perf_record_opts *opts); | 101 | int record_opts__config(struct record_opts *opts); |
102 | int perf_record_opts__config(struct perf_record_opts *opts); | ||
103 | 102 | ||
104 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, | 103 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, |
105 | struct target *target, | 104 | struct target *target, |
106 | const char *argv[], bool pipe_output, | 105 | const char *argv[], bool pipe_output, |
107 | bool want_signal); | 106 | void (*exec_error)(int signo, siginfo_t *info, |
107 | void *ucontext)); | ||
108 | int perf_evlist__start_workload(struct perf_evlist *evlist); | 108 | int perf_evlist__start_workload(struct perf_evlist *evlist); |
109 | 109 | ||
110 | int perf_evlist__parse_mmap_pages(const struct option *opt, | 110 | int perf_evlist__parse_mmap_pages(const struct option *opt, |
@@ -135,7 +135,6 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist, | |||
135 | } | 135 | } |
136 | 136 | ||
137 | int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target); | 137 | int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target); |
138 | void perf_evlist__delete_maps(struct perf_evlist *evlist); | ||
139 | int perf_evlist__apply_filters(struct perf_evlist *evlist); | 138 | int perf_evlist__apply_filters(struct perf_evlist *evlist); |
140 | 139 | ||
141 | void __perf_evlist__set_leader(struct list_head *list); | 140 | void __perf_evlist__set_leader(struct list_head *list); |
@@ -193,4 +192,74 @@ static inline void perf_mmap__write_tail(struct perf_mmap *md, | |||
193 | pc->data_tail = tail; | 192 | pc->data_tail = tail; |
194 | } | 193 | } |
195 | 194 | ||
195 | bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str); | ||
196 | void perf_evlist__to_front(struct perf_evlist *evlist, | ||
197 | struct perf_evsel *move_evsel); | ||
198 | |||
199 | /** | ||
200 | * __evlist__for_each - iterate thru all the evsels | ||
201 | * @list: list_head instance to iterate | ||
202 | * @evsel: struct evsel iterator | ||
203 | */ | ||
204 | #define __evlist__for_each(list, evsel) \ | ||
205 | list_for_each_entry(evsel, list, node) | ||
206 | |||
207 | /** | ||
208 | * evlist__for_each - iterate thru all the evsels | ||
209 | * @evlist: evlist instance to iterate | ||
210 | * @evsel: struct evsel iterator | ||
211 | */ | ||
212 | #define evlist__for_each(evlist, evsel) \ | ||
213 | __evlist__for_each(&(evlist)->entries, evsel) | ||
214 | |||
215 | /** | ||
216 | * __evlist__for_each_continue - continue iteration thru all the evsels | ||
217 | * @list: list_head instance to iterate | ||
218 | * @evsel: struct evsel iterator | ||
219 | */ | ||
220 | #define __evlist__for_each_continue(list, evsel) \ | ||
221 | list_for_each_entry_continue(evsel, list, node) | ||
222 | |||
223 | /** | ||
224 | * evlist__for_each_continue - continue iteration thru all the evsels | ||
225 | * @evlist: evlist instance to iterate | ||
226 | * @evsel: struct evsel iterator | ||
227 | */ | ||
228 | #define evlist__for_each_continue(evlist, evsel) \ | ||
229 | __evlist__for_each_continue(&(evlist)->entries, evsel) | ||
230 | |||
231 | /** | ||
232 | * __evlist__for_each_reverse - iterate thru all the evsels in reverse order | ||
233 | * @list: list_head instance to iterate | ||
234 | * @evsel: struct evsel iterator | ||
235 | */ | ||
236 | #define __evlist__for_each_reverse(list, evsel) \ | ||
237 | list_for_each_entry_reverse(evsel, list, node) | ||
238 | |||
239 | /** | ||
240 | * evlist__for_each_reverse - iterate thru all the evsels in reverse order | ||
241 | * @evlist: evlist instance to iterate | ||
242 | * @evsel: struct evsel iterator | ||
243 | */ | ||
244 | #define evlist__for_each_reverse(evlist, evsel) \ | ||
245 | __evlist__for_each_reverse(&(evlist)->entries, evsel) | ||
246 | |||
247 | /** | ||
248 | * __evlist__for_each_safe - safely iterate thru all the evsels | ||
249 | * @list: list_head instance to iterate | ||
250 | * @tmp: struct evsel temp iterator | ||
251 | * @evsel: struct evsel iterator | ||
252 | */ | ||
253 | #define __evlist__for_each_safe(list, tmp, evsel) \ | ||
254 | list_for_each_entry_safe(evsel, tmp, list, node) | ||
255 | |||
256 | /** | ||
257 | * evlist__for_each_safe - safely iterate thru all the evsels | ||
258 | * @evlist: evlist instance to iterate | ||
259 | * @evsel: struct evsel iterator | ||
260 | * @tmp: struct evsel temp iterator | ||
261 | */ | ||
262 | #define evlist__for_each_safe(evlist, tmp, evsel) \ | ||
263 | __evlist__for_each_safe(&(evlist)->entries, tmp, evsel) | ||
264 | |||
196 | #endif /* __PERF_EVLIST_H */ | 265 | #endif /* __PERF_EVLIST_H */ |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 46dd4c2a41ce..55407c594b87 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -9,7 +9,7 @@ | |||
9 | 9 | ||
10 | #include <byteswap.h> | 10 | #include <byteswap.h> |
11 | #include <linux/bitops.h> | 11 | #include <linux/bitops.h> |
12 | #include <lk/debugfs.h> | 12 | #include <api/fs/debugfs.h> |
13 | #include <traceevent/event-parse.h> | 13 | #include <traceevent/event-parse.h> |
14 | #include <linux/hw_breakpoint.h> | 14 | #include <linux/hw_breakpoint.h> |
15 | #include <linux/perf_event.h> | 15 | #include <linux/perf_event.h> |
@@ -23,6 +23,7 @@ | |||
23 | #include "target.h" | 23 | #include "target.h" |
24 | #include "perf_regs.h" | 24 | #include "perf_regs.h" |
25 | #include "debug.h" | 25 | #include "debug.h" |
26 | #include "trace-event.h" | ||
26 | 27 | ||
27 | static struct { | 28 | static struct { |
28 | bool sample_id_all; | 29 | bool sample_id_all; |
@@ -162,6 +163,8 @@ void perf_evsel__init(struct perf_evsel *evsel, | |||
162 | evsel->idx = idx; | 163 | evsel->idx = idx; |
163 | evsel->attr = *attr; | 164 | evsel->attr = *attr; |
164 | evsel->leader = evsel; | 165 | evsel->leader = evsel; |
166 | evsel->unit = ""; | ||
167 | evsel->scale = 1.0; | ||
165 | INIT_LIST_HEAD(&evsel->node); | 168 | INIT_LIST_HEAD(&evsel->node); |
166 | hists__init(&evsel->hists); | 169 | hists__init(&evsel->hists); |
167 | evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); | 170 | evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); |
@@ -178,47 +181,6 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) | |||
178 | return evsel; | 181 | return evsel; |
179 | } | 182 | } |
180 | 183 | ||
181 | struct event_format *event_format__new(const char *sys, const char *name) | ||
182 | { | ||
183 | int fd, n; | ||
184 | char *filename; | ||
185 | void *bf = NULL, *nbf; | ||
186 | size_t size = 0, alloc_size = 0; | ||
187 | struct event_format *format = NULL; | ||
188 | |||
189 | if (asprintf(&filename, "%s/%s/%s/format", tracing_events_path, sys, name) < 0) | ||
190 | goto out; | ||
191 | |||
192 | fd = open(filename, O_RDONLY); | ||
193 | if (fd < 0) | ||
194 | goto out_free_filename; | ||
195 | |||
196 | do { | ||
197 | if (size == alloc_size) { | ||
198 | alloc_size += BUFSIZ; | ||
199 | nbf = realloc(bf, alloc_size); | ||
200 | if (nbf == NULL) | ||
201 | goto out_free_bf; | ||
202 | bf = nbf; | ||
203 | } | ||
204 | |||
205 | n = read(fd, bf + size, alloc_size - size); | ||
206 | if (n < 0) | ||
207 | goto out_free_bf; | ||
208 | size += n; | ||
209 | } while (n > 0); | ||
210 | |||
211 | pevent_parse_format(&format, bf, size, sys); | ||
212 | |||
213 | out_free_bf: | ||
214 | free(bf); | ||
215 | close(fd); | ||
216 | out_free_filename: | ||
217 | free(filename); | ||
218 | out: | ||
219 | return format; | ||
220 | } | ||
221 | |||
222 | struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx) | 184 | struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx) |
223 | { | 185 | { |
224 | struct perf_evsel *evsel = zalloc(sizeof(*evsel)); | 186 | struct perf_evsel *evsel = zalloc(sizeof(*evsel)); |
@@ -233,7 +195,7 @@ struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int | |||
233 | if (asprintf(&evsel->name, "%s:%s", sys, name) < 0) | 195 | if (asprintf(&evsel->name, "%s:%s", sys, name) < 0) |
234 | goto out_free; | 196 | goto out_free; |
235 | 197 | ||
236 | evsel->tp_format = event_format__new(sys, name); | 198 | evsel->tp_format = trace_event__tp_format(sys, name); |
237 | if (evsel->tp_format == NULL) | 199 | if (evsel->tp_format == NULL) |
238 | goto out_free; | 200 | goto out_free; |
239 | 201 | ||
@@ -246,7 +208,7 @@ struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int | |||
246 | return evsel; | 208 | return evsel; |
247 | 209 | ||
248 | out_free: | 210 | out_free: |
249 | free(evsel->name); | 211 | zfree(&evsel->name); |
250 | free(evsel); | 212 | free(evsel); |
251 | return NULL; | 213 | return NULL; |
252 | } | 214 | } |
@@ -566,12 +528,12 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size) | |||
566 | * enable/disable events specifically, as there's no | 528 | * enable/disable events specifically, as there's no |
567 | * initial traced exec call. | 529 | * initial traced exec call. |
568 | */ | 530 | */ |
569 | void perf_evsel__config(struct perf_evsel *evsel, | 531 | void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) |
570 | struct perf_record_opts *opts) | ||
571 | { | 532 | { |
572 | struct perf_evsel *leader = evsel->leader; | 533 | struct perf_evsel *leader = evsel->leader; |
573 | struct perf_event_attr *attr = &evsel->attr; | 534 | struct perf_event_attr *attr = &evsel->attr; |
574 | int track = !evsel->idx; /* only the first counter needs these */ | 535 | int track = !evsel->idx; /* only the first counter needs these */ |
536 | bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread; | ||
575 | 537 | ||
576 | attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; | 538 | attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; |
577 | attr->inherit = !opts->no_inherit; | 539 | attr->inherit = !opts->no_inherit; |
@@ -645,7 +607,7 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
645 | } | 607 | } |
646 | } | 608 | } |
647 | 609 | ||
648 | if (target__has_cpu(&opts->target) || opts->target.force_per_cpu) | 610 | if (target__has_cpu(&opts->target)) |
649 | perf_evsel__set_sample_bit(evsel, CPU); | 611 | perf_evsel__set_sample_bit(evsel, CPU); |
650 | 612 | ||
651 | if (opts->period) | 613 | if (opts->period) |
@@ -653,7 +615,7 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
653 | 615 | ||
654 | if (!perf_missing_features.sample_id_all && | 616 | if (!perf_missing_features.sample_id_all && |
655 | (opts->sample_time || !opts->no_inherit || | 617 | (opts->sample_time || !opts->no_inherit || |
656 | target__has_cpu(&opts->target) || opts->target.force_per_cpu)) | 618 | target__has_cpu(&opts->target) || per_cpu)) |
657 | perf_evsel__set_sample_bit(evsel, TIME); | 619 | perf_evsel__set_sample_bit(evsel, TIME); |
658 | 620 | ||
659 | if (opts->raw_samples) { | 621 | if (opts->raw_samples) { |
@@ -665,7 +627,7 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
665 | if (opts->sample_address) | 627 | if (opts->sample_address) |
666 | perf_evsel__set_sample_bit(evsel, DATA_SRC); | 628 | perf_evsel__set_sample_bit(evsel, DATA_SRC); |
667 | 629 | ||
668 | if (opts->no_delay) { | 630 | if (opts->no_buffering) { |
669 | attr->watermark = 0; | 631 | attr->watermark = 0; |
670 | attr->wakeup_events = 1; | 632 | attr->wakeup_events = 1; |
671 | } | 633 | } |
@@ -696,7 +658,8 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
696 | * Setting enable_on_exec for independent events and | 658 | * Setting enable_on_exec for independent events and |
697 | * group leaders for traced executed by perf. | 659 | * group leaders for traced executed by perf. |
698 | */ | 660 | */ |
699 | if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel)) | 661 | if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel) && |
662 | !opts->initial_delay) | ||
700 | attr->enable_on_exec = 1; | 663 | attr->enable_on_exec = 1; |
701 | } | 664 | } |
702 | 665 | ||
@@ -788,8 +751,7 @@ void perf_evsel__free_id(struct perf_evsel *evsel) | |||
788 | { | 751 | { |
789 | xyarray__delete(evsel->sample_id); | 752 | xyarray__delete(evsel->sample_id); |
790 | evsel->sample_id = NULL; | 753 | evsel->sample_id = NULL; |
791 | free(evsel->id); | 754 | zfree(&evsel->id); |
792 | evsel->id = NULL; | ||
793 | } | 755 | } |
794 | 756 | ||
795 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | 757 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) |
@@ -805,7 +767,7 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
805 | 767 | ||
806 | void perf_evsel__free_counts(struct perf_evsel *evsel) | 768 | void perf_evsel__free_counts(struct perf_evsel *evsel) |
807 | { | 769 | { |
808 | free(evsel->counts); | 770 | zfree(&evsel->counts); |
809 | } | 771 | } |
810 | 772 | ||
811 | void perf_evsel__exit(struct perf_evsel *evsel) | 773 | void perf_evsel__exit(struct perf_evsel *evsel) |
@@ -819,10 +781,10 @@ void perf_evsel__delete(struct perf_evsel *evsel) | |||
819 | { | 781 | { |
820 | perf_evsel__exit(evsel); | 782 | perf_evsel__exit(evsel); |
821 | close_cgroup(evsel->cgrp); | 783 | close_cgroup(evsel->cgrp); |
822 | free(evsel->group_name); | 784 | zfree(&evsel->group_name); |
823 | if (evsel->tp_format) | 785 | if (evsel->tp_format) |
824 | pevent_free_format(evsel->tp_format); | 786 | pevent_free_format(evsel->tp_format); |
825 | free(evsel->name); | 787 | zfree(&evsel->name); |
826 | free(evsel); | 788 | free(evsel); |
827 | } | 789 | } |
828 | 790 | ||
@@ -1119,7 +1081,6 @@ void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
1119 | 1081 | ||
1120 | perf_evsel__close_fd(evsel, ncpus, nthreads); | 1082 | perf_evsel__close_fd(evsel, ncpus, nthreads); |
1121 | perf_evsel__free_fd(evsel); | 1083 | perf_evsel__free_fd(evsel); |
1122 | evsel->fd = NULL; | ||
1123 | } | 1084 | } |
1124 | 1085 | ||
1125 | static struct { | 1086 | static struct { |
@@ -1998,8 +1959,7 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | |||
1998 | evsel->attr.type = PERF_TYPE_SOFTWARE; | 1959 | evsel->attr.type = PERF_TYPE_SOFTWARE; |
1999 | evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK; | 1960 | evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK; |
2000 | 1961 | ||
2001 | free(evsel->name); | 1962 | zfree(&evsel->name); |
2002 | evsel->name = NULL; | ||
2003 | return true; | 1963 | return true; |
2004 | } | 1964 | } |
2005 | 1965 | ||
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 1ea7c92e6e33..f1b325665aae 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -68,6 +68,8 @@ struct perf_evsel { | |||
68 | u32 ids; | 68 | u32 ids; |
69 | struct hists hists; | 69 | struct hists hists; |
70 | char *name; | 70 | char *name; |
71 | double scale; | ||
72 | const char *unit; | ||
71 | struct event_format *tp_format; | 73 | struct event_format *tp_format; |
72 | union { | 74 | union { |
73 | void *priv; | 75 | void *priv; |
@@ -94,7 +96,7 @@ struct perf_evsel { | |||
94 | struct cpu_map; | 96 | struct cpu_map; |
95 | struct thread_map; | 97 | struct thread_map; |
96 | struct perf_evlist; | 98 | struct perf_evlist; |
97 | struct perf_record_opts; | 99 | struct record_opts; |
98 | 100 | ||
99 | struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx); | 101 | struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx); |
100 | 102 | ||
@@ -118,7 +120,7 @@ void perf_evsel__exit(struct perf_evsel *evsel); | |||
118 | void perf_evsel__delete(struct perf_evsel *evsel); | 120 | void perf_evsel__delete(struct perf_evsel *evsel); |
119 | 121 | ||
120 | void perf_evsel__config(struct perf_evsel *evsel, | 122 | void perf_evsel__config(struct perf_evsel *evsel, |
121 | struct perf_record_opts *opts); | 123 | struct record_opts *opts); |
122 | 124 | ||
123 | int __perf_evsel__sample_size(u64 sample_type); | 125 | int __perf_evsel__sample_size(u64 sample_type); |
124 | void perf_evsel__calc_id_pos(struct perf_evsel *evsel); | 126 | void perf_evsel__calc_id_pos(struct perf_evsel *evsel); |
@@ -138,6 +140,7 @@ extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX]; | |||
138 | int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, | 140 | int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, |
139 | char *bf, size_t size); | 141 | char *bf, size_t size); |
140 | const char *perf_evsel__name(struct perf_evsel *evsel); | 142 | const char *perf_evsel__name(struct perf_evsel *evsel); |
143 | |||
141 | const char *perf_evsel__group_name(struct perf_evsel *evsel); | 144 | const char *perf_evsel__group_name(struct perf_evsel *evsel); |
142 | int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); | 145 | int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); |
143 | 146 | ||
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 1cd035708931..893f8e2df928 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -177,7 +177,7 @@ perf_header__set_cmdline(int argc, const char **argv) | |||
177 | continue; \ | 177 | continue; \ |
178 | else | 178 | else |
179 | 179 | ||
180 | static int write_buildid(char *name, size_t name_len, u8 *build_id, | 180 | static int write_buildid(const char *name, size_t name_len, u8 *build_id, |
181 | pid_t pid, u16 misc, int fd) | 181 | pid_t pid, u16 misc, int fd) |
182 | { | 182 | { |
183 | int err; | 183 | int err; |
@@ -209,7 +209,7 @@ static int __dsos__write_buildid_table(struct list_head *head, | |||
209 | 209 | ||
210 | dsos__for_each_with_build_id(pos, head) { | 210 | dsos__for_each_with_build_id(pos, head) { |
211 | int err; | 211 | int err; |
212 | char *name; | 212 | const char *name; |
213 | size_t name_len; | 213 | size_t name_len; |
214 | 214 | ||
215 | if (!pos->hit) | 215 | if (!pos->hit) |
@@ -387,7 +387,7 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine, | |||
387 | { | 387 | { |
388 | bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; | 388 | bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; |
389 | bool is_vdso = is_vdso_map(dso->short_name); | 389 | bool is_vdso = is_vdso_map(dso->short_name); |
390 | char *name = dso->long_name; | 390 | const char *name = dso->long_name; |
391 | char nm[PATH_MAX]; | 391 | char nm[PATH_MAX]; |
392 | 392 | ||
393 | if (dso__is_kcore(dso)) { | 393 | if (dso__is_kcore(dso)) { |
@@ -643,8 +643,7 @@ static int write_event_desc(int fd, struct perf_header *h __maybe_unused, | |||
643 | if (ret < 0) | 643 | if (ret < 0) |
644 | return ret; | 644 | return ret; |
645 | 645 | ||
646 | list_for_each_entry(evsel, &evlist->entries, node) { | 646 | evlist__for_each(evlist, evsel) { |
647 | |||
648 | ret = do_write(fd, &evsel->attr, sz); | 647 | ret = do_write(fd, &evsel->attr, sz); |
649 | if (ret < 0) | 648 | if (ret < 0) |
650 | return ret; | 649 | return ret; |
@@ -800,10 +799,10 @@ static void free_cpu_topo(struct cpu_topo *tp) | |||
800 | return; | 799 | return; |
801 | 800 | ||
802 | for (i = 0 ; i < tp->core_sib; i++) | 801 | for (i = 0 ; i < tp->core_sib; i++) |
803 | free(tp->core_siblings[i]); | 802 | zfree(&tp->core_siblings[i]); |
804 | 803 | ||
805 | for (i = 0 ; i < tp->thread_sib; i++) | 804 | for (i = 0 ; i < tp->thread_sib; i++) |
806 | free(tp->thread_siblings[i]); | 805 | zfree(&tp->thread_siblings[i]); |
807 | 806 | ||
808 | free(tp); | 807 | free(tp); |
809 | } | 808 | } |
@@ -931,7 +930,7 @@ static int write_topo_node(int fd, int node) | |||
931 | /* skip over invalid lines */ | 930 | /* skip over invalid lines */ |
932 | if (!strchr(buf, ':')) | 931 | if (!strchr(buf, ':')) |
933 | continue; | 932 | continue; |
934 | if (sscanf(buf, "%*s %*d %s %"PRIu64, field, &mem) != 2) | 933 | if (sscanf(buf, "%*s %*d %31s %"PRIu64, field, &mem) != 2) |
935 | goto done; | 934 | goto done; |
936 | if (!strcmp(field, "MemTotal:")) | 935 | if (!strcmp(field, "MemTotal:")) |
937 | mem_total = mem; | 936 | mem_total = mem; |
@@ -1092,7 +1091,7 @@ static int write_group_desc(int fd, struct perf_header *h __maybe_unused, | |||
1092 | if (ret < 0) | 1091 | if (ret < 0) |
1093 | return ret; | 1092 | return ret; |
1094 | 1093 | ||
1095 | list_for_each_entry(evsel, &evlist->entries, node) { | 1094 | evlist__for_each(evlist, evsel) { |
1096 | if (perf_evsel__is_group_leader(evsel) && | 1095 | if (perf_evsel__is_group_leader(evsel) && |
1097 | evsel->nr_members > 1) { | 1096 | evsel->nr_members > 1) { |
1098 | const char *name = evsel->group_name ?: "{anon_group}"; | 1097 | const char *name = evsel->group_name ?: "{anon_group}"; |
@@ -1232,10 +1231,8 @@ static void free_event_desc(struct perf_evsel *events) | |||
1232 | return; | 1231 | return; |
1233 | 1232 | ||
1234 | for (evsel = events; evsel->attr.size; evsel++) { | 1233 | for (evsel = events; evsel->attr.size; evsel++) { |
1235 | if (evsel->name) | 1234 | zfree(&evsel->name); |
1236 | free(evsel->name); | 1235 | zfree(&evsel->id); |
1237 | if (evsel->id) | ||
1238 | free(evsel->id); | ||
1239 | } | 1236 | } |
1240 | 1237 | ||
1241 | free(events); | 1238 | free(events); |
@@ -1326,8 +1323,7 @@ read_event_desc(struct perf_header *ph, int fd) | |||
1326 | } | 1323 | } |
1327 | } | 1324 | } |
1328 | out: | 1325 | out: |
1329 | if (buf) | 1326 | free(buf); |
1330 | free(buf); | ||
1331 | return events; | 1327 | return events; |
1332 | error: | 1328 | error: |
1333 | if (events) | 1329 | if (events) |
@@ -1490,7 +1486,7 @@ static void print_group_desc(struct perf_header *ph, int fd __maybe_unused, | |||
1490 | 1486 | ||
1491 | session = container_of(ph, struct perf_session, header); | 1487 | session = container_of(ph, struct perf_session, header); |
1492 | 1488 | ||
1493 | list_for_each_entry(evsel, &session->evlist->entries, node) { | 1489 | evlist__for_each(session->evlist, evsel) { |
1494 | if (perf_evsel__is_group_leader(evsel) && | 1490 | if (perf_evsel__is_group_leader(evsel) && |
1495 | evsel->nr_members > 1) { | 1491 | evsel->nr_members > 1) { |
1496 | fprintf(fp, "# group: %s{%s", evsel->group_name ?: "", | 1492 | fprintf(fp, "# group: %s{%s", evsel->group_name ?: "", |
@@ -1709,7 +1705,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused, | |||
1709 | struct perf_header *ph, int fd, | 1705 | struct perf_header *ph, int fd, |
1710 | void *data __maybe_unused) | 1706 | void *data __maybe_unused) |
1711 | { | 1707 | { |
1712 | size_t ret; | 1708 | ssize_t ret; |
1713 | u32 nr; | 1709 | u32 nr; |
1714 | 1710 | ||
1715 | ret = readn(fd, &nr, sizeof(nr)); | 1711 | ret = readn(fd, &nr, sizeof(nr)); |
@@ -1753,7 +1749,7 @@ static int process_total_mem(struct perf_file_section *section __maybe_unused, | |||
1753 | void *data __maybe_unused) | 1749 | void *data __maybe_unused) |
1754 | { | 1750 | { |
1755 | uint64_t mem; | 1751 | uint64_t mem; |
1756 | size_t ret; | 1752 | ssize_t ret; |
1757 | 1753 | ||
1758 | ret = readn(fd, &mem, sizeof(mem)); | 1754 | ret = readn(fd, &mem, sizeof(mem)); |
1759 | if (ret != sizeof(mem)) | 1755 | if (ret != sizeof(mem)) |
@@ -1771,7 +1767,7 @@ perf_evlist__find_by_index(struct perf_evlist *evlist, int idx) | |||
1771 | { | 1767 | { |
1772 | struct perf_evsel *evsel; | 1768 | struct perf_evsel *evsel; |
1773 | 1769 | ||
1774 | list_for_each_entry(evsel, &evlist->entries, node) { | 1770 | evlist__for_each(evlist, evsel) { |
1775 | if (evsel->idx == idx) | 1771 | if (evsel->idx == idx) |
1776 | return evsel; | 1772 | return evsel; |
1777 | } | 1773 | } |
@@ -1822,7 +1818,7 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused, | |||
1822 | struct perf_header *ph, int fd, | 1818 | struct perf_header *ph, int fd, |
1823 | void *data __maybe_unused) | 1819 | void *data __maybe_unused) |
1824 | { | 1820 | { |
1825 | size_t ret; | 1821 | ssize_t ret; |
1826 | char *str; | 1822 | char *str; |
1827 | u32 nr, i; | 1823 | u32 nr, i; |
1828 | struct strbuf sb; | 1824 | struct strbuf sb; |
@@ -1858,7 +1854,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused | |||
1858 | struct perf_header *ph, int fd, | 1854 | struct perf_header *ph, int fd, |
1859 | void *data __maybe_unused) | 1855 | void *data __maybe_unused) |
1860 | { | 1856 | { |
1861 | size_t ret; | 1857 | ssize_t ret; |
1862 | u32 nr, i; | 1858 | u32 nr, i; |
1863 | char *str; | 1859 | char *str; |
1864 | struct strbuf sb; | 1860 | struct strbuf sb; |
@@ -1914,7 +1910,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse | |||
1914 | struct perf_header *ph, int fd, | 1910 | struct perf_header *ph, int fd, |
1915 | void *data __maybe_unused) | 1911 | void *data __maybe_unused) |
1916 | { | 1912 | { |
1917 | size_t ret; | 1913 | ssize_t ret; |
1918 | u32 nr, node, i; | 1914 | u32 nr, node, i; |
1919 | char *str; | 1915 | char *str; |
1920 | uint64_t mem_total, mem_free; | 1916 | uint64_t mem_total, mem_free; |
@@ -1974,7 +1970,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused | |||
1974 | struct perf_header *ph, int fd, | 1970 | struct perf_header *ph, int fd, |
1975 | void *data __maybe_unused) | 1971 | void *data __maybe_unused) |
1976 | { | 1972 | { |
1977 | size_t ret; | 1973 | ssize_t ret; |
1978 | char *name; | 1974 | char *name; |
1979 | u32 pmu_num; | 1975 | u32 pmu_num; |
1980 | u32 type; | 1976 | u32 type; |
@@ -2074,7 +2070,7 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused, | |||
2074 | session->evlist->nr_groups = nr_groups; | 2070 | session->evlist->nr_groups = nr_groups; |
2075 | 2071 | ||
2076 | i = nr = 0; | 2072 | i = nr = 0; |
2077 | list_for_each_entry(evsel, &session->evlist->entries, node) { | 2073 | evlist__for_each(session->evlist, evsel) { |
2078 | if (evsel->idx == (int) desc[i].leader_idx) { | 2074 | if (evsel->idx == (int) desc[i].leader_idx) { |
2079 | evsel->leader = evsel; | 2075 | evsel->leader = evsel; |
2080 | /* {anon_group} is a dummy name */ | 2076 | /* {anon_group} is a dummy name */ |
@@ -2108,7 +2104,7 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused, | |||
2108 | ret = 0; | 2104 | ret = 0; |
2109 | out_free: | 2105 | out_free: |
2110 | for (i = 0; i < nr_groups; i++) | 2106 | for (i = 0; i < nr_groups; i++) |
2111 | free(desc[i].name); | 2107 | zfree(&desc[i].name); |
2112 | free(desc); | 2108 | free(desc); |
2113 | 2109 | ||
2114 | return ret; | 2110 | return ret; |
@@ -2301,7 +2297,7 @@ int perf_session__write_header(struct perf_session *session, | |||
2301 | 2297 | ||
2302 | lseek(fd, sizeof(f_header), SEEK_SET); | 2298 | lseek(fd, sizeof(f_header), SEEK_SET); |
2303 | 2299 | ||
2304 | list_for_each_entry(evsel, &evlist->entries, node) { | 2300 | evlist__for_each(session->evlist, evsel) { |
2305 | evsel->id_offset = lseek(fd, 0, SEEK_CUR); | 2301 | evsel->id_offset = lseek(fd, 0, SEEK_CUR); |
2306 | err = do_write(fd, evsel->id, evsel->ids * sizeof(u64)); | 2302 | err = do_write(fd, evsel->id, evsel->ids * sizeof(u64)); |
2307 | if (err < 0) { | 2303 | if (err < 0) { |
@@ -2312,7 +2308,7 @@ int perf_session__write_header(struct perf_session *session, | |||
2312 | 2308 | ||
2313 | attr_offset = lseek(fd, 0, SEEK_CUR); | 2309 | attr_offset = lseek(fd, 0, SEEK_CUR); |
2314 | 2310 | ||
2315 | list_for_each_entry(evsel, &evlist->entries, node) { | 2311 | evlist__for_each(evlist, evsel) { |
2316 | f_attr = (struct perf_file_attr){ | 2312 | f_attr = (struct perf_file_attr){ |
2317 | .attr = evsel->attr, | 2313 | .attr = evsel->attr, |
2318 | .ids = { | 2314 | .ids = { |
@@ -2327,7 +2323,8 @@ int perf_session__write_header(struct perf_session *session, | |||
2327 | } | 2323 | } |
2328 | } | 2324 | } |
2329 | 2325 | ||
2330 | header->data_offset = lseek(fd, 0, SEEK_CUR); | 2326 | if (!header->data_offset) |
2327 | header->data_offset = lseek(fd, 0, SEEK_CUR); | ||
2331 | header->feat_offset = header->data_offset + header->data_size; | 2328 | header->feat_offset = header->data_offset + header->data_size; |
2332 | 2329 | ||
2333 | if (at_exit) { | 2330 | if (at_exit) { |
@@ -2534,7 +2531,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz, | |||
2534 | int perf_file_header__read(struct perf_file_header *header, | 2531 | int perf_file_header__read(struct perf_file_header *header, |
2535 | struct perf_header *ph, int fd) | 2532 | struct perf_header *ph, int fd) |
2536 | { | 2533 | { |
2537 | int ret; | 2534 | ssize_t ret; |
2538 | 2535 | ||
2539 | lseek(fd, 0, SEEK_SET); | 2536 | lseek(fd, 0, SEEK_SET); |
2540 | 2537 | ||
@@ -2628,7 +2625,7 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, | |||
2628 | struct perf_header *ph, int fd, | 2625 | struct perf_header *ph, int fd, |
2629 | bool repipe) | 2626 | bool repipe) |
2630 | { | 2627 | { |
2631 | int ret; | 2628 | ssize_t ret; |
2632 | 2629 | ||
2633 | ret = readn(fd, header, sizeof(*header)); | 2630 | ret = readn(fd, header, sizeof(*header)); |
2634 | if (ret <= 0) | 2631 | if (ret <= 0) |
@@ -2669,7 +2666,7 @@ static int read_attr(int fd, struct perf_header *ph, | |||
2669 | struct perf_event_attr *attr = &f_attr->attr; | 2666 | struct perf_event_attr *attr = &f_attr->attr; |
2670 | size_t sz, left; | 2667 | size_t sz, left; |
2671 | size_t our_sz = sizeof(f_attr->attr); | 2668 | size_t our_sz = sizeof(f_attr->attr); |
2672 | int ret; | 2669 | ssize_t ret; |
2673 | 2670 | ||
2674 | memset(f_attr, 0, sizeof(*f_attr)); | 2671 | memset(f_attr, 0, sizeof(*f_attr)); |
2675 | 2672 | ||
@@ -2744,7 +2741,7 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist, | |||
2744 | { | 2741 | { |
2745 | struct perf_evsel *pos; | 2742 | struct perf_evsel *pos; |
2746 | 2743 | ||
2747 | list_for_each_entry(pos, &evlist->entries, node) { | 2744 | evlist__for_each(evlist, pos) { |
2748 | if (pos->attr.type == PERF_TYPE_TRACEPOINT && | 2745 | if (pos->attr.type == PERF_TYPE_TRACEPOINT && |
2749 | perf_evsel__prepare_tracepoint_event(pos, pevent)) | 2746 | perf_evsel__prepare_tracepoint_event(pos, pevent)) |
2750 | return -1; | 2747 | return -1; |
@@ -2834,11 +2831,11 @@ int perf_session__read_header(struct perf_session *session) | |||
2834 | 2831 | ||
2835 | symbol_conf.nr_events = nr_attrs; | 2832 | symbol_conf.nr_events = nr_attrs; |
2836 | 2833 | ||
2837 | perf_header__process_sections(header, fd, &session->pevent, | 2834 | perf_header__process_sections(header, fd, &session->tevent, |
2838 | perf_file_section__process); | 2835 | perf_file_section__process); |
2839 | 2836 | ||
2840 | if (perf_evlist__prepare_tracepoint_events(session->evlist, | 2837 | if (perf_evlist__prepare_tracepoint_events(session->evlist, |
2841 | session->pevent)) | 2838 | session->tevent.pevent)) |
2842 | goto out_delete_evlist; | 2839 | goto out_delete_evlist; |
2843 | 2840 | ||
2844 | return 0; | 2841 | return 0; |
@@ -2892,7 +2889,7 @@ int perf_event__synthesize_attrs(struct perf_tool *tool, | |||
2892 | struct perf_evsel *evsel; | 2889 | struct perf_evsel *evsel; |
2893 | int err = 0; | 2890 | int err = 0; |
2894 | 2891 | ||
2895 | list_for_each_entry(evsel, &session->evlist->entries, node) { | 2892 | evlist__for_each(session->evlist, evsel) { |
2896 | err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids, | 2893 | err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids, |
2897 | evsel->id, process); | 2894 | evsel->id, process); |
2898 | if (err) { | 2895 | if (err) { |
@@ -3003,7 +3000,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused, | |||
3003 | lseek(fd, offset + sizeof(struct tracing_data_event), | 3000 | lseek(fd, offset + sizeof(struct tracing_data_event), |
3004 | SEEK_SET); | 3001 | SEEK_SET); |
3005 | 3002 | ||
3006 | size_read = trace_report(fd, &session->pevent, | 3003 | size_read = trace_report(fd, &session->tevent, |
3007 | session->repipe); | 3004 | session->repipe); |
3008 | padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; | 3005 | padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; |
3009 | 3006 | ||
@@ -3025,7 +3022,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused, | |||
3025 | } | 3022 | } |
3026 | 3023 | ||
3027 | perf_evlist__prepare_tracepoint_events(session->evlist, | 3024 | perf_evlist__prepare_tracepoint_events(session->evlist, |
3028 | session->pevent); | 3025 | session->tevent.pevent); |
3029 | 3026 | ||
3030 | return size_read + padding; | 3027 | return size_read + padding; |
3031 | } | 3028 | } |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 307c9aed972e..a2d047bdf4ef 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -77,16 +77,16 @@ struct perf_session_env { | |||
77 | unsigned long long total_mem; | 77 | unsigned long long total_mem; |
78 | 78 | ||
79 | int nr_cmdline; | 79 | int nr_cmdline; |
80 | char *cmdline; | ||
81 | int nr_sibling_cores; | 80 | int nr_sibling_cores; |
82 | char *sibling_cores; | ||
83 | int nr_sibling_threads; | 81 | int nr_sibling_threads; |
84 | char *sibling_threads; | ||
85 | int nr_numa_nodes; | 82 | int nr_numa_nodes; |
86 | char *numa_nodes; | ||
87 | int nr_pmu_mappings; | 83 | int nr_pmu_mappings; |
88 | char *pmu_mappings; | ||
89 | int nr_groups; | 84 | int nr_groups; |
85 | char *cmdline; | ||
86 | char *sibling_cores; | ||
87 | char *sibling_threads; | ||
88 | char *numa_nodes; | ||
89 | char *pmu_mappings; | ||
90 | }; | 90 | }; |
91 | 91 | ||
92 | struct perf_header { | 92 | struct perf_header { |
diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c index 8b1f6e891b8a..86c37c472263 100644 --- a/tools/perf/util/help.c +++ b/tools/perf/util/help.c | |||
@@ -22,8 +22,8 @@ static void clean_cmdnames(struct cmdnames *cmds) | |||
22 | unsigned int i; | 22 | unsigned int i; |
23 | 23 | ||
24 | for (i = 0; i < cmds->cnt; ++i) | 24 | for (i = 0; i < cmds->cnt; ++i) |
25 | free(cmds->names[i]); | 25 | zfree(&cmds->names[i]); |
26 | free(cmds->names); | 26 | zfree(&cmds->names); |
27 | cmds->cnt = 0; | 27 | cmds->cnt = 0; |
28 | cmds->alloc = 0; | 28 | cmds->alloc = 0; |
29 | } | 29 | } |
@@ -263,9 +263,8 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old) | |||
263 | 263 | ||
264 | for (i = 0; i < old->cnt; i++) | 264 | for (i = 0; i < old->cnt; i++) |
265 | cmds->names[cmds->cnt++] = old->names[i]; | 265 | cmds->names[cmds->cnt++] = old->names[i]; |
266 | free(old->names); | 266 | zfree(&old->names); |
267 | old->cnt = 0; | 267 | old->cnt = 0; |
268 | old->names = NULL; | ||
269 | } | 268 | } |
270 | 269 | ||
271 | const char *help_unknown_cmd(const char *cmd) | 270 | const char *help_unknown_cmd(const char *cmd) |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 822903eaa201..e4e6249b87d4 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #include "annotate.h" | ||
2 | #include "util.h" | 1 | #include "util.h" |
3 | #include "build-id.h" | 2 | #include "build-id.h" |
4 | #include "hist.h" | 3 | #include "hist.h" |
@@ -182,21 +181,21 @@ void hists__output_recalc_col_len(struct hists *hists, int max_rows) | |||
182 | } | 181 | } |
183 | } | 182 | } |
184 | 183 | ||
185 | static void hist_entry__add_cpumode_period(struct hist_entry *he, | 184 | static void he_stat__add_cpumode_period(struct he_stat *he_stat, |
186 | unsigned int cpumode, u64 period) | 185 | unsigned int cpumode, u64 period) |
187 | { | 186 | { |
188 | switch (cpumode) { | 187 | switch (cpumode) { |
189 | case PERF_RECORD_MISC_KERNEL: | 188 | case PERF_RECORD_MISC_KERNEL: |
190 | he->stat.period_sys += period; | 189 | he_stat->period_sys += period; |
191 | break; | 190 | break; |
192 | case PERF_RECORD_MISC_USER: | 191 | case PERF_RECORD_MISC_USER: |
193 | he->stat.period_us += period; | 192 | he_stat->period_us += period; |
194 | break; | 193 | break; |
195 | case PERF_RECORD_MISC_GUEST_KERNEL: | 194 | case PERF_RECORD_MISC_GUEST_KERNEL: |
196 | he->stat.period_guest_sys += period; | 195 | he_stat->period_guest_sys += period; |
197 | break; | 196 | break; |
198 | case PERF_RECORD_MISC_GUEST_USER: | 197 | case PERF_RECORD_MISC_GUEST_USER: |
199 | he->stat.period_guest_us += period; | 198 | he_stat->period_guest_us += period; |
200 | break; | 199 | break; |
201 | default: | 200 | default: |
202 | break; | 201 | break; |
@@ -223,10 +222,10 @@ static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src) | |||
223 | dest->weight += src->weight; | 222 | dest->weight += src->weight; |
224 | } | 223 | } |
225 | 224 | ||
226 | static void hist_entry__decay(struct hist_entry *he) | 225 | static void he_stat__decay(struct he_stat *he_stat) |
227 | { | 226 | { |
228 | he->stat.period = (he->stat.period * 7) / 8; | 227 | he_stat->period = (he_stat->period * 7) / 8; |
229 | he->stat.nr_events = (he->stat.nr_events * 7) / 8; | 228 | he_stat->nr_events = (he_stat->nr_events * 7) / 8; |
230 | /* XXX need decay for weight too? */ | 229 | /* XXX need decay for weight too? */ |
231 | } | 230 | } |
232 | 231 | ||
@@ -237,7 +236,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) | |||
237 | if (prev_period == 0) | 236 | if (prev_period == 0) |
238 | return true; | 237 | return true; |
239 | 238 | ||
240 | hist_entry__decay(he); | 239 | he_stat__decay(&he->stat); |
241 | 240 | ||
242 | if (!he->filtered) | 241 | if (!he->filtered) |
243 | hists->stats.total_period -= prev_period - he->stat.period; | 242 | hists->stats.total_period -= prev_period - he->stat.period; |
@@ -342,15 +341,15 @@ static u8 symbol__parent_filter(const struct symbol *parent) | |||
342 | } | 341 | } |
343 | 342 | ||
344 | static struct hist_entry *add_hist_entry(struct hists *hists, | 343 | static struct hist_entry *add_hist_entry(struct hists *hists, |
345 | struct hist_entry *entry, | 344 | struct hist_entry *entry, |
346 | struct addr_location *al, | 345 | struct addr_location *al) |
347 | u64 period, | ||
348 | u64 weight) | ||
349 | { | 346 | { |
350 | struct rb_node **p; | 347 | struct rb_node **p; |
351 | struct rb_node *parent = NULL; | 348 | struct rb_node *parent = NULL; |
352 | struct hist_entry *he; | 349 | struct hist_entry *he; |
353 | int64_t cmp; | 350 | int64_t cmp; |
351 | u64 period = entry->stat.period; | ||
352 | u64 weight = entry->stat.weight; | ||
354 | 353 | ||
355 | p = &hists->entries_in->rb_node; | 354 | p = &hists->entries_in->rb_node; |
356 | 355 | ||
@@ -373,7 +372,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists, | |||
373 | * This mem info was allocated from machine__resolve_mem | 372 | * This mem info was allocated from machine__resolve_mem |
374 | * and will not be used anymore. | 373 | * and will not be used anymore. |
375 | */ | 374 | */ |
376 | free(entry->mem_info); | 375 | zfree(&entry->mem_info); |
377 | 376 | ||
378 | /* If the map of an existing hist_entry has | 377 | /* If the map of an existing hist_entry has |
379 | * become out-of-date due to an exec() or | 378 | * become out-of-date due to an exec() or |
@@ -403,7 +402,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists, | |||
403 | rb_link_node(&he->rb_node_in, parent, p); | 402 | rb_link_node(&he->rb_node_in, parent, p); |
404 | rb_insert_color(&he->rb_node_in, hists->entries_in); | 403 | rb_insert_color(&he->rb_node_in, hists->entries_in); |
405 | out: | 404 | out: |
406 | hist_entry__add_cpumode_period(he, al->cpumode, period); | 405 | he_stat__add_cpumode_period(&he->stat, al->cpumode, period); |
407 | return he; | 406 | return he; |
408 | } | 407 | } |
409 | 408 | ||
@@ -437,7 +436,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists, | |||
437 | .transaction = transaction, | 436 | .transaction = transaction, |
438 | }; | 437 | }; |
439 | 438 | ||
440 | return add_hist_entry(hists, &entry, al, period, weight); | 439 | return add_hist_entry(hists, &entry, al); |
441 | } | 440 | } |
442 | 441 | ||
443 | int64_t | 442 | int64_t |
@@ -476,8 +475,8 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) | |||
476 | 475 | ||
477 | void hist_entry__free(struct hist_entry *he) | 476 | void hist_entry__free(struct hist_entry *he) |
478 | { | 477 | { |
479 | free(he->branch_info); | 478 | zfree(&he->branch_info); |
480 | free(he->mem_info); | 479 | zfree(&he->mem_info); |
481 | free_srcline(he->srcline); | 480 | free_srcline(he->srcline); |
482 | free(he); | 481 | free(he); |
483 | } | 482 | } |
@@ -807,16 +806,6 @@ void hists__filter_by_symbol(struct hists *hists) | |||
807 | } | 806 | } |
808 | } | 807 | } |
809 | 808 | ||
810 | int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) | ||
811 | { | ||
812 | return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); | ||
813 | } | ||
814 | |||
815 | int hist_entry__annotate(struct hist_entry *he, size_t privsize) | ||
816 | { | ||
817 | return symbol__annotate(he->ms.sym, he->ms.map, privsize); | ||
818 | } | ||
819 | |||
820 | void events_stats__inc(struct events_stats *stats, u32 type) | 809 | void events_stats__inc(struct events_stats *stats, u32 type) |
821 | { | 810 | { |
822 | ++stats->nr_events[0]; | 811 | ++stats->nr_events[0]; |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index b621347a1585..a59743fa3ef7 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -111,9 +111,6 @@ size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); | |||
111 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | 111 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, |
112 | int max_cols, float min_pcnt, FILE *fp); | 112 | int max_cols, float min_pcnt, FILE *fp); |
113 | 113 | ||
114 | int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr); | ||
115 | int hist_entry__annotate(struct hist_entry *he, size_t privsize); | ||
116 | |||
117 | void hists__filter_by_dso(struct hists *hists); | 114 | void hists__filter_by_dso(struct hists *hists); |
118 | void hists__filter_by_thread(struct hists *hists); | 115 | void hists__filter_by_thread(struct hists *hists); |
119 | void hists__filter_by_symbol(struct hists *hists); | 116 | void hists__filter_by_symbol(struct hists *hists); |
diff --git a/tools/perf/util/include/asm/bug.h b/tools/perf/util/include/asm/bug.h deleted file mode 100644 index 7fcc6810adc2..000000000000 --- a/tools/perf/util/include/asm/bug.h +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | #ifndef _PERF_ASM_GENERIC_BUG_H | ||
2 | #define _PERF_ASM_GENERIC_BUG_H | ||
3 | |||
4 | #define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0) | ||
5 | |||
6 | #define WARN(condition, format...) ({ \ | ||
7 | int __ret_warn_on = !!(condition); \ | ||
8 | if (unlikely(__ret_warn_on)) \ | ||
9 | __WARN_printf(format); \ | ||
10 | unlikely(__ret_warn_on); \ | ||
11 | }) | ||
12 | |||
13 | #define WARN_ONCE(condition, format...) ({ \ | ||
14 | static int __warned; \ | ||
15 | int __ret_warn_once = !!(condition); \ | ||
16 | \ | ||
17 | if (unlikely(__ret_warn_once)) \ | ||
18 | if (WARN(!__warned, format)) \ | ||
19 | __warned = 1; \ | ||
20 | unlikely(__ret_warn_once); \ | ||
21 | }) | ||
22 | #endif | ||
diff --git a/tools/perf/util/include/asm/hash.h b/tools/perf/util/include/asm/hash.h new file mode 100644 index 000000000000..d82b170bb216 --- /dev/null +++ b/tools/perf/util/include/asm/hash.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef __ASM_GENERIC_HASH_H | ||
2 | #define __ASM_GENERIC_HASH_H | ||
3 | |||
4 | /* Stub */ | ||
5 | |||
6 | #endif /* __ASM_GENERIC_HASH_H */ | ||
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h index 45cf10a562bd..dadfa7e54287 100644 --- a/tools/perf/util/include/linux/bitops.h +++ b/tools/perf/util/include/linux/bitops.h | |||
@@ -87,13 +87,15 @@ static __always_inline unsigned long __ffs(unsigned long word) | |||
87 | return num; | 87 | return num; |
88 | } | 88 | } |
89 | 89 | ||
90 | typedef const unsigned long __attribute__((__may_alias__)) long_alias_t; | ||
91 | |||
90 | /* | 92 | /* |
91 | * Find the first set bit in a memory region. | 93 | * Find the first set bit in a memory region. |
92 | */ | 94 | */ |
93 | static inline unsigned long | 95 | static inline unsigned long |
94 | find_first_bit(const unsigned long *addr, unsigned long size) | 96 | find_first_bit(const unsigned long *addr, unsigned long size) |
95 | { | 97 | { |
96 | const unsigned long *p = addr; | 98 | long_alias_t *p = (long_alias_t *) addr; |
97 | unsigned long result = 0; | 99 | unsigned long result = 0; |
98 | unsigned long tmp; | 100 | unsigned long tmp; |
99 | 101 | ||
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h deleted file mode 100644 index b003ad7200b2..000000000000 --- a/tools/perf/util/include/linux/compiler.h +++ /dev/null | |||
@@ -1,30 +0,0 @@ | |||
1 | #ifndef _PERF_LINUX_COMPILER_H_ | ||
2 | #define _PERF_LINUX_COMPILER_H_ | ||
3 | |||
4 | #ifndef __always_inline | ||
5 | # define __always_inline inline __attribute__((always_inline)) | ||
6 | #endif | ||
7 | |||
8 | #define __user | ||
9 | |||
10 | #ifndef __attribute_const__ | ||
11 | # define __attribute_const__ | ||
12 | #endif | ||
13 | |||
14 | #ifndef __maybe_unused | ||
15 | # define __maybe_unused __attribute__((unused)) | ||
16 | #endif | ||
17 | |||
18 | #ifndef __packed | ||
19 | # define __packed __attribute__((__packed__)) | ||
20 | #endif | ||
21 | |||
22 | #ifndef __force | ||
23 | # define __force | ||
24 | #endif | ||
25 | |||
26 | #ifndef __weak | ||
27 | # define __weak __attribute__((weak)) | ||
28 | #endif | ||
29 | |||
30 | #endif | ||
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 84cdb072ac83..620a1983b76b 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include "strlist.h" | 9 | #include "strlist.h" |
10 | #include "thread.h" | 10 | #include "thread.h" |
11 | #include <stdbool.h> | 11 | #include <stdbool.h> |
12 | #include <symbol/kallsyms.h> | ||
12 | #include "unwind.h" | 13 | #include "unwind.h" |
13 | 14 | ||
14 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | 15 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) |
@@ -26,6 +27,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | |||
26 | machine->pid = pid; | 27 | machine->pid = pid; |
27 | 28 | ||
28 | machine->symbol_filter = NULL; | 29 | machine->symbol_filter = NULL; |
30 | machine->id_hdr_size = 0; | ||
29 | 31 | ||
30 | machine->root_dir = strdup(root_dir); | 32 | machine->root_dir = strdup(root_dir); |
31 | if (machine->root_dir == NULL) | 33 | if (machine->root_dir == NULL) |
@@ -101,8 +103,7 @@ void machine__exit(struct machine *machine) | |||
101 | map_groups__exit(&machine->kmaps); | 103 | map_groups__exit(&machine->kmaps); |
102 | dsos__delete(&machine->user_dsos); | 104 | dsos__delete(&machine->user_dsos); |
103 | dsos__delete(&machine->kernel_dsos); | 105 | dsos__delete(&machine->kernel_dsos); |
104 | free(machine->root_dir); | 106 | zfree(&machine->root_dir); |
105 | machine->root_dir = NULL; | ||
106 | } | 107 | } |
107 | 108 | ||
108 | void machine__delete(struct machine *machine) | 109 | void machine__delete(struct machine *machine) |
@@ -495,23 +496,22 @@ static int symbol__in_kernel(void *arg, const char *name, | |||
495 | return 1; | 496 | return 1; |
496 | } | 497 | } |
497 | 498 | ||
499 | static void machine__get_kallsyms_filename(struct machine *machine, char *buf, | ||
500 | size_t bufsz) | ||
501 | { | ||
502 | if (machine__is_default_guest(machine)) | ||
503 | scnprintf(buf, bufsz, "%s", symbol_conf.default_guest_kallsyms); | ||
504 | else | ||
505 | scnprintf(buf, bufsz, "%s/proc/kallsyms", machine->root_dir); | ||
506 | } | ||
507 | |||
498 | /* Figure out the start address of kernel map from /proc/kallsyms */ | 508 | /* Figure out the start address of kernel map from /proc/kallsyms */ |
499 | static u64 machine__get_kernel_start_addr(struct machine *machine) | 509 | static u64 machine__get_kernel_start_addr(struct machine *machine) |
500 | { | 510 | { |
501 | const char *filename; | 511 | char filename[PATH_MAX]; |
502 | char path[PATH_MAX]; | ||
503 | struct process_args args; | 512 | struct process_args args; |
504 | 513 | ||
505 | if (machine__is_host(machine)) { | 514 | machine__get_kallsyms_filename(machine, filename, PATH_MAX); |
506 | filename = "/proc/kallsyms"; | ||
507 | } else { | ||
508 | if (machine__is_default_guest(machine)) | ||
509 | filename = (char *)symbol_conf.default_guest_kallsyms; | ||
510 | else { | ||
511 | sprintf(path, "%s/proc/kallsyms", machine->root_dir); | ||
512 | filename = path; | ||
513 | } | ||
514 | } | ||
515 | 515 | ||
516 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) | 516 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) |
517 | return 0; | 517 | return 0; |
@@ -565,11 +565,10 @@ void machine__destroy_kernel_maps(struct machine *machine) | |||
565 | * on one of them. | 565 | * on one of them. |
566 | */ | 566 | */ |
567 | if (type == MAP__FUNCTION) { | 567 | if (type == MAP__FUNCTION) { |
568 | free((char *)kmap->ref_reloc_sym->name); | 568 | zfree((char **)&kmap->ref_reloc_sym->name); |
569 | kmap->ref_reloc_sym->name = NULL; | 569 | zfree(&kmap->ref_reloc_sym); |
570 | free(kmap->ref_reloc_sym); | 570 | } else |
571 | } | 571 | kmap->ref_reloc_sym = NULL; |
572 | kmap->ref_reloc_sym = NULL; | ||
573 | } | 572 | } |
574 | 573 | ||
575 | map__delete(machine->vmlinux_maps[type]); | 574 | map__delete(machine->vmlinux_maps[type]); |
@@ -767,8 +766,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg, | |||
767 | ret = -1; | 766 | ret = -1; |
768 | goto out; | 767 | goto out; |
769 | } | 768 | } |
770 | dso__set_long_name(map->dso, long_name); | 769 | dso__set_long_name(map->dso, long_name, true); |
771 | map->dso->lname_alloc = 1; | ||
772 | dso__kernel_module_get_build_id(map->dso, ""); | 770 | dso__kernel_module_get_build_id(map->dso, ""); |
773 | } | 771 | } |
774 | } | 772 | } |
@@ -834,9 +832,25 @@ static int machine__create_modules(struct machine *machine) | |||
834 | return 0; | 832 | return 0; |
835 | } | 833 | } |
836 | 834 | ||
835 | const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL}; | ||
836 | |||
837 | int machine__create_kernel_maps(struct machine *machine) | 837 | int machine__create_kernel_maps(struct machine *machine) |
838 | { | 838 | { |
839 | struct dso *kernel = machine__get_kernel(machine); | 839 | struct dso *kernel = machine__get_kernel(machine); |
840 | char filename[PATH_MAX]; | ||
841 | const char *name; | ||
842 | u64 addr = 0; | ||
843 | int i; | ||
844 | |||
845 | machine__get_kallsyms_filename(machine, filename, PATH_MAX); | ||
846 | |||
847 | for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) { | ||
848 | addr = kallsyms__get_function_start(filename, name); | ||
849 | if (addr) | ||
850 | break; | ||
851 | } | ||
852 | if (!addr) | ||
853 | return -1; | ||
840 | 854 | ||
841 | if (kernel == NULL || | 855 | if (kernel == NULL || |
842 | __machine__create_kernel_maps(machine, kernel) < 0) | 856 | __machine__create_kernel_maps(machine, kernel) < 0) |
@@ -855,6 +869,13 @@ int machine__create_kernel_maps(struct machine *machine) | |||
855 | * Now that we have all the maps created, just set the ->end of them: | 869 | * Now that we have all the maps created, just set the ->end of them: |
856 | */ | 870 | */ |
857 | map_groups__fixup_end(&machine->kmaps); | 871 | map_groups__fixup_end(&machine->kmaps); |
872 | |||
873 | if (maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name, | ||
874 | addr)) { | ||
875 | machine__destroy_kernel_maps(machine); | ||
876 | return -1; | ||
877 | } | ||
878 | |||
858 | return 0; | 879 | return 0; |
859 | } | 880 | } |
860 | 881 | ||
@@ -939,8 +960,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine, | |||
939 | if (name == NULL) | 960 | if (name == NULL) |
940 | goto out_problem; | 961 | goto out_problem; |
941 | 962 | ||
942 | map->dso->short_name = name; | 963 | dso__set_short_name(map->dso, name, true); |
943 | map->dso->sname_alloc = 1; | ||
944 | map->end = map->start + event->mmap.len; | 964 | map->end = map->start + event->mmap.len; |
945 | } else if (is_kernel_mmap) { | 965 | } else if (is_kernel_mmap) { |
946 | const char *symbol_name = (event->mmap.filename + | 966 | const char *symbol_name = (event->mmap.filename + |
@@ -1193,7 +1213,7 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread, | |||
1193 | */ | 1213 | */ |
1194 | thread__find_addr_location(thread, machine, m, MAP__FUNCTION, | 1214 | thread__find_addr_location(thread, machine, m, MAP__FUNCTION, |
1195 | ip, &al); | 1215 | ip, &al); |
1196 | if (al.sym) | 1216 | if (al.map) |
1197 | goto found; | 1217 | goto found; |
1198 | } | 1218 | } |
1199 | found: | 1219 | found: |
@@ -1320,8 +1340,6 @@ static int machine__resolve_callchain_sample(struct machine *machine, | |||
1320 | *root_al = al; | 1340 | *root_al = al; |
1321 | callchain_cursor_reset(&callchain_cursor); | 1341 | callchain_cursor_reset(&callchain_cursor); |
1322 | } | 1342 | } |
1323 | if (!symbol_conf.use_callchain) | ||
1324 | break; | ||
1325 | } | 1343 | } |
1326 | 1344 | ||
1327 | err = callchain_cursor_append(&callchain_cursor, | 1345 | err = callchain_cursor_append(&callchain_cursor, |
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 477133015440..f77e91e483dc 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
@@ -18,6 +18,8 @@ union perf_event; | |||
18 | #define HOST_KERNEL_ID (-1) | 18 | #define HOST_KERNEL_ID (-1) |
19 | #define DEFAULT_GUEST_KERNEL_ID (0) | 19 | #define DEFAULT_GUEST_KERNEL_ID (0) |
20 | 20 | ||
21 | extern const char *ref_reloc_sym_names[]; | ||
22 | |||
21 | struct machine { | 23 | struct machine { |
22 | struct rb_node rb_node; | 24 | struct rb_node rb_node; |
23 | pid_t pid; | 25 | pid_t pid; |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index ef5bc913ca7a..39cd2d0faff6 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include "strlist.h" | 11 | #include "strlist.h" |
12 | #include "vdso.h" | 12 | #include "vdso.h" |
13 | #include "build-id.h" | 13 | #include "build-id.h" |
14 | #include "util.h" | ||
14 | #include <linux/string.h> | 15 | #include <linux/string.h> |
15 | 16 | ||
16 | const char *map_type__name[MAP__NR_TYPES] = { | 17 | const char *map_type__name[MAP__NR_TYPES] = { |
@@ -38,6 +39,7 @@ void map__init(struct map *map, enum map_type type, | |||
38 | map->start = start; | 39 | map->start = start; |
39 | map->end = end; | 40 | map->end = end; |
40 | map->pgoff = pgoff; | 41 | map->pgoff = pgoff; |
42 | map->reloc = 0; | ||
41 | map->dso = dso; | 43 | map->dso = dso; |
42 | map->map_ip = map__map_ip; | 44 | map->map_ip = map__map_ip; |
43 | map->unmap_ip = map__unmap_ip; | 45 | map->unmap_ip = map__unmap_ip; |
@@ -68,7 +70,7 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | |||
68 | map->ino = ino; | 70 | map->ino = ino; |
69 | map->ino_generation = ino_gen; | 71 | map->ino_generation = ino_gen; |
70 | 72 | ||
71 | if (anon) { | 73 | if ((anon || no_dso) && type == MAP__FUNCTION) { |
72 | snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); | 74 | snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); |
73 | filename = newfilename; | 75 | filename = newfilename; |
74 | } | 76 | } |
@@ -92,7 +94,7 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | |||
92 | * functions still return NULL, and we avoid the | 94 | * functions still return NULL, and we avoid the |
93 | * unnecessary map__load warning. | 95 | * unnecessary map__load warning. |
94 | */ | 96 | */ |
95 | if (no_dso) | 97 | if (type != MAP__FUNCTION) |
96 | dso__set_loaded(dso, map->type); | 98 | dso__set_loaded(dso, map->type); |
97 | } | 99 | } |
98 | } | 100 | } |
@@ -252,6 +254,22 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp) | |||
252 | return fprintf(fp, "%s", dsoname); | 254 | return fprintf(fp, "%s", dsoname); |
253 | } | 255 | } |
254 | 256 | ||
257 | int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, | ||
258 | FILE *fp) | ||
259 | { | ||
260 | char *srcline; | ||
261 | int ret = 0; | ||
262 | |||
263 | if (map && map->dso) { | ||
264 | srcline = get_srcline(map->dso, | ||
265 | map__rip_2objdump(map, addr)); | ||
266 | if (srcline != SRCLINE_UNKNOWN) | ||
267 | ret = fprintf(fp, "%s%s", prefix, srcline); | ||
268 | free_srcline(srcline); | ||
269 | } | ||
270 | return ret; | ||
271 | } | ||
272 | |||
255 | /** | 273 | /** |
256 | * map__rip_2objdump - convert symbol start address to objdump address. | 274 | * map__rip_2objdump - convert symbol start address to objdump address. |
257 | * @map: memory map | 275 | * @map: memory map |
@@ -271,7 +289,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip) | |||
271 | if (map->dso->rel) | 289 | if (map->dso->rel) |
272 | return rip - map->pgoff; | 290 | return rip - map->pgoff; |
273 | 291 | ||
274 | return map->unmap_ip(map, rip); | 292 | return map->unmap_ip(map, rip) - map->reloc; |
275 | } | 293 | } |
276 | 294 | ||
277 | /** | 295 | /** |
@@ -294,7 +312,7 @@ u64 map__objdump_2mem(struct map *map, u64 ip) | |||
294 | if (map->dso->rel) | 312 | if (map->dso->rel) |
295 | return map->unmap_ip(map, ip + map->pgoff); | 313 | return map->unmap_ip(map, ip + map->pgoff); |
296 | 314 | ||
297 | return ip; | 315 | return ip + map->reloc; |
298 | } | 316 | } |
299 | 317 | ||
300 | void map_groups__init(struct map_groups *mg) | 318 | void map_groups__init(struct map_groups *mg) |
@@ -369,7 +387,8 @@ struct symbol *map_groups__find_symbol(struct map_groups *mg, | |||
369 | { | 387 | { |
370 | struct map *map = map_groups__find(mg, type, addr); | 388 | struct map *map = map_groups__find(mg, type, addr); |
371 | 389 | ||
372 | if (map != NULL) { | 390 | /* Ensure map is loaded before using map->map_ip */ |
391 | if (map != NULL && map__load(map, filter) >= 0) { | ||
373 | if (mapp != NULL) | 392 | if (mapp != NULL) |
374 | *mapp = map; | 393 | *mapp = map; |
375 | return map__find_symbol(map, map->map_ip(map, addr), filter); | 394 | return map__find_symbol(map, map->map_ip(map, addr), filter); |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index e4e259c3ba16..257e513205ce 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -36,6 +36,7 @@ struct map { | |||
36 | bool erange_warned; | 36 | bool erange_warned; |
37 | u32 priv; | 37 | u32 priv; |
38 | u64 pgoff; | 38 | u64 pgoff; |
39 | u64 reloc; | ||
39 | u32 maj, min; /* only valid for MMAP2 record */ | 40 | u32 maj, min; /* only valid for MMAP2 record */ |
40 | u64 ino; /* only valid for MMAP2 record */ | 41 | u64 ino; /* only valid for MMAP2 record */ |
41 | u64 ino_generation;/* only valid for MMAP2 record */ | 42 | u64 ino_generation;/* only valid for MMAP2 record */ |
@@ -103,6 +104,8 @@ struct map *map__clone(struct map *map); | |||
103 | int map__overlap(struct map *l, struct map *r); | 104 | int map__overlap(struct map *l, struct map *r); |
104 | size_t map__fprintf(struct map *map, FILE *fp); | 105 | size_t map__fprintf(struct map *map, FILE *fp); |
105 | size_t map__fprintf_dsoname(struct map *map, FILE *fp); | 106 | size_t map__fprintf_dsoname(struct map *map, FILE *fp); |
107 | int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, | ||
108 | FILE *fp); | ||
106 | 109 | ||
107 | int map__load(struct map *map, symbol_filter_t filter); | 110 | int map__load(struct map *map, symbol_filter_t filter); |
108 | struct symbol *map__find_symbol(struct map *map, | 111 | struct symbol *map__find_symbol(struct map *map, |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 6de6f89c2a61..1e15df10a88c 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -10,7 +10,7 @@ | |||
10 | #include "symbol.h" | 10 | #include "symbol.h" |
11 | #include "cache.h" | 11 | #include "cache.h" |
12 | #include "header.h" | 12 | #include "header.h" |
13 | #include <lk/debugfs.h> | 13 | #include <api/fs/debugfs.h> |
14 | #include "parse-events-bison.h" | 14 | #include "parse-events-bison.h" |
15 | #define YY_EXTRA_TYPE int | 15 | #define YY_EXTRA_TYPE int |
16 | #include "parse-events-flex.h" | 16 | #include "parse-events-flex.h" |
@@ -204,7 +204,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) | |||
204 | } | 204 | } |
205 | path->name = malloc(MAX_EVENT_LENGTH); | 205 | path->name = malloc(MAX_EVENT_LENGTH); |
206 | if (!path->name) { | 206 | if (!path->name) { |
207 | free(path->system); | 207 | zfree(&path->system); |
208 | free(path); | 208 | free(path); |
209 | return NULL; | 209 | return NULL; |
210 | } | 210 | } |
@@ -236,8 +236,8 @@ struct tracepoint_path *tracepoint_name_to_path(const char *name) | |||
236 | path->name = strdup(str+1); | 236 | path->name = strdup(str+1); |
237 | 237 | ||
238 | if (path->system == NULL || path->name == NULL) { | 238 | if (path->system == NULL || path->name == NULL) { |
239 | free(path->system); | 239 | zfree(&path->system); |
240 | free(path->name); | 240 | zfree(&path->name); |
241 | free(path); | 241 | free(path); |
242 | path = NULL; | 242 | path = NULL; |
243 | } | 243 | } |
@@ -269,9 +269,10 @@ const char *event_type(int type) | |||
269 | 269 | ||
270 | 270 | ||
271 | 271 | ||
272 | static int __add_event(struct list_head *list, int *idx, | 272 | static struct perf_evsel * |
273 | struct perf_event_attr *attr, | 273 | __add_event(struct list_head *list, int *idx, |
274 | char *name, struct cpu_map *cpus) | 274 | struct perf_event_attr *attr, |
275 | char *name, struct cpu_map *cpus) | ||
275 | { | 276 | { |
276 | struct perf_evsel *evsel; | 277 | struct perf_evsel *evsel; |
277 | 278 | ||
@@ -279,19 +280,19 @@ static int __add_event(struct list_head *list, int *idx, | |||
279 | 280 | ||
280 | evsel = perf_evsel__new_idx(attr, (*idx)++); | 281 | evsel = perf_evsel__new_idx(attr, (*idx)++); |
281 | if (!evsel) | 282 | if (!evsel) |
282 | return -ENOMEM; | 283 | return NULL; |
283 | 284 | ||
284 | evsel->cpus = cpus; | 285 | evsel->cpus = cpus; |
285 | if (name) | 286 | if (name) |
286 | evsel->name = strdup(name); | 287 | evsel->name = strdup(name); |
287 | list_add_tail(&evsel->node, list); | 288 | list_add_tail(&evsel->node, list); |
288 | return 0; | 289 | return evsel; |
289 | } | 290 | } |
290 | 291 | ||
291 | static int add_event(struct list_head *list, int *idx, | 292 | static int add_event(struct list_head *list, int *idx, |
292 | struct perf_event_attr *attr, char *name) | 293 | struct perf_event_attr *attr, char *name) |
293 | { | 294 | { |
294 | return __add_event(list, idx, attr, name, NULL); | 295 | return __add_event(list, idx, attr, name, NULL) ? 0 : -ENOMEM; |
295 | } | 296 | } |
296 | 297 | ||
297 | static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) | 298 | static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) |
@@ -633,6 +634,9 @@ int parse_events_add_pmu(struct list_head *list, int *idx, | |||
633 | { | 634 | { |
634 | struct perf_event_attr attr; | 635 | struct perf_event_attr attr; |
635 | struct perf_pmu *pmu; | 636 | struct perf_pmu *pmu; |
637 | struct perf_evsel *evsel; | ||
638 | const char *unit; | ||
639 | double scale; | ||
636 | 640 | ||
637 | pmu = perf_pmu__find(name); | 641 | pmu = perf_pmu__find(name); |
638 | if (!pmu) | 642 | if (!pmu) |
@@ -640,7 +644,7 @@ int parse_events_add_pmu(struct list_head *list, int *idx, | |||
640 | 644 | ||
641 | memset(&attr, 0, sizeof(attr)); | 645 | memset(&attr, 0, sizeof(attr)); |
642 | 646 | ||
643 | if (perf_pmu__check_alias(pmu, head_config)) | 647 | if (perf_pmu__check_alias(pmu, head_config, &unit, &scale)) |
644 | return -EINVAL; | 648 | return -EINVAL; |
645 | 649 | ||
646 | /* | 650 | /* |
@@ -652,8 +656,14 @@ int parse_events_add_pmu(struct list_head *list, int *idx, | |||
652 | if (perf_pmu__config(pmu, &attr, head_config)) | 656 | if (perf_pmu__config(pmu, &attr, head_config)) |
653 | return -EINVAL; | 657 | return -EINVAL; |
654 | 658 | ||
655 | return __add_event(list, idx, &attr, pmu_event_name(head_config), | 659 | evsel = __add_event(list, idx, &attr, pmu_event_name(head_config), |
656 | pmu->cpus); | 660 | pmu->cpus); |
661 | if (evsel) { | ||
662 | evsel->unit = unit; | ||
663 | evsel->scale = scale; | ||
664 | } | ||
665 | |||
666 | return evsel ? 0 : -ENOMEM; | ||
657 | } | 667 | } |
658 | 668 | ||
659 | int parse_events__modifier_group(struct list_head *list, | 669 | int parse_events__modifier_group(struct list_head *list, |
@@ -810,8 +820,7 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add) | |||
810 | if (!add && get_event_modifier(&mod, str, NULL)) | 820 | if (!add && get_event_modifier(&mod, str, NULL)) |
811 | return -EINVAL; | 821 | return -EINVAL; |
812 | 822 | ||
813 | list_for_each_entry(evsel, list, node) { | 823 | __evlist__for_each(list, evsel) { |
814 | |||
815 | if (add && get_event_modifier(&mod, str, evsel)) | 824 | if (add && get_event_modifier(&mod, str, evsel)) |
816 | return -EINVAL; | 825 | return -EINVAL; |
817 | 826 | ||
@@ -835,7 +844,7 @@ int parse_events_name(struct list_head *list, char *name) | |||
835 | { | 844 | { |
836 | struct perf_evsel *evsel; | 845 | struct perf_evsel *evsel; |
837 | 846 | ||
838 | list_for_each_entry(evsel, list, node) { | 847 | __evlist__for_each(list, evsel) { |
839 | if (!evsel->name) | 848 | if (!evsel->name) |
840 | evsel->name = strdup(name); | 849 | evsel->name = strdup(name); |
841 | } | 850 | } |
@@ -907,7 +916,7 @@ int parse_events_terms(struct list_head *terms, const char *str) | |||
907 | ret = parse_events__scanner(str, &data, PE_START_TERMS); | 916 | ret = parse_events__scanner(str, &data, PE_START_TERMS); |
908 | if (!ret) { | 917 | if (!ret) { |
909 | list_splice(data.terms, terms); | 918 | list_splice(data.terms, terms); |
910 | free(data.terms); | 919 | zfree(&data.terms); |
911 | return 0; | 920 | return 0; |
912 | } | 921 | } |
913 | 922 | ||
@@ -1082,12 +1091,12 @@ int is_valid_tracepoint(const char *event_string) | |||
1082 | static bool is_event_supported(u8 type, unsigned config) | 1091 | static bool is_event_supported(u8 type, unsigned config) |
1083 | { | 1092 | { |
1084 | bool ret = true; | 1093 | bool ret = true; |
1094 | int open_return; | ||
1085 | struct perf_evsel *evsel; | 1095 | struct perf_evsel *evsel; |
1086 | struct perf_event_attr attr = { | 1096 | struct perf_event_attr attr = { |
1087 | .type = type, | 1097 | .type = type, |
1088 | .config = config, | 1098 | .config = config, |
1089 | .disabled = 1, | 1099 | .disabled = 1, |
1090 | .exclude_kernel = 1, | ||
1091 | }; | 1100 | }; |
1092 | struct { | 1101 | struct { |
1093 | struct thread_map map; | 1102 | struct thread_map map; |
@@ -1099,7 +1108,20 @@ static bool is_event_supported(u8 type, unsigned config) | |||
1099 | 1108 | ||
1100 | evsel = perf_evsel__new(&attr); | 1109 | evsel = perf_evsel__new(&attr); |
1101 | if (evsel) { | 1110 | if (evsel) { |
1102 | ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0; | 1111 | open_return = perf_evsel__open(evsel, NULL, &tmap.map); |
1112 | ret = open_return >= 0; | ||
1113 | |||
1114 | if (open_return == -EACCES) { | ||
1115 | /* | ||
1116 | * This happens if the paranoid value | ||
1117 | * /proc/sys/kernel/perf_event_paranoid is set to 2 | ||
1118 | * Re-run with exclude_kernel set; we don't do that | ||
1119 | * by default as some ARM machines do not support it. | ||
1120 | * | ||
1121 | */ | ||
1122 | evsel->attr.exclude_kernel = 1; | ||
1123 | ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0; | ||
1124 | } | ||
1103 | perf_evsel__delete(evsel); | 1125 | perf_evsel__delete(evsel); |
1104 | } | 1126 | } |
1105 | 1127 | ||
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index 31f404a032a9..d22e3f8017dc 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c | |||
@@ -78,6 +78,8 @@ static int get_value(struct parse_opt_ctx_t *p, | |||
78 | 78 | ||
79 | case OPTION_BOOLEAN: | 79 | case OPTION_BOOLEAN: |
80 | *(bool *)opt->value = unset ? false : true; | 80 | *(bool *)opt->value = unset ? false : true; |
81 | if (opt->set) | ||
82 | *(bool *)opt->set = true; | ||
81 | return 0; | 83 | return 0; |
82 | 84 | ||
83 | case OPTION_INCR: | 85 | case OPTION_INCR: |
@@ -224,6 +226,24 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, | |||
224 | return 0; | 226 | return 0; |
225 | } | 227 | } |
226 | if (!rest) { | 228 | if (!rest) { |
229 | if (!prefixcmp(options->long_name, "no-")) { | ||
230 | /* | ||
231 | * The long name itself starts with "no-", so | ||
232 | * accept the option without "no-" so that users | ||
233 | * do not have to enter "no-no-" to get the | ||
234 | * negation. | ||
235 | */ | ||
236 | rest = skip_prefix(arg, options->long_name + 3); | ||
237 | if (rest) { | ||
238 | flags |= OPT_UNSET; | ||
239 | goto match; | ||
240 | } | ||
241 | /* Abbreviated case */ | ||
242 | if (!prefixcmp(options->long_name + 3, arg)) { | ||
243 | flags |= OPT_UNSET; | ||
244 | goto is_abbreviated; | ||
245 | } | ||
246 | } | ||
227 | /* abbreviated? */ | 247 | /* abbreviated? */ |
228 | if (!strncmp(options->long_name, arg, arg_end - arg)) { | 248 | if (!strncmp(options->long_name, arg, arg_end - arg)) { |
229 | is_abbreviated: | 249 | is_abbreviated: |
@@ -259,6 +279,7 @@ is_abbreviated: | |||
259 | if (!rest) | 279 | if (!rest) |
260 | continue; | 280 | continue; |
261 | } | 281 | } |
282 | match: | ||
262 | if (*rest) { | 283 | if (*rest) { |
263 | if (*rest != '=') | 284 | if (*rest != '=') |
264 | continue; | 285 | continue; |
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h index b0241e28eaf7..cbf0149cf221 100644 --- a/tools/perf/util/parse-options.h +++ b/tools/perf/util/parse-options.h | |||
@@ -82,6 +82,9 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset); | |||
82 | * OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in | 82 | * OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in |
83 | * the value when met. | 83 | * the value when met. |
84 | * CALLBACKS can use it like they want. | 84 | * CALLBACKS can use it like they want. |
85 | * | ||
86 | * `set`:: | ||
87 | * whether an option was set by the user | ||
85 | */ | 88 | */ |
86 | struct option { | 89 | struct option { |
87 | enum parse_opt_type type; | 90 | enum parse_opt_type type; |
@@ -94,6 +97,7 @@ struct option { | |||
94 | int flags; | 97 | int flags; |
95 | parse_opt_cb *callback; | 98 | parse_opt_cb *callback; |
96 | intptr_t defval; | 99 | intptr_t defval; |
100 | bool *set; | ||
97 | }; | 101 | }; |
98 | 102 | ||
99 | #define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v ) | 103 | #define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v ) |
@@ -103,6 +107,10 @@ struct option { | |||
103 | #define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) } | 107 | #define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) } |
104 | #define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h), .defval = (b) } | 108 | #define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h), .defval = (b) } |
105 | #define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) } | 109 | #define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) } |
110 | #define OPT_BOOLEAN_SET(s, l, v, os, h) \ | ||
111 | { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), \ | ||
112 | .value = check_vtype(v, bool *), .help = (h), \ | ||
113 | .set = check_vtype(os, bool *)} | ||
106 | #define OPT_INCR(s, l, v, h) { .type = OPTION_INCR, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) } | 114 | #define OPT_INCR(s, l, v, h) { .type = OPTION_INCR, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) } |
107 | #define OPT_SET_UINT(s, l, v, h, i) { .type = OPTION_SET_UINT, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h), .defval = (i) } | 115 | #define OPT_SET_UINT(s, l, v, h, i) { .type = OPTION_SET_UINT, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h), .defval = (i) } |
108 | #define OPT_SET_PTR(s, l, v, h, p) { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) } | 116 | #define OPT_SET_PTR(s, l, v, h, p) { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) } |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index c232d8dd410b..b752ecb40d86 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -1,19 +1,23 @@ | |||
1 | #include <linux/list.h> | 1 | #include <linux/list.h> |
2 | #include <sys/types.h> | 2 | #include <sys/types.h> |
3 | #include <sys/stat.h> | ||
4 | #include <unistd.h> | 3 | #include <unistd.h> |
5 | #include <stdio.h> | 4 | #include <stdio.h> |
6 | #include <dirent.h> | 5 | #include <dirent.h> |
7 | #include "fs.h" | 6 | #include "fs.h" |
7 | #include <locale.h> | ||
8 | #include "util.h" | 8 | #include "util.h" |
9 | #include "pmu.h" | 9 | #include "pmu.h" |
10 | #include "parse-events.h" | 10 | #include "parse-events.h" |
11 | #include "cpumap.h" | 11 | #include "cpumap.h" |
12 | 12 | ||
13 | #define UNIT_MAX_LEN 31 /* max length for event unit name */ | ||
14 | |||
13 | struct perf_pmu_alias { | 15 | struct perf_pmu_alias { |
14 | char *name; | 16 | char *name; |
15 | struct list_head terms; | 17 | struct list_head terms; |
16 | struct list_head list; | 18 | struct list_head list; |
19 | char unit[UNIT_MAX_LEN+1]; | ||
20 | double scale; | ||
17 | }; | 21 | }; |
18 | 22 | ||
19 | struct perf_pmu_format { | 23 | struct perf_pmu_format { |
@@ -94,7 +98,80 @@ static int pmu_format(const char *name, struct list_head *format) | |||
94 | return 0; | 98 | return 0; |
95 | } | 99 | } |
96 | 100 | ||
97 | static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) | 101 | static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) |
102 | { | ||
103 | struct stat st; | ||
104 | ssize_t sret; | ||
105 | char scale[128]; | ||
106 | int fd, ret = -1; | ||
107 | char path[PATH_MAX]; | ||
108 | const char *lc; | ||
109 | |||
110 | snprintf(path, PATH_MAX, "%s/%s.scale", dir, name); | ||
111 | |||
112 | fd = open(path, O_RDONLY); | ||
113 | if (fd == -1) | ||
114 | return -1; | ||
115 | |||
116 | if (fstat(fd, &st) < 0) | ||
117 | goto error; | ||
118 | |||
119 | sret = read(fd, scale, sizeof(scale)-1); | ||
120 | if (sret < 0) | ||
121 | goto error; | ||
122 | |||
123 | scale[sret] = '\0'; | ||
124 | /* | ||
125 | * save current locale | ||
126 | */ | ||
127 | lc = setlocale(LC_NUMERIC, NULL); | ||
128 | |||
129 | /* | ||
130 | * force to C locale to ensure kernel | ||
131 | * scale string is converted correctly. | ||
132 | * kernel uses default C locale. | ||
133 | */ | ||
134 | setlocale(LC_NUMERIC, "C"); | ||
135 | |||
136 | alias->scale = strtod(scale, NULL); | ||
137 | |||
138 | /* restore locale */ | ||
139 | setlocale(LC_NUMERIC, lc); | ||
140 | |||
141 | ret = 0; | ||
142 | error: | ||
143 | close(fd); | ||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name) | ||
148 | { | ||
149 | char path[PATH_MAX]; | ||
150 | ssize_t sret; | ||
151 | int fd; | ||
152 | |||
153 | snprintf(path, PATH_MAX, "%s/%s.unit", dir, name); | ||
154 | |||
155 | fd = open(path, O_RDONLY); | ||
156 | if (fd == -1) | ||
157 | return -1; | ||
158 | |||
159 | sret = read(fd, alias->unit, UNIT_MAX_LEN); | ||
160 | if (sret < 0) | ||
161 | goto error; | ||
162 | |||
163 | close(fd); | ||
164 | |||
165 | alias->unit[sret] = '\0'; | ||
166 | |||
167 | return 0; | ||
168 | error: | ||
169 | close(fd); | ||
170 | alias->unit[0] = '\0'; | ||
171 | return -1; | ||
172 | } | ||
173 | |||
174 | static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) | ||
98 | { | 175 | { |
99 | struct perf_pmu_alias *alias; | 176 | struct perf_pmu_alias *alias; |
100 | char buf[256]; | 177 | char buf[256]; |
@@ -110,6 +187,9 @@ static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) | |||
110 | return -ENOMEM; | 187 | return -ENOMEM; |
111 | 188 | ||
112 | INIT_LIST_HEAD(&alias->terms); | 189 | INIT_LIST_HEAD(&alias->terms); |
190 | alias->scale = 1.0; | ||
191 | alias->unit[0] = '\0'; | ||
192 | |||
113 | ret = parse_events_terms(&alias->terms, buf); | 193 | ret = parse_events_terms(&alias->terms, buf); |
114 | if (ret) { | 194 | if (ret) { |
115 | free(alias); | 195 | free(alias); |
@@ -117,7 +197,14 @@ static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) | |||
117 | } | 197 | } |
118 | 198 | ||
119 | alias->name = strdup(name); | 199 | alias->name = strdup(name); |
200 | /* | ||
201 | * load unit name and scale if available | ||
202 | */ | ||
203 | perf_pmu__parse_unit(alias, dir, name); | ||
204 | perf_pmu__parse_scale(alias, dir, name); | ||
205 | |||
120 | list_add_tail(&alias->list, list); | 206 | list_add_tail(&alias->list, list); |
207 | |||
121 | return 0; | 208 | return 0; |
122 | } | 209 | } |
123 | 210 | ||
@@ -129,6 +216,7 @@ static int pmu_aliases_parse(char *dir, struct list_head *head) | |||
129 | { | 216 | { |
130 | struct dirent *evt_ent; | 217 | struct dirent *evt_ent; |
131 | DIR *event_dir; | 218 | DIR *event_dir; |
219 | size_t len; | ||
132 | int ret = 0; | 220 | int ret = 0; |
133 | 221 | ||
134 | event_dir = opendir(dir); | 222 | event_dir = opendir(dir); |
@@ -143,13 +231,24 @@ static int pmu_aliases_parse(char *dir, struct list_head *head) | |||
143 | if (!strcmp(name, ".") || !strcmp(name, "..")) | 231 | if (!strcmp(name, ".") || !strcmp(name, "..")) |
144 | continue; | 232 | continue; |
145 | 233 | ||
234 | /* | ||
235 | * skip .unit and .scale info files | ||
236 | * parsed in perf_pmu__new_alias() | ||
237 | */ | ||
238 | len = strlen(name); | ||
239 | if (len > 5 && !strcmp(name + len - 5, ".unit")) | ||
240 | continue; | ||
241 | if (len > 6 && !strcmp(name + len - 6, ".scale")) | ||
242 | continue; | ||
243 | |||
146 | snprintf(path, PATH_MAX, "%s/%s", dir, name); | 244 | snprintf(path, PATH_MAX, "%s/%s", dir, name); |
147 | 245 | ||
148 | ret = -EINVAL; | 246 | ret = -EINVAL; |
149 | file = fopen(path, "r"); | 247 | file = fopen(path, "r"); |
150 | if (!file) | 248 | if (!file) |
151 | break; | 249 | break; |
152 | ret = perf_pmu__new_alias(head, name, file); | 250 | |
251 | ret = perf_pmu__new_alias(head, dir, name, file); | ||
153 | fclose(file); | 252 | fclose(file); |
154 | } | 253 | } |
155 | 254 | ||
@@ -406,7 +505,7 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value) | |||
406 | 505 | ||
407 | /* | 506 | /* |
408 | * Setup one of config[12] attr members based on the | 507 | * Setup one of config[12] attr members based on the |
409 | * user input data - temr parameter. | 508 | * user input data - term parameter. |
410 | */ | 509 | */ |
411 | static int pmu_config_term(struct list_head *formats, | 510 | static int pmu_config_term(struct list_head *formats, |
412 | struct perf_event_attr *attr, | 511 | struct perf_event_attr *attr, |
@@ -508,16 +607,46 @@ static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, | |||
508 | return NULL; | 607 | return NULL; |
509 | } | 608 | } |
510 | 609 | ||
610 | |||
611 | static int check_unit_scale(struct perf_pmu_alias *alias, | ||
612 | const char **unit, double *scale) | ||
613 | { | ||
614 | /* | ||
615 | * Only one term in event definition can | ||
616 | * define unit and scale, fail if there's | ||
617 | * more than one. | ||
618 | */ | ||
619 | if ((*unit && alias->unit) || | ||
620 | (*scale && alias->scale)) | ||
621 | return -EINVAL; | ||
622 | |||
623 | if (alias->unit) | ||
624 | *unit = alias->unit; | ||
625 | |||
626 | if (alias->scale) | ||
627 | *scale = alias->scale; | ||
628 | |||
629 | return 0; | ||
630 | } | ||
631 | |||
511 | /* | 632 | /* |
512 | * Find alias in the terms list and replace it with the terms | 633 | * Find alias in the terms list and replace it with the terms |
513 | * defined for the alias | 634 | * defined for the alias |
514 | */ | 635 | */ |
515 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) | 636 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, |
637 | const char **unit, double *scale) | ||
516 | { | 638 | { |
517 | struct parse_events_term *term, *h; | 639 | struct parse_events_term *term, *h; |
518 | struct perf_pmu_alias *alias; | 640 | struct perf_pmu_alias *alias; |
519 | int ret; | 641 | int ret; |
520 | 642 | ||
643 | /* | ||
644 | * Mark unit and scale as not set | ||
645 | * (different from default values, see below) | ||
646 | */ | ||
647 | *unit = NULL; | ||
648 | *scale = 0.0; | ||
649 | |||
521 | list_for_each_entry_safe(term, h, head_terms, list) { | 650 | list_for_each_entry_safe(term, h, head_terms, list) { |
522 | alias = pmu_find_alias(pmu, term); | 651 | alias = pmu_find_alias(pmu, term); |
523 | if (!alias) | 652 | if (!alias) |
@@ -525,9 +654,26 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) | |||
525 | ret = pmu_alias_terms(alias, &term->list); | 654 | ret = pmu_alias_terms(alias, &term->list); |
526 | if (ret) | 655 | if (ret) |
527 | return ret; | 656 | return ret; |
657 | |||
658 | ret = check_unit_scale(alias, unit, scale); | ||
659 | if (ret) | ||
660 | return ret; | ||
661 | |||
528 | list_del(&term->list); | 662 | list_del(&term->list); |
529 | free(term); | 663 | free(term); |
530 | } | 664 | } |
665 | |||
666 | /* | ||
667 | * if no unit or scale foundin aliases, then | ||
668 | * set defaults as for evsel | ||
669 | * unit cannot left to NULL | ||
670 | */ | ||
671 | if (*unit == NULL) | ||
672 | *unit = ""; | ||
673 | |||
674 | if (*scale == 0.0) | ||
675 | *scale = 1.0; | ||
676 | |||
531 | return 0; | 677 | return 0; |
532 | } | 678 | } |
533 | 679 | ||
@@ -625,7 +771,7 @@ void print_pmu_events(const char *event_glob, bool name_only) | |||
625 | continue; | 771 | continue; |
626 | } | 772 | } |
627 | printf(" %-50s [Kernel PMU event]\n", aliases[j]); | 773 | printf(" %-50s [Kernel PMU event]\n", aliases[j]); |
628 | free(aliases[j]); | 774 | zfree(&aliases[j]); |
629 | printed++; | 775 | printed++; |
630 | } | 776 | } |
631 | if (printed) | 777 | if (printed) |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 1179b26f244a..8b64125a9281 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -28,7 +28,8 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, | |||
28 | int perf_pmu__config_terms(struct list_head *formats, | 28 | int perf_pmu__config_terms(struct list_head *formats, |
29 | struct perf_event_attr *attr, | 29 | struct perf_event_attr *attr, |
30 | struct list_head *head_terms); | 30 | struct list_head *head_terms); |
31 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); | 31 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, |
32 | const char **unit, double *scale); | ||
32 | struct list_head *perf_pmu__alias(struct perf_pmu *pmu, | 33 | struct list_head *perf_pmu__alias(struct perf_pmu *pmu, |
33 | struct list_head *head_terms); | 34 | struct list_head *head_terms); |
34 | int perf_pmu_wrap(void); | 35 | int perf_pmu_wrap(void); |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 9c6989ca2bea..d8b048c20cde 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -40,7 +40,7 @@ | |||
40 | #include "color.h" | 40 | #include "color.h" |
41 | #include "symbol.h" | 41 | #include "symbol.h" |
42 | #include "thread.h" | 42 | #include "thread.h" |
43 | #include <lk/debugfs.h> | 43 | #include <api/fs/debugfs.h> |
44 | #include "trace-event.h" /* For __maybe_unused */ | 44 | #include "trace-event.h" /* For __maybe_unused */ |
45 | #include "probe-event.h" | 45 | #include "probe-event.h" |
46 | #include "probe-finder.h" | 46 | #include "probe-finder.h" |
@@ -72,6 +72,7 @@ static int e_snprintf(char *str, size_t size, const char *format, ...) | |||
72 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); | 72 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); |
73 | static int convert_name_to_addr(struct perf_probe_event *pev, | 73 | static int convert_name_to_addr(struct perf_probe_event *pev, |
74 | const char *exec); | 74 | const char *exec); |
75 | static void clear_probe_trace_event(struct probe_trace_event *tev); | ||
75 | static struct machine machine; | 76 | static struct machine machine; |
76 | 77 | ||
77 | /* Initialize symbol maps and path of vmlinux/modules */ | 78 | /* Initialize symbol maps and path of vmlinux/modules */ |
@@ -154,7 +155,7 @@ static struct dso *kernel_get_module_dso(const char *module) | |||
154 | 155 | ||
155 | vmlinux_name = symbol_conf.vmlinux_name; | 156 | vmlinux_name = symbol_conf.vmlinux_name; |
156 | if (vmlinux_name) { | 157 | if (vmlinux_name) { |
157 | if (dso__load_vmlinux(dso, map, vmlinux_name, NULL) <= 0) | 158 | if (dso__load_vmlinux(dso, map, vmlinux_name, false, NULL) <= 0) |
158 | return NULL; | 159 | return NULL; |
159 | } else { | 160 | } else { |
160 | if (dso__load_vmlinux_path(dso, map, NULL) <= 0) { | 161 | if (dso__load_vmlinux_path(dso, map, NULL) <= 0) { |
@@ -186,6 +187,37 @@ static int init_user_exec(void) | |||
186 | return ret; | 187 | return ret; |
187 | } | 188 | } |
188 | 189 | ||
190 | static int convert_exec_to_group(const char *exec, char **result) | ||
191 | { | ||
192 | char *ptr1, *ptr2, *exec_copy; | ||
193 | char buf[64]; | ||
194 | int ret; | ||
195 | |||
196 | exec_copy = strdup(exec); | ||
197 | if (!exec_copy) | ||
198 | return -ENOMEM; | ||
199 | |||
200 | ptr1 = basename(exec_copy); | ||
201 | if (!ptr1) { | ||
202 | ret = -EINVAL; | ||
203 | goto out; | ||
204 | } | ||
205 | |||
206 | ptr2 = strpbrk(ptr1, "-._"); | ||
207 | if (ptr2) | ||
208 | *ptr2 = '\0'; | ||
209 | ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1); | ||
210 | if (ret < 0) | ||
211 | goto out; | ||
212 | |||
213 | *result = strdup(buf); | ||
214 | ret = *result ? 0 : -ENOMEM; | ||
215 | |||
216 | out: | ||
217 | free(exec_copy); | ||
218 | return ret; | ||
219 | } | ||
220 | |||
189 | static int convert_to_perf_probe_point(struct probe_trace_point *tp, | 221 | static int convert_to_perf_probe_point(struct probe_trace_point *tp, |
190 | struct perf_probe_point *pp) | 222 | struct perf_probe_point *pp) |
191 | { | 223 | { |
@@ -261,6 +293,68 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | |||
261 | return 0; | 293 | return 0; |
262 | } | 294 | } |
263 | 295 | ||
296 | static int get_text_start_address(const char *exec, unsigned long *address) | ||
297 | { | ||
298 | Elf *elf; | ||
299 | GElf_Ehdr ehdr; | ||
300 | GElf_Shdr shdr; | ||
301 | int fd, ret = -ENOENT; | ||
302 | |||
303 | fd = open(exec, O_RDONLY); | ||
304 | if (fd < 0) | ||
305 | return -errno; | ||
306 | |||
307 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
308 | if (elf == NULL) | ||
309 | return -EINVAL; | ||
310 | |||
311 | if (gelf_getehdr(elf, &ehdr) == NULL) | ||
312 | goto out; | ||
313 | |||
314 | if (!elf_section_by_name(elf, &ehdr, &shdr, ".text", NULL)) | ||
315 | goto out; | ||
316 | |||
317 | *address = shdr.sh_addr - shdr.sh_offset; | ||
318 | ret = 0; | ||
319 | out: | ||
320 | elf_end(elf); | ||
321 | return ret; | ||
322 | } | ||
323 | |||
324 | static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, | ||
325 | int ntevs, const char *exec) | ||
326 | { | ||
327 | int i, ret = 0; | ||
328 | unsigned long offset, stext = 0; | ||
329 | char buf[32]; | ||
330 | |||
331 | if (!exec) | ||
332 | return 0; | ||
333 | |||
334 | ret = get_text_start_address(exec, &stext); | ||
335 | if (ret < 0) | ||
336 | return ret; | ||
337 | |||
338 | for (i = 0; i < ntevs && ret >= 0; i++) { | ||
339 | /* point.address is the addres of point.symbol + point.offset */ | ||
340 | offset = tevs[i].point.address - stext; | ||
341 | tevs[i].point.offset = 0; | ||
342 | zfree(&tevs[i].point.symbol); | ||
343 | ret = e_snprintf(buf, 32, "0x%lx", offset); | ||
344 | if (ret < 0) | ||
345 | break; | ||
346 | tevs[i].point.module = strdup(exec); | ||
347 | tevs[i].point.symbol = strdup(buf); | ||
348 | if (!tevs[i].point.symbol || !tevs[i].point.module) { | ||
349 | ret = -ENOMEM; | ||
350 | break; | ||
351 | } | ||
352 | tevs[i].uprobes = true; | ||
353 | } | ||
354 | |||
355 | return ret; | ||
356 | } | ||
357 | |||
264 | static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, | 358 | static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, |
265 | int ntevs, const char *module) | 359 | int ntevs, const char *module) |
266 | { | 360 | { |
@@ -290,12 +384,18 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, | |||
290 | } | 384 | } |
291 | } | 385 | } |
292 | 386 | ||
293 | if (tmp) | 387 | free(tmp); |
294 | free(tmp); | ||
295 | |||
296 | return ret; | 388 | return ret; |
297 | } | 389 | } |
298 | 390 | ||
391 | static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) | ||
392 | { | ||
393 | int i; | ||
394 | |||
395 | for (i = 0; i < ntevs; i++) | ||
396 | clear_probe_trace_event(tevs + i); | ||
397 | } | ||
398 | |||
299 | /* Try to find perf_probe_event with debuginfo */ | 399 | /* Try to find perf_probe_event with debuginfo */ |
300 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | 400 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, |
301 | struct probe_trace_event **tevs, | 401 | struct probe_trace_event **tevs, |
@@ -305,15 +405,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
305 | struct debuginfo *dinfo; | 405 | struct debuginfo *dinfo; |
306 | int ntevs, ret = 0; | 406 | int ntevs, ret = 0; |
307 | 407 | ||
308 | if (pev->uprobes) { | ||
309 | if (need_dwarf) { | ||
310 | pr_warning("Debuginfo-analysis is not yet supported" | ||
311 | " with -x/--exec option.\n"); | ||
312 | return -ENOSYS; | ||
313 | } | ||
314 | return convert_name_to_addr(pev, target); | ||
315 | } | ||
316 | |||
317 | dinfo = open_debuginfo(target); | 408 | dinfo = open_debuginfo(target); |
318 | 409 | ||
319 | if (!dinfo) { | 410 | if (!dinfo) { |
@@ -332,9 +423,18 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
332 | 423 | ||
333 | if (ntevs > 0) { /* Succeeded to find trace events */ | 424 | if (ntevs > 0) { /* Succeeded to find trace events */ |
334 | pr_debug("find %d probe_trace_events.\n", ntevs); | 425 | pr_debug("find %d probe_trace_events.\n", ntevs); |
335 | if (target) | 426 | if (target) { |
336 | ret = add_module_to_probe_trace_events(*tevs, ntevs, | 427 | if (pev->uprobes) |
337 | target); | 428 | ret = add_exec_to_probe_trace_events(*tevs, |
429 | ntevs, target); | ||
430 | else | ||
431 | ret = add_module_to_probe_trace_events(*tevs, | ||
432 | ntevs, target); | ||
433 | } | ||
434 | if (ret < 0) { | ||
435 | clear_probe_trace_events(*tevs, ntevs); | ||
436 | zfree(tevs); | ||
437 | } | ||
338 | return ret < 0 ? ret : ntevs; | 438 | return ret < 0 ? ret : ntevs; |
339 | } | 439 | } |
340 | 440 | ||
@@ -401,15 +501,13 @@ static int get_real_path(const char *raw_path, const char *comp_dir, | |||
401 | case EFAULT: | 501 | case EFAULT: |
402 | raw_path = strchr(++raw_path, '/'); | 502 | raw_path = strchr(++raw_path, '/'); |
403 | if (!raw_path) { | 503 | if (!raw_path) { |
404 | free(*new_path); | 504 | zfree(new_path); |
405 | *new_path = NULL; | ||
406 | return -ENOENT; | 505 | return -ENOENT; |
407 | } | 506 | } |
408 | continue; | 507 | continue; |
409 | 508 | ||
410 | default: | 509 | default: |
411 | free(*new_path); | 510 | zfree(new_path); |
412 | *new_path = NULL; | ||
413 | return -errno; | 511 | return -errno; |
414 | } | 512 | } |
415 | } | 513 | } |
@@ -580,7 +678,7 @@ static int show_available_vars_at(struct debuginfo *dinfo, | |||
580 | */ | 678 | */ |
581 | fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, | 679 | fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, |
582 | vl->point.offset); | 680 | vl->point.offset); |
583 | free(vl->point.symbol); | 681 | zfree(&vl->point.symbol); |
584 | nvars = 0; | 682 | nvars = 0; |
585 | if (vl->vars) { | 683 | if (vl->vars) { |
586 | strlist__for_each(node, vl->vars) { | 684 | strlist__for_each(node, vl->vars) { |
@@ -647,16 +745,14 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | |||
647 | 745 | ||
648 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | 746 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, |
649 | struct probe_trace_event **tevs __maybe_unused, | 747 | struct probe_trace_event **tevs __maybe_unused, |
650 | int max_tevs __maybe_unused, const char *target) | 748 | int max_tevs __maybe_unused, |
749 | const char *target __maybe_unused) | ||
651 | { | 750 | { |
652 | if (perf_probe_event_need_dwarf(pev)) { | 751 | if (perf_probe_event_need_dwarf(pev)) { |
653 | pr_warning("Debuginfo-analysis is not supported.\n"); | 752 | pr_warning("Debuginfo-analysis is not supported.\n"); |
654 | return -ENOSYS; | 753 | return -ENOSYS; |
655 | } | 754 | } |
656 | 755 | ||
657 | if (pev->uprobes) | ||
658 | return convert_name_to_addr(pev, target); | ||
659 | |||
660 | return 0; | 756 | return 0; |
661 | } | 757 | } |
662 | 758 | ||
@@ -678,6 +774,28 @@ int show_available_vars(struct perf_probe_event *pevs __maybe_unused, | |||
678 | } | 774 | } |
679 | #endif | 775 | #endif |
680 | 776 | ||
777 | void line_range__clear(struct line_range *lr) | ||
778 | { | ||
779 | struct line_node *ln; | ||
780 | |||
781 | free(lr->function); | ||
782 | free(lr->file); | ||
783 | free(lr->path); | ||
784 | free(lr->comp_dir); | ||
785 | while (!list_empty(&lr->line_list)) { | ||
786 | ln = list_first_entry(&lr->line_list, struct line_node, list); | ||
787 | list_del(&ln->list); | ||
788 | free(ln); | ||
789 | } | ||
790 | memset(lr, 0, sizeof(*lr)); | ||
791 | } | ||
792 | |||
793 | void line_range__init(struct line_range *lr) | ||
794 | { | ||
795 | memset(lr, 0, sizeof(*lr)); | ||
796 | INIT_LIST_HEAD(&lr->line_list); | ||
797 | } | ||
798 | |||
681 | static int parse_line_num(char **ptr, int *val, const char *what) | 799 | static int parse_line_num(char **ptr, int *val, const char *what) |
682 | { | 800 | { |
683 | const char *start = *ptr; | 801 | const char *start = *ptr; |
@@ -1278,8 +1396,7 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) | |||
1278 | error: | 1396 | error: |
1279 | pr_debug("Failed to synthesize perf probe point: %s\n", | 1397 | pr_debug("Failed to synthesize perf probe point: %s\n", |
1280 | strerror(-ret)); | 1398 | strerror(-ret)); |
1281 | if (buf) | 1399 | free(buf); |
1282 | free(buf); | ||
1283 | return NULL; | 1400 | return NULL; |
1284 | } | 1401 | } |
1285 | 1402 | ||
@@ -1480,34 +1597,25 @@ void clear_perf_probe_event(struct perf_probe_event *pev) | |||
1480 | struct perf_probe_arg_field *field, *next; | 1597 | struct perf_probe_arg_field *field, *next; |
1481 | int i; | 1598 | int i; |
1482 | 1599 | ||
1483 | if (pev->event) | 1600 | free(pev->event); |
1484 | free(pev->event); | 1601 | free(pev->group); |
1485 | if (pev->group) | 1602 | free(pp->file); |
1486 | free(pev->group); | 1603 | free(pp->function); |
1487 | if (pp->file) | 1604 | free(pp->lazy_line); |
1488 | free(pp->file); | 1605 | |
1489 | if (pp->function) | ||
1490 | free(pp->function); | ||
1491 | if (pp->lazy_line) | ||
1492 | free(pp->lazy_line); | ||
1493 | for (i = 0; i < pev->nargs; i++) { | 1606 | for (i = 0; i < pev->nargs; i++) { |
1494 | if (pev->args[i].name) | 1607 | free(pev->args[i].name); |
1495 | free(pev->args[i].name); | 1608 | free(pev->args[i].var); |
1496 | if (pev->args[i].var) | 1609 | free(pev->args[i].type); |
1497 | free(pev->args[i].var); | ||
1498 | if (pev->args[i].type) | ||
1499 | free(pev->args[i].type); | ||
1500 | field = pev->args[i].field; | 1610 | field = pev->args[i].field; |
1501 | while (field) { | 1611 | while (field) { |
1502 | next = field->next; | 1612 | next = field->next; |
1503 | if (field->name) | 1613 | zfree(&field->name); |
1504 | free(field->name); | ||
1505 | free(field); | 1614 | free(field); |
1506 | field = next; | 1615 | field = next; |
1507 | } | 1616 | } |
1508 | } | 1617 | } |
1509 | if (pev->args) | 1618 | free(pev->args); |
1510 | free(pev->args); | ||
1511 | memset(pev, 0, sizeof(*pev)); | 1619 | memset(pev, 0, sizeof(*pev)); |
1512 | } | 1620 | } |
1513 | 1621 | ||
@@ -1516,21 +1624,14 @@ static void clear_probe_trace_event(struct probe_trace_event *tev) | |||
1516 | struct probe_trace_arg_ref *ref, *next; | 1624 | struct probe_trace_arg_ref *ref, *next; |
1517 | int i; | 1625 | int i; |
1518 | 1626 | ||
1519 | if (tev->event) | 1627 | free(tev->event); |
1520 | free(tev->event); | 1628 | free(tev->group); |
1521 | if (tev->group) | 1629 | free(tev->point.symbol); |
1522 | free(tev->group); | 1630 | free(tev->point.module); |
1523 | if (tev->point.symbol) | ||
1524 | free(tev->point.symbol); | ||
1525 | if (tev->point.module) | ||
1526 | free(tev->point.module); | ||
1527 | for (i = 0; i < tev->nargs; i++) { | 1631 | for (i = 0; i < tev->nargs; i++) { |
1528 | if (tev->args[i].name) | 1632 | free(tev->args[i].name); |
1529 | free(tev->args[i].name); | 1633 | free(tev->args[i].value); |
1530 | if (tev->args[i].value) | 1634 | free(tev->args[i].type); |
1531 | free(tev->args[i].value); | ||
1532 | if (tev->args[i].type) | ||
1533 | free(tev->args[i].type); | ||
1534 | ref = tev->args[i].ref; | 1635 | ref = tev->args[i].ref; |
1535 | while (ref) { | 1636 | while (ref) { |
1536 | next = ref->next; | 1637 | next = ref->next; |
@@ -1538,8 +1639,7 @@ static void clear_probe_trace_event(struct probe_trace_event *tev) | |||
1538 | ref = next; | 1639 | ref = next; |
1539 | } | 1640 | } |
1540 | } | 1641 | } |
1541 | if (tev->args) | 1642 | free(tev->args); |
1542 | free(tev->args); | ||
1543 | memset(tev, 0, sizeof(*tev)); | 1643 | memset(tev, 0, sizeof(*tev)); |
1544 | } | 1644 | } |
1545 | 1645 | ||
@@ -1913,14 +2013,29 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
1913 | int max_tevs, const char *target) | 2013 | int max_tevs, const char *target) |
1914 | { | 2014 | { |
1915 | struct symbol *sym; | 2015 | struct symbol *sym; |
1916 | int ret = 0, i; | 2016 | int ret, i; |
1917 | struct probe_trace_event *tev; | 2017 | struct probe_trace_event *tev; |
1918 | 2018 | ||
2019 | if (pev->uprobes && !pev->group) { | ||
2020 | /* Replace group name if not given */ | ||
2021 | ret = convert_exec_to_group(target, &pev->group); | ||
2022 | if (ret != 0) { | ||
2023 | pr_warning("Failed to make a group name.\n"); | ||
2024 | return ret; | ||
2025 | } | ||
2026 | } | ||
2027 | |||
1919 | /* Convert perf_probe_event with debuginfo */ | 2028 | /* Convert perf_probe_event with debuginfo */ |
1920 | ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); | 2029 | ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); |
1921 | if (ret != 0) | 2030 | if (ret != 0) |
1922 | return ret; /* Found in debuginfo or got an error */ | 2031 | return ret; /* Found in debuginfo or got an error */ |
1923 | 2032 | ||
2033 | if (pev->uprobes) { | ||
2034 | ret = convert_name_to_addr(pev, target); | ||
2035 | if (ret < 0) | ||
2036 | return ret; | ||
2037 | } | ||
2038 | |||
1924 | /* Allocate trace event buffer */ | 2039 | /* Allocate trace event buffer */ |
1925 | tev = *tevs = zalloc(sizeof(struct probe_trace_event)); | 2040 | tev = *tevs = zalloc(sizeof(struct probe_trace_event)); |
1926 | if (tev == NULL) | 2041 | if (tev == NULL) |
@@ -2056,7 +2171,7 @@ end: | |||
2056 | for (i = 0; i < npevs; i++) { | 2171 | for (i = 0; i < npevs; i++) { |
2057 | for (j = 0; j < pkgs[i].ntevs; j++) | 2172 | for (j = 0; j < pkgs[i].ntevs; j++) |
2058 | clear_probe_trace_event(&pkgs[i].tevs[j]); | 2173 | clear_probe_trace_event(&pkgs[i].tevs[j]); |
2059 | free(pkgs[i].tevs); | 2174 | zfree(&pkgs[i].tevs); |
2060 | } | 2175 | } |
2061 | free(pkgs); | 2176 | free(pkgs); |
2062 | 2177 | ||
@@ -2281,7 +2396,7 @@ static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec) | |||
2281 | struct perf_probe_point *pp = &pev->point; | 2396 | struct perf_probe_point *pp = &pev->point; |
2282 | struct symbol *sym; | 2397 | struct symbol *sym; |
2283 | struct map *map = NULL; | 2398 | struct map *map = NULL; |
2284 | char *function = NULL, *name = NULL; | 2399 | char *function = NULL; |
2285 | int ret = -EINVAL; | 2400 | int ret = -EINVAL; |
2286 | unsigned long long vaddr = 0; | 2401 | unsigned long long vaddr = 0; |
2287 | 2402 | ||
@@ -2297,12 +2412,7 @@ static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec) | |||
2297 | goto out; | 2412 | goto out; |
2298 | } | 2413 | } |
2299 | 2414 | ||
2300 | name = realpath(exec, NULL); | 2415 | map = dso__new_map(exec); |
2301 | if (!name) { | ||
2302 | pr_warning("Cannot find realpath for %s.\n", exec); | ||
2303 | goto out; | ||
2304 | } | ||
2305 | map = dso__new_map(name); | ||
2306 | if (!map) { | 2416 | if (!map) { |
2307 | pr_warning("Cannot find appropriate DSO for %s.\n", exec); | 2417 | pr_warning("Cannot find appropriate DSO for %s.\n", exec); |
2308 | goto out; | 2418 | goto out; |
@@ -2367,7 +2477,5 @@ out: | |||
2367 | } | 2477 | } |
2368 | if (function) | 2478 | if (function) |
2369 | free(function); | 2479 | free(function); |
2370 | if (name) | ||
2371 | free(name); | ||
2372 | return ret; | 2480 | return ret; |
2373 | } | 2481 | } |
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index f9f3de8b4220..fcaf7273e85a 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
@@ -12,6 +12,7 @@ struct probe_trace_point { | |||
12 | char *symbol; /* Base symbol */ | 12 | char *symbol; /* Base symbol */ |
13 | char *module; /* Module name */ | 13 | char *module; /* Module name */ |
14 | unsigned long offset; /* Offset from symbol */ | 14 | unsigned long offset; /* Offset from symbol */ |
15 | unsigned long address; /* Actual address of the trace point */ | ||
15 | bool retprobe; /* Return probe flag */ | 16 | bool retprobe; /* Return probe flag */ |
16 | }; | 17 | }; |
17 | 18 | ||
@@ -119,6 +120,12 @@ extern void clear_perf_probe_event(struct perf_probe_event *pev); | |||
119 | /* Command string to line-range */ | 120 | /* Command string to line-range */ |
120 | extern int parse_line_range_desc(const char *cmd, struct line_range *lr); | 121 | extern int parse_line_range_desc(const char *cmd, struct line_range *lr); |
121 | 122 | ||
123 | /* Release line range members */ | ||
124 | extern void line_range__clear(struct line_range *lr); | ||
125 | |||
126 | /* Initialize line range */ | ||
127 | extern void line_range__init(struct line_range *lr); | ||
128 | |||
122 | /* Internal use: Return kernel/module path */ | 129 | /* Internal use: Return kernel/module path */ |
123 | extern const char *kernel_get_module_path(const char *module); | 130 | extern const char *kernel_get_module_path(const char *module); |
124 | 131 | ||
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index ffb657ffd327..061edb162b5b 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -226,10 +226,8 @@ struct debuginfo *debuginfo__new(const char *path) | |||
226 | if (!dbg) | 226 | if (!dbg) |
227 | return NULL; | 227 | return NULL; |
228 | 228 | ||
229 | if (debuginfo__init_offline_dwarf(dbg, path) < 0) { | 229 | if (debuginfo__init_offline_dwarf(dbg, path) < 0) |
230 | free(dbg); | 230 | zfree(&dbg); |
231 | dbg = NULL; | ||
232 | } | ||
233 | 231 | ||
234 | return dbg; | 232 | return dbg; |
235 | } | 233 | } |
@@ -241,10 +239,8 @@ struct debuginfo *debuginfo__new_online_kernel(unsigned long addr) | |||
241 | if (!dbg) | 239 | if (!dbg) |
242 | return NULL; | 240 | return NULL; |
243 | 241 | ||
244 | if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0) { | 242 | if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0) |
245 | free(dbg); | 243 | zfree(&dbg); |
246 | dbg = NULL; | ||
247 | } | ||
248 | 244 | ||
249 | return dbg; | 245 | return dbg; |
250 | } | 246 | } |
@@ -729,6 +725,7 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, | |||
729 | return -ENOENT; | 725 | return -ENOENT; |
730 | } | 726 | } |
731 | tp->offset = (unsigned long)(paddr - sym.st_value); | 727 | tp->offset = (unsigned long)(paddr - sym.st_value); |
728 | tp->address = (unsigned long)paddr; | ||
732 | tp->symbol = strdup(symbol); | 729 | tp->symbol = strdup(symbol); |
733 | if (!tp->symbol) | 730 | if (!tp->symbol) |
734 | return -ENOMEM; | 731 | return -ENOMEM; |
@@ -1301,8 +1298,7 @@ int debuginfo__find_trace_events(struct debuginfo *dbg, | |||
1301 | 1298 | ||
1302 | ret = debuginfo__find_probes(dbg, &tf.pf); | 1299 | ret = debuginfo__find_probes(dbg, &tf.pf); |
1303 | if (ret < 0) { | 1300 | if (ret < 0) { |
1304 | free(*tevs); | 1301 | zfree(tevs); |
1305 | *tevs = NULL; | ||
1306 | return ret; | 1302 | return ret; |
1307 | } | 1303 | } |
1308 | 1304 | ||
@@ -1413,13 +1409,10 @@ int debuginfo__find_available_vars_at(struct debuginfo *dbg, | |||
1413 | if (ret < 0) { | 1409 | if (ret < 0) { |
1414 | /* Free vlist for error */ | 1410 | /* Free vlist for error */ |
1415 | while (af.nvls--) { | 1411 | while (af.nvls--) { |
1416 | if (af.vls[af.nvls].point.symbol) | 1412 | zfree(&af.vls[af.nvls].point.symbol); |
1417 | free(af.vls[af.nvls].point.symbol); | 1413 | strlist__delete(af.vls[af.nvls].vars); |
1418 | if (af.vls[af.nvls].vars) | ||
1419 | strlist__delete(af.vls[af.nvls].vars); | ||
1420 | } | 1414 | } |
1421 | free(af.vls); | 1415 | zfree(vls); |
1422 | *vls = NULL; | ||
1423 | return ret; | 1416 | return ret; |
1424 | } | 1417 | } |
1425 | 1418 | ||
@@ -1523,10 +1516,7 @@ post: | |||
1523 | if (fname) { | 1516 | if (fname) { |
1524 | ppt->file = strdup(fname); | 1517 | ppt->file = strdup(fname); |
1525 | if (ppt->file == NULL) { | 1518 | if (ppt->file == NULL) { |
1526 | if (ppt->function) { | 1519 | zfree(&ppt->function); |
1527 | free(ppt->function); | ||
1528 | ppt->function = NULL; | ||
1529 | } | ||
1530 | ret = -ENOMEM; | 1520 | ret = -ENOMEM; |
1531 | goto end; | 1521 | goto end; |
1532 | } | 1522 | } |
@@ -1580,8 +1570,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | |||
1580 | else | 1570 | else |
1581 | ret = 0; /* Lines are not found */ | 1571 | ret = 0; /* Lines are not found */ |
1582 | else { | 1572 | else { |
1583 | free(lf->lr->path); | 1573 | zfree(&lf->lr->path); |
1584 | lf->lr->path = NULL; | ||
1585 | } | 1574 | } |
1586 | return ret; | 1575 | return ret; |
1587 | } | 1576 | } |
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index 239036fb2b2c..595bfc73d2ed 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources | |||
@@ -18,4 +18,5 @@ util/cgroup.c | |||
18 | util/rblist.c | 18 | util/rblist.c |
19 | util/strlist.c | 19 | util/strlist.c |
20 | util/fs.c | 20 | util/fs.c |
21 | util/trace-event.c | ||
21 | ../../lib/rbtree.c | 22 | ../../lib/rbtree.c |
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 4bf8ace7f511..122669c18ff4 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
@@ -908,9 +908,10 @@ static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i) | |||
908 | if (i >= pevlist->evlist.nr_entries) | 908 | if (i >= pevlist->evlist.nr_entries) |
909 | return NULL; | 909 | return NULL; |
910 | 910 | ||
911 | list_for_each_entry(pos, &pevlist->evlist.entries, node) | 911 | evlist__for_each(&pevlist->evlist, pos) { |
912 | if (i-- == 0) | 912 | if (i-- == 0) |
913 | break; | 913 | break; |
914 | } | ||
914 | 915 | ||
915 | return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel)); | 916 | return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel)); |
916 | } | 917 | } |
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index c8845b107f60..373762501dad 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c | |||
@@ -74,8 +74,7 @@ bool perf_can_sample_identifier(void) | |||
74 | return perf_probe_api(perf_probe_sample_identifier); | 74 | return perf_probe_api(perf_probe_sample_identifier); |
75 | } | 75 | } |
76 | 76 | ||
77 | void perf_evlist__config(struct perf_evlist *evlist, | 77 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) |
78 | struct perf_record_opts *opts) | ||
79 | { | 78 | { |
80 | struct perf_evsel *evsel; | 79 | struct perf_evsel *evsel; |
81 | bool use_sample_identifier = false; | 80 | bool use_sample_identifier = false; |
@@ -90,19 +89,19 @@ void perf_evlist__config(struct perf_evlist *evlist, | |||
90 | if (evlist->cpus->map[0] < 0) | 89 | if (evlist->cpus->map[0] < 0) |
91 | opts->no_inherit = true; | 90 | opts->no_inherit = true; |
92 | 91 | ||
93 | list_for_each_entry(evsel, &evlist->entries, node) | 92 | evlist__for_each(evlist, evsel) |
94 | perf_evsel__config(evsel, opts); | 93 | perf_evsel__config(evsel, opts); |
95 | 94 | ||
96 | if (evlist->nr_entries > 1) { | 95 | if (evlist->nr_entries > 1) { |
97 | struct perf_evsel *first = perf_evlist__first(evlist); | 96 | struct perf_evsel *first = perf_evlist__first(evlist); |
98 | 97 | ||
99 | list_for_each_entry(evsel, &evlist->entries, node) { | 98 | evlist__for_each(evlist, evsel) { |
100 | if (evsel->attr.sample_type == first->attr.sample_type) | 99 | if (evsel->attr.sample_type == first->attr.sample_type) |
101 | continue; | 100 | continue; |
102 | use_sample_identifier = perf_can_sample_identifier(); | 101 | use_sample_identifier = perf_can_sample_identifier(); |
103 | break; | 102 | break; |
104 | } | 103 | } |
105 | list_for_each_entry(evsel, &evlist->entries, node) | 104 | evlist__for_each(evlist, evsel) |
106 | perf_evsel__set_sample_id(evsel, use_sample_identifier); | 105 | perf_evsel__set_sample_id(evsel, use_sample_identifier); |
107 | } | 106 | } |
108 | 107 | ||
@@ -123,7 +122,7 @@ static int get_max_rate(unsigned int *rate) | |||
123 | return filename__read_int(path, (int *) rate); | 122 | return filename__read_int(path, (int *) rate); |
124 | } | 123 | } |
125 | 124 | ||
126 | static int perf_record_opts__config_freq(struct perf_record_opts *opts) | 125 | static int record_opts__config_freq(struct record_opts *opts) |
127 | { | 126 | { |
128 | bool user_freq = opts->user_freq != UINT_MAX; | 127 | bool user_freq = opts->user_freq != UINT_MAX; |
129 | unsigned int max_rate; | 128 | unsigned int max_rate; |
@@ -173,7 +172,44 @@ static int perf_record_opts__config_freq(struct perf_record_opts *opts) | |||
173 | return 0; | 172 | return 0; |
174 | } | 173 | } |
175 | 174 | ||
176 | int perf_record_opts__config(struct perf_record_opts *opts) | 175 | int record_opts__config(struct record_opts *opts) |
177 | { | 176 | { |
178 | return perf_record_opts__config_freq(opts); | 177 | return record_opts__config_freq(opts); |
178 | } | ||
179 | |||
180 | bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str) | ||
181 | { | ||
182 | struct perf_evlist *temp_evlist; | ||
183 | struct perf_evsel *evsel; | ||
184 | int err, fd, cpu; | ||
185 | bool ret = false; | ||
186 | |||
187 | temp_evlist = perf_evlist__new(); | ||
188 | if (!temp_evlist) | ||
189 | return false; | ||
190 | |||
191 | err = parse_events(temp_evlist, str); | ||
192 | if (err) | ||
193 | goto out_delete; | ||
194 | |||
195 | evsel = perf_evlist__last(temp_evlist); | ||
196 | |||
197 | if (!evlist || cpu_map__empty(evlist->cpus)) { | ||
198 | struct cpu_map *cpus = cpu_map__new(NULL); | ||
199 | |||
200 | cpu = cpus ? cpus->map[0] : 0; | ||
201 | cpu_map__delete(cpus); | ||
202 | } else { | ||
203 | cpu = evlist->cpus->map[0]; | ||
204 | } | ||
205 | |||
206 | fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); | ||
207 | if (fd >= 0) { | ||
208 | close(fd); | ||
209 | ret = true; | ||
210 | } | ||
211 | |||
212 | out_delete: | ||
213 | perf_evlist__delete(temp_evlist); | ||
214 | return ret; | ||
179 | } | 215 | } |
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index d5e5969f6fea..e108207c5de0 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c | |||
@@ -194,8 +194,7 @@ static void define_event_symbols(struct event_format *event, | |||
194 | zero_flag_atom = 0; | 194 | zero_flag_atom = 0; |
195 | break; | 195 | break; |
196 | case PRINT_FIELD: | 196 | case PRINT_FIELD: |
197 | if (cur_field_name) | 197 | free(cur_field_name); |
198 | free(cur_field_name); | ||
199 | cur_field_name = strdup(args->field.name); | 198 | cur_field_name = strdup(args->field.name); |
200 | break; | 199 | break; |
201 | case PRINT_FLAGS: | 200 | case PRINT_FLAGS: |
@@ -257,12 +256,9 @@ static inline struct event_format *find_cache_event(struct perf_evsel *evsel) | |||
257 | return event; | 256 | return event; |
258 | } | 257 | } |
259 | 258 | ||
260 | static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused, | 259 | static void perl_process_tracepoint(struct perf_sample *sample, |
261 | struct perf_sample *sample, | ||
262 | struct perf_evsel *evsel, | 260 | struct perf_evsel *evsel, |
263 | struct machine *machine __maybe_unused, | 261 | struct thread *thread) |
264 | struct thread *thread, | ||
265 | struct addr_location *al) | ||
266 | { | 262 | { |
267 | struct format_field *field; | 263 | struct format_field *field; |
268 | static char handler[256]; | 264 | static char handler[256]; |
@@ -349,10 +345,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused, | |||
349 | 345 | ||
350 | static void perl_process_event_generic(union perf_event *event, | 346 | static void perl_process_event_generic(union perf_event *event, |
351 | struct perf_sample *sample, | 347 | struct perf_sample *sample, |
352 | struct perf_evsel *evsel, | 348 | struct perf_evsel *evsel) |
353 | struct machine *machine __maybe_unused, | ||
354 | struct thread *thread __maybe_unused, | ||
355 | struct addr_location *al __maybe_unused) | ||
356 | { | 349 | { |
357 | dSP; | 350 | dSP; |
358 | 351 | ||
@@ -377,12 +370,11 @@ static void perl_process_event_generic(union perf_event *event, | |||
377 | static void perl_process_event(union perf_event *event, | 370 | static void perl_process_event(union perf_event *event, |
378 | struct perf_sample *sample, | 371 | struct perf_sample *sample, |
379 | struct perf_evsel *evsel, | 372 | struct perf_evsel *evsel, |
380 | struct machine *machine, | ||
381 | struct thread *thread, | 373 | struct thread *thread, |
382 | struct addr_location *al) | 374 | struct addr_location *al __maybe_unused) |
383 | { | 375 | { |
384 | perl_process_tracepoint(event, sample, evsel, machine, thread, al); | 376 | perl_process_tracepoint(sample, evsel, thread); |
385 | perl_process_event_generic(event, sample, evsel, machine, thread, al); | 377 | perl_process_event_generic(event, sample, evsel); |
386 | } | 378 | } |
387 | 379 | ||
388 | static void run_start_sub(void) | 380 | static void run_start_sub(void) |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 53c20e7fd900..cd9774df3750 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -161,8 +161,7 @@ static void define_event_symbols(struct event_format *event, | |||
161 | zero_flag_atom = 0; | 161 | zero_flag_atom = 0; |
162 | break; | 162 | break; |
163 | case PRINT_FIELD: | 163 | case PRINT_FIELD: |
164 | if (cur_field_name) | 164 | free(cur_field_name); |
165 | free(cur_field_name); | ||
166 | cur_field_name = strdup(args->field.name); | 165 | cur_field_name = strdup(args->field.name); |
167 | break; | 166 | break; |
168 | case PRINT_FLAGS: | 167 | case PRINT_FLAGS: |
@@ -231,13 +230,10 @@ static inline struct event_format *find_cache_event(struct perf_evsel *evsel) | |||
231 | return event; | 230 | return event; |
232 | } | 231 | } |
233 | 232 | ||
234 | static void python_process_tracepoint(union perf_event *perf_event | 233 | static void python_process_tracepoint(struct perf_sample *sample, |
235 | __maybe_unused, | 234 | struct perf_evsel *evsel, |
236 | struct perf_sample *sample, | 235 | struct thread *thread, |
237 | struct perf_evsel *evsel, | 236 | struct addr_location *al) |
238 | struct machine *machine __maybe_unused, | ||
239 | struct thread *thread, | ||
240 | struct addr_location *al) | ||
241 | { | 237 | { |
242 | PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; | 238 | PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; |
243 | static char handler_name[256]; | 239 | static char handler_name[256]; |
@@ -351,11 +347,8 @@ static void python_process_tracepoint(union perf_event *perf_event | |||
351 | Py_DECREF(t); | 347 | Py_DECREF(t); |
352 | } | 348 | } |
353 | 349 | ||
354 | static void python_process_general_event(union perf_event *perf_event | 350 | static void python_process_general_event(struct perf_sample *sample, |
355 | __maybe_unused, | ||
356 | struct perf_sample *sample, | ||
357 | struct perf_evsel *evsel, | 351 | struct perf_evsel *evsel, |
358 | struct machine *machine __maybe_unused, | ||
359 | struct thread *thread, | 352 | struct thread *thread, |
360 | struct addr_location *al) | 353 | struct addr_location *al) |
361 | { | 354 | { |
@@ -411,22 +404,19 @@ exit: | |||
411 | Py_DECREF(t); | 404 | Py_DECREF(t); |
412 | } | 405 | } |
413 | 406 | ||
414 | static void python_process_event(union perf_event *perf_event, | 407 | static void python_process_event(union perf_event *event __maybe_unused, |
415 | struct perf_sample *sample, | 408 | struct perf_sample *sample, |
416 | struct perf_evsel *evsel, | 409 | struct perf_evsel *evsel, |
417 | struct machine *machine, | ||
418 | struct thread *thread, | 410 | struct thread *thread, |
419 | struct addr_location *al) | 411 | struct addr_location *al) |
420 | { | 412 | { |
421 | switch (evsel->attr.type) { | 413 | switch (evsel->attr.type) { |
422 | case PERF_TYPE_TRACEPOINT: | 414 | case PERF_TYPE_TRACEPOINT: |
423 | python_process_tracepoint(perf_event, sample, evsel, | 415 | python_process_tracepoint(sample, evsel, thread, al); |
424 | machine, thread, al); | ||
425 | break; | 416 | break; |
426 | /* Reserve for future process_hw/sw/raw APIs */ | 417 | /* Reserve for future process_hw/sw/raw APIs */ |
427 | default: | 418 | default: |
428 | python_process_general_event(perf_event, sample, evsel, | 419 | python_process_general_event(sample, evsel, thread, al); |
429 | machine, thread, al); | ||
430 | } | 420 | } |
431 | } | 421 | } |
432 | 422 | ||
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index f36d24a02445..5da6ce74c676 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -132,18 +132,18 @@ static void perf_session__delete_threads(struct perf_session *session) | |||
132 | 132 | ||
133 | static void perf_session_env__delete(struct perf_session_env *env) | 133 | static void perf_session_env__delete(struct perf_session_env *env) |
134 | { | 134 | { |
135 | free(env->hostname); | 135 | zfree(&env->hostname); |
136 | free(env->os_release); | 136 | zfree(&env->os_release); |
137 | free(env->version); | 137 | zfree(&env->version); |
138 | free(env->arch); | 138 | zfree(&env->arch); |
139 | free(env->cpu_desc); | 139 | zfree(&env->cpu_desc); |
140 | free(env->cpuid); | 140 | zfree(&env->cpuid); |
141 | 141 | ||
142 | free(env->cmdline); | 142 | zfree(&env->cmdline); |
143 | free(env->sibling_cores); | 143 | zfree(&env->sibling_cores); |
144 | free(env->sibling_threads); | 144 | zfree(&env->sibling_threads); |
145 | free(env->numa_nodes); | 145 | zfree(&env->numa_nodes); |
146 | free(env->pmu_mappings); | 146 | zfree(&env->pmu_mappings); |
147 | } | 147 | } |
148 | 148 | ||
149 | void perf_session__delete(struct perf_session *session) | 149 | void perf_session__delete(struct perf_session *session) |
@@ -247,27 +247,6 @@ void perf_tool__fill_defaults(struct perf_tool *tool) | |||
247 | } | 247 | } |
248 | } | 248 | } |
249 | 249 | ||
250 | void mem_bswap_32(void *src, int byte_size) | ||
251 | { | ||
252 | u32 *m = src; | ||
253 | while (byte_size > 0) { | ||
254 | *m = bswap_32(*m); | ||
255 | byte_size -= sizeof(u32); | ||
256 | ++m; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | void mem_bswap_64(void *src, int byte_size) | ||
261 | { | ||
262 | u64 *m = src; | ||
263 | |||
264 | while (byte_size > 0) { | ||
265 | *m = bswap_64(*m); | ||
266 | byte_size -= sizeof(u64); | ||
267 | ++m; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | static void swap_sample_id_all(union perf_event *event, void *data) | 250 | static void swap_sample_id_all(union perf_event *event, void *data) |
272 | { | 251 | { |
273 | void *end = (void *) event + event->header.size; | 252 | void *end = (void *) event + event->header.size; |
@@ -851,6 +830,7 @@ static struct machine * | |||
851 | struct perf_sample *sample) | 830 | struct perf_sample *sample) |
852 | { | 831 | { |
853 | const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 832 | const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
833 | struct machine *machine; | ||
854 | 834 | ||
855 | if (perf_guest && | 835 | if (perf_guest && |
856 | ((cpumode == PERF_RECORD_MISC_GUEST_KERNEL) || | 836 | ((cpumode == PERF_RECORD_MISC_GUEST_KERNEL) || |
@@ -863,7 +843,11 @@ static struct machine * | |||
863 | else | 843 | else |
864 | pid = sample->pid; | 844 | pid = sample->pid; |
865 | 845 | ||
866 | return perf_session__findnew_machine(session, pid); | 846 | machine = perf_session__find_machine(session, pid); |
847 | if (!machine) | ||
848 | machine = perf_session__findnew_machine(session, | ||
849 | DEFAULT_GUEST_KERNEL_ID); | ||
850 | return machine; | ||
867 | } | 851 | } |
868 | 852 | ||
869 | return &session->machines.host; | 853 | return &session->machines.host; |
@@ -1024,6 +1008,12 @@ static int perf_session__process_user_event(struct perf_session *session, union | |||
1024 | if (err == 0) | 1008 | if (err == 0) |
1025 | perf_session__set_id_hdr_size(session); | 1009 | perf_session__set_id_hdr_size(session); |
1026 | return err; | 1010 | return err; |
1011 | case PERF_RECORD_HEADER_EVENT_TYPE: | ||
1012 | /* | ||
1013 | * Depreceated, but we need to handle it for sake | ||
1014 | * of old data files create in pipe mode. | ||
1015 | */ | ||
1016 | return 0; | ||
1027 | case PERF_RECORD_HEADER_TRACING_DATA: | 1017 | case PERF_RECORD_HEADER_TRACING_DATA: |
1028 | /* setup for reading amidst mmap */ | 1018 | /* setup for reading amidst mmap */ |
1029 | lseek(fd, file_offset, SEEK_SET); | 1019 | lseek(fd, file_offset, SEEK_SET); |
@@ -1158,7 +1148,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session, | |||
1158 | void *buf = NULL; | 1148 | void *buf = NULL; |
1159 | int skip = 0; | 1149 | int skip = 0; |
1160 | u64 head; | 1150 | u64 head; |
1161 | int err; | 1151 | ssize_t err; |
1162 | void *p; | 1152 | void *p; |
1163 | 1153 | ||
1164 | perf_tool__fill_defaults(tool); | 1154 | perf_tool__fill_defaults(tool); |
@@ -1400,7 +1390,7 @@ bool perf_session__has_traces(struct perf_session *session, const char *msg) | |||
1400 | { | 1390 | { |
1401 | struct perf_evsel *evsel; | 1391 | struct perf_evsel *evsel; |
1402 | 1392 | ||
1403 | list_for_each_entry(evsel, &session->evlist->entries, node) { | 1393 | evlist__for_each(session->evlist, evsel) { |
1404 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT) | 1394 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT) |
1405 | return true; | 1395 | return true; |
1406 | } | 1396 | } |
@@ -1458,7 +1448,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) | |||
1458 | 1448 | ||
1459 | ret += events_stats__fprintf(&session->stats, fp); | 1449 | ret += events_stats__fprintf(&session->stats, fp); |
1460 | 1450 | ||
1461 | list_for_each_entry(pos, &session->evlist->entries, node) { | 1451 | evlist__for_each(session->evlist, pos) { |
1462 | ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); | 1452 | ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); |
1463 | ret += events_stats__fprintf(&pos->hists.stats, fp); | 1453 | ret += events_stats__fprintf(&pos->hists.stats, fp); |
1464 | } | 1454 | } |
@@ -1480,35 +1470,30 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | |||
1480 | { | 1470 | { |
1481 | struct perf_evsel *pos; | 1471 | struct perf_evsel *pos; |
1482 | 1472 | ||
1483 | list_for_each_entry(pos, &session->evlist->entries, node) { | 1473 | evlist__for_each(session->evlist, pos) { |
1484 | if (pos->attr.type == type) | 1474 | if (pos->attr.type == type) |
1485 | return pos; | 1475 | return pos; |
1486 | } | 1476 | } |
1487 | return NULL; | 1477 | return NULL; |
1488 | } | 1478 | } |
1489 | 1479 | ||
1490 | void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | 1480 | void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, |
1491 | struct perf_sample *sample, struct machine *machine, | 1481 | struct addr_location *al, |
1492 | unsigned int print_opts, unsigned int stack_depth) | 1482 | unsigned int print_opts, unsigned int stack_depth) |
1493 | { | 1483 | { |
1494 | struct addr_location al; | ||
1495 | struct callchain_cursor_node *node; | 1484 | struct callchain_cursor_node *node; |
1496 | int print_ip = print_opts & PRINT_IP_OPT_IP; | 1485 | int print_ip = print_opts & PRINT_IP_OPT_IP; |
1497 | int print_sym = print_opts & PRINT_IP_OPT_SYM; | 1486 | int print_sym = print_opts & PRINT_IP_OPT_SYM; |
1498 | int print_dso = print_opts & PRINT_IP_OPT_DSO; | 1487 | int print_dso = print_opts & PRINT_IP_OPT_DSO; |
1499 | int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; | 1488 | int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; |
1500 | int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; | 1489 | int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; |
1490 | int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE; | ||
1501 | char s = print_oneline ? ' ' : '\t'; | 1491 | char s = print_oneline ? ' ' : '\t'; |
1502 | 1492 | ||
1503 | if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { | ||
1504 | error("problem processing %d event, skipping it.\n", | ||
1505 | event->header.type); | ||
1506 | return; | ||
1507 | } | ||
1508 | |||
1509 | if (symbol_conf.use_callchain && sample->callchain) { | 1493 | if (symbol_conf.use_callchain && sample->callchain) { |
1494 | struct addr_location node_al; | ||
1510 | 1495 | ||
1511 | if (machine__resolve_callchain(machine, evsel, al.thread, | 1496 | if (machine__resolve_callchain(al->machine, evsel, al->thread, |
1512 | sample, NULL, NULL, | 1497 | sample, NULL, NULL, |
1513 | PERF_MAX_STACK_DEPTH) != 0) { | 1498 | PERF_MAX_STACK_DEPTH) != 0) { |
1514 | if (verbose) | 1499 | if (verbose) |
@@ -1517,20 +1502,31 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | |||
1517 | } | 1502 | } |
1518 | callchain_cursor_commit(&callchain_cursor); | 1503 | callchain_cursor_commit(&callchain_cursor); |
1519 | 1504 | ||
1505 | if (print_symoffset) | ||
1506 | node_al = *al; | ||
1507 | |||
1520 | while (stack_depth) { | 1508 | while (stack_depth) { |
1509 | u64 addr = 0; | ||
1510 | |||
1521 | node = callchain_cursor_current(&callchain_cursor); | 1511 | node = callchain_cursor_current(&callchain_cursor); |
1522 | if (!node) | 1512 | if (!node) |
1523 | break; | 1513 | break; |
1524 | 1514 | ||
1515 | if (node->sym && node->sym->ignore) | ||
1516 | goto next; | ||
1517 | |||
1525 | if (print_ip) | 1518 | if (print_ip) |
1526 | printf("%c%16" PRIx64, s, node->ip); | 1519 | printf("%c%16" PRIx64, s, node->ip); |
1527 | 1520 | ||
1521 | if (node->map) | ||
1522 | addr = node->map->map_ip(node->map, node->ip); | ||
1523 | |||
1528 | if (print_sym) { | 1524 | if (print_sym) { |
1529 | printf(" "); | 1525 | printf(" "); |
1530 | if (print_symoffset) { | 1526 | if (print_symoffset) { |
1531 | al.addr = node->ip; | 1527 | node_al.addr = addr; |
1532 | al.map = node->map; | 1528 | node_al.map = node->map; |
1533 | symbol__fprintf_symname_offs(node->sym, &al, stdout); | 1529 | symbol__fprintf_symname_offs(node->sym, &node_al, stdout); |
1534 | } else | 1530 | } else |
1535 | symbol__fprintf_symname(node->sym, stdout); | 1531 | symbol__fprintf_symname(node->sym, stdout); |
1536 | } | 1532 | } |
@@ -1541,39 +1537,49 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | |||
1541 | printf(")"); | 1537 | printf(")"); |
1542 | } | 1538 | } |
1543 | 1539 | ||
1540 | if (print_srcline) | ||
1541 | map__fprintf_srcline(node->map, addr, "\n ", | ||
1542 | stdout); | ||
1543 | |||
1544 | if (!print_oneline) | 1544 | if (!print_oneline) |
1545 | printf("\n"); | 1545 | printf("\n"); |
1546 | 1546 | ||
1547 | callchain_cursor_advance(&callchain_cursor); | ||
1548 | |||
1549 | stack_depth--; | 1547 | stack_depth--; |
1548 | next: | ||
1549 | callchain_cursor_advance(&callchain_cursor); | ||
1550 | } | 1550 | } |
1551 | 1551 | ||
1552 | } else { | 1552 | } else { |
1553 | if (al->sym && al->sym->ignore) | ||
1554 | return; | ||
1555 | |||
1553 | if (print_ip) | 1556 | if (print_ip) |
1554 | printf("%16" PRIx64, sample->ip); | 1557 | printf("%16" PRIx64, sample->ip); |
1555 | 1558 | ||
1556 | if (print_sym) { | 1559 | if (print_sym) { |
1557 | printf(" "); | 1560 | printf(" "); |
1558 | if (print_symoffset) | 1561 | if (print_symoffset) |
1559 | symbol__fprintf_symname_offs(al.sym, &al, | 1562 | symbol__fprintf_symname_offs(al->sym, al, |
1560 | stdout); | 1563 | stdout); |
1561 | else | 1564 | else |
1562 | symbol__fprintf_symname(al.sym, stdout); | 1565 | symbol__fprintf_symname(al->sym, stdout); |
1563 | } | 1566 | } |
1564 | 1567 | ||
1565 | if (print_dso) { | 1568 | if (print_dso) { |
1566 | printf(" ("); | 1569 | printf(" ("); |
1567 | map__fprintf_dsoname(al.map, stdout); | 1570 | map__fprintf_dsoname(al->map, stdout); |
1568 | printf(")"); | 1571 | printf(")"); |
1569 | } | 1572 | } |
1573 | |||
1574 | if (print_srcline) | ||
1575 | map__fprintf_srcline(al->map, al->addr, "\n ", stdout); | ||
1570 | } | 1576 | } |
1571 | } | 1577 | } |
1572 | 1578 | ||
1573 | int perf_session__cpu_bitmap(struct perf_session *session, | 1579 | int perf_session__cpu_bitmap(struct perf_session *session, |
1574 | const char *cpu_list, unsigned long *cpu_bitmap) | 1580 | const char *cpu_list, unsigned long *cpu_bitmap) |
1575 | { | 1581 | { |
1576 | int i; | 1582 | int i, err = -1; |
1577 | struct cpu_map *map; | 1583 | struct cpu_map *map; |
1578 | 1584 | ||
1579 | for (i = 0; i < PERF_TYPE_MAX; ++i) { | 1585 | for (i = 0; i < PERF_TYPE_MAX; ++i) { |
@@ -1602,13 +1608,17 @@ int perf_session__cpu_bitmap(struct perf_session *session, | |||
1602 | if (cpu >= MAX_NR_CPUS) { | 1608 | if (cpu >= MAX_NR_CPUS) { |
1603 | pr_err("Requested CPU %d too large. " | 1609 | pr_err("Requested CPU %d too large. " |
1604 | "Consider raising MAX_NR_CPUS\n", cpu); | 1610 | "Consider raising MAX_NR_CPUS\n", cpu); |
1605 | return -1; | 1611 | goto out_delete_map; |
1606 | } | 1612 | } |
1607 | 1613 | ||
1608 | set_bit(cpu, cpu_bitmap); | 1614 | set_bit(cpu, cpu_bitmap); |
1609 | } | 1615 | } |
1610 | 1616 | ||
1611 | return 0; | 1617 | err = 0; |
1618 | |||
1619 | out_delete_map: | ||
1620 | cpu_map__delete(map); | ||
1621 | return err; | ||
1612 | } | 1622 | } |
1613 | 1623 | ||
1614 | void perf_session__fprintf_info(struct perf_session *session, FILE *fp, | 1624 | void perf_session__fprintf_info(struct perf_session *session, FILE *fp, |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 50f640958f0f..3140f8ae6148 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -1,6 +1,7 @@ | |||
1 | #ifndef __PERF_SESSION_H | 1 | #ifndef __PERF_SESSION_H |
2 | #define __PERF_SESSION_H | 2 | #define __PERF_SESSION_H |
3 | 3 | ||
4 | #include "trace-event.h" | ||
4 | #include "hist.h" | 5 | #include "hist.h" |
5 | #include "event.h" | 6 | #include "event.h" |
6 | #include "header.h" | 7 | #include "header.h" |
@@ -32,7 +33,7 @@ struct perf_session { | |||
32 | struct perf_header header; | 33 | struct perf_header header; |
33 | struct machines machines; | 34 | struct machines machines; |
34 | struct perf_evlist *evlist; | 35 | struct perf_evlist *evlist; |
35 | struct pevent *pevent; | 36 | struct trace_event tevent; |
36 | struct events_stats stats; | 37 | struct events_stats stats; |
37 | bool repipe; | 38 | bool repipe; |
38 | struct ordered_samples ordered_samples; | 39 | struct ordered_samples ordered_samples; |
@@ -44,6 +45,7 @@ struct perf_session { | |||
44 | #define PRINT_IP_OPT_DSO (1<<2) | 45 | #define PRINT_IP_OPT_DSO (1<<2) |
45 | #define PRINT_IP_OPT_SYMOFFSET (1<<3) | 46 | #define PRINT_IP_OPT_SYMOFFSET (1<<3) |
46 | #define PRINT_IP_OPT_ONELINE (1<<4) | 47 | #define PRINT_IP_OPT_ONELINE (1<<4) |
48 | #define PRINT_IP_OPT_SRCLINE (1<<5) | ||
47 | 49 | ||
48 | struct perf_tool; | 50 | struct perf_tool; |
49 | 51 | ||
@@ -72,8 +74,6 @@ int perf_session__resolve_callchain(struct perf_session *session, | |||
72 | 74 | ||
73 | bool perf_session__has_traces(struct perf_session *session, const char *msg); | 75 | bool perf_session__has_traces(struct perf_session *session, const char *msg); |
74 | 76 | ||
75 | void mem_bswap_64(void *src, int byte_size); | ||
76 | void mem_bswap_32(void *src, int byte_size); | ||
77 | void perf_event__attr_swap(struct perf_event_attr *attr); | 77 | void perf_event__attr_swap(struct perf_event_attr *attr); |
78 | 78 | ||
79 | int perf_session__create_kernel_maps(struct perf_session *session); | 79 | int perf_session__create_kernel_maps(struct perf_session *session); |
@@ -105,8 +105,8 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); | |||
105 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | 105 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, |
106 | unsigned int type); | 106 | unsigned int type); |
107 | 107 | ||
108 | void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | 108 | void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, |
109 | struct perf_sample *sample, struct machine *machine, | 109 | struct addr_location *al, |
110 | unsigned int print_opts, unsigned int stack_depth); | 110 | unsigned int print_opts, unsigned int stack_depth); |
111 | 111 | ||
112 | int perf_session__cpu_bitmap(struct perf_session *session, | 112 | int perf_session__cpu_bitmap(struct perf_session *session, |
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index 58ea5ca6c255..d0aee4b9dfd4 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py | |||
@@ -25,7 +25,7 @@ cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter' | |||
25 | build_lib = getenv('PYTHON_EXTBUILD_LIB') | 25 | build_lib = getenv('PYTHON_EXTBUILD_LIB') |
26 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') | 26 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') |
27 | libtraceevent = getenv('LIBTRACEEVENT') | 27 | libtraceevent = getenv('LIBTRACEEVENT') |
28 | liblk = getenv('LIBLK') | 28 | libapikfs = getenv('LIBAPIKFS') |
29 | 29 | ||
30 | ext_sources = [f.strip() for f in file('util/python-ext-sources') | 30 | ext_sources = [f.strip() for f in file('util/python-ext-sources') |
31 | if len(f.strip()) > 0 and f[0] != '#'] | 31 | if len(f.strip()) > 0 and f[0] != '#'] |
@@ -34,7 +34,7 @@ perf = Extension('perf', | |||
34 | sources = ext_sources, | 34 | sources = ext_sources, |
35 | include_dirs = ['util/include'], | 35 | include_dirs = ['util/include'], |
36 | extra_compile_args = cflags, | 36 | extra_compile_args = cflags, |
37 | extra_objects = [libtraceevent, liblk], | 37 | extra_objects = [libtraceevent, libapikfs], |
38 | ) | 38 | ) |
39 | 39 | ||
40 | setup(name='perf', | 40 | setup(name='perf', |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 8b0bb1f4494a..635cd8f8b22e 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -13,6 +13,7 @@ int have_ignore_callees = 0; | |||
13 | int sort__need_collapse = 0; | 13 | int sort__need_collapse = 0; |
14 | int sort__has_parent = 0; | 14 | int sort__has_parent = 0; |
15 | int sort__has_sym = 0; | 15 | int sort__has_sym = 0; |
16 | int sort__has_dso = 0; | ||
16 | enum sort_mode sort__mode = SORT_MODE__NORMAL; | 17 | enum sort_mode sort__mode = SORT_MODE__NORMAL; |
17 | 18 | ||
18 | enum sort_type sort__first_dimension; | 19 | enum sort_type sort__first_dimension; |
@@ -161,6 +162,11 @@ struct sort_entry sort_dso = { | |||
161 | 162 | ||
162 | /* --sort symbol */ | 163 | /* --sort symbol */ |
163 | 164 | ||
165 | static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip) | ||
166 | { | ||
167 | return (int64_t)(right_ip - left_ip); | ||
168 | } | ||
169 | |||
164 | static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r) | 170 | static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r) |
165 | { | 171 | { |
166 | u64 ip_l, ip_r; | 172 | u64 ip_l, ip_r; |
@@ -183,15 +189,17 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) | |||
183 | int64_t ret; | 189 | int64_t ret; |
184 | 190 | ||
185 | if (!left->ms.sym && !right->ms.sym) | 191 | if (!left->ms.sym && !right->ms.sym) |
186 | return right->level - left->level; | 192 | return _sort__addr_cmp(left->ip, right->ip); |
187 | 193 | ||
188 | /* | 194 | /* |
189 | * comparing symbol address alone is not enough since it's a | 195 | * comparing symbol address alone is not enough since it's a |
190 | * relative address within a dso. | 196 | * relative address within a dso. |
191 | */ | 197 | */ |
192 | ret = sort__dso_cmp(left, right); | 198 | if (!sort__has_dso) { |
193 | if (ret != 0) | 199 | ret = sort__dso_cmp(left, right); |
194 | return ret; | 200 | if (ret != 0) |
201 | return ret; | ||
202 | } | ||
195 | 203 | ||
196 | return _sort__sym_cmp(left->ms.sym, right->ms.sym); | 204 | return _sort__sym_cmp(left->ms.sym, right->ms.sym); |
197 | } | 205 | } |
@@ -372,7 +380,7 @@ sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right) | |||
372 | struct addr_map_symbol *from_r = &right->branch_info->from; | 380 | struct addr_map_symbol *from_r = &right->branch_info->from; |
373 | 381 | ||
374 | if (!from_l->sym && !from_r->sym) | 382 | if (!from_l->sym && !from_r->sym) |
375 | return right->level - left->level; | 383 | return _sort__addr_cmp(from_l->addr, from_r->addr); |
376 | 384 | ||
377 | return _sort__sym_cmp(from_l->sym, from_r->sym); | 385 | return _sort__sym_cmp(from_l->sym, from_r->sym); |
378 | } | 386 | } |
@@ -384,7 +392,7 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right) | |||
384 | struct addr_map_symbol *to_r = &right->branch_info->to; | 392 | struct addr_map_symbol *to_r = &right->branch_info->to; |
385 | 393 | ||
386 | if (!to_l->sym && !to_r->sym) | 394 | if (!to_l->sym && !to_r->sym) |
387 | return right->level - left->level; | 395 | return _sort__addr_cmp(to_l->addr, to_r->addr); |
388 | 396 | ||
389 | return _sort__sym_cmp(to_l->sym, to_r->sym); | 397 | return _sort__sym_cmp(to_l->sym, to_r->sym); |
390 | } | 398 | } |
@@ -1056,6 +1064,8 @@ int sort_dimension__add(const char *tok) | |||
1056 | sort__has_parent = 1; | 1064 | sort__has_parent = 1; |
1057 | } else if (sd->entry == &sort_sym) { | 1065 | } else if (sd->entry == &sort_sym) { |
1058 | sort__has_sym = 1; | 1066 | sort__has_sym = 1; |
1067 | } else if (sd->entry == &sort_dso) { | ||
1068 | sort__has_dso = 1; | ||
1059 | } | 1069 | } |
1060 | 1070 | ||
1061 | __sort_dimension__add(sd, i); | 1071 | __sort_dimension__add(sd, i); |
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index d11aefbc4b8d..f3e4bc5fe5d2 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c | |||
@@ -129,7 +129,7 @@ static struct a2l_data *addr2line_init(const char *path) | |||
129 | 129 | ||
130 | out: | 130 | out: |
131 | if (a2l) { | 131 | if (a2l) { |
132 | free((void *)a2l->input); | 132 | zfree((char **)&a2l->input); |
133 | free(a2l); | 133 | free(a2l); |
134 | } | 134 | } |
135 | bfd_close(abfd); | 135 | bfd_close(abfd); |
@@ -140,24 +140,30 @@ static void addr2line_cleanup(struct a2l_data *a2l) | |||
140 | { | 140 | { |
141 | if (a2l->abfd) | 141 | if (a2l->abfd) |
142 | bfd_close(a2l->abfd); | 142 | bfd_close(a2l->abfd); |
143 | free((void *)a2l->input); | 143 | zfree((char **)&a2l->input); |
144 | free(a2l->syms); | 144 | zfree(&a2l->syms); |
145 | free(a2l); | 145 | free(a2l); |
146 | } | 146 | } |
147 | 147 | ||
148 | static int addr2line(const char *dso_name, unsigned long addr, | 148 | static int addr2line(const char *dso_name, unsigned long addr, |
149 | char **file, unsigned int *line) | 149 | char **file, unsigned int *line, struct dso *dso) |
150 | { | 150 | { |
151 | int ret = 0; | 151 | int ret = 0; |
152 | struct a2l_data *a2l; | 152 | struct a2l_data *a2l = dso->a2l; |
153 | |||
154 | if (!a2l) { | ||
155 | dso->a2l = addr2line_init(dso_name); | ||
156 | a2l = dso->a2l; | ||
157 | } | ||
153 | 158 | ||
154 | a2l = addr2line_init(dso_name); | ||
155 | if (a2l == NULL) { | 159 | if (a2l == NULL) { |
156 | pr_warning("addr2line_init failed for %s\n", dso_name); | 160 | pr_warning("addr2line_init failed for %s\n", dso_name); |
157 | return 0; | 161 | return 0; |
158 | } | 162 | } |
159 | 163 | ||
160 | a2l->addr = addr; | 164 | a2l->addr = addr; |
165 | a2l->found = false; | ||
166 | |||
161 | bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); | 167 | bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); |
162 | 168 | ||
163 | if (a2l->found && a2l->filename) { | 169 | if (a2l->found && a2l->filename) { |
@@ -168,14 +174,26 @@ static int addr2line(const char *dso_name, unsigned long addr, | |||
168 | ret = 1; | 174 | ret = 1; |
169 | } | 175 | } |
170 | 176 | ||
171 | addr2line_cleanup(a2l); | ||
172 | return ret; | 177 | return ret; |
173 | } | 178 | } |
174 | 179 | ||
180 | void dso__free_a2l(struct dso *dso) | ||
181 | { | ||
182 | struct a2l_data *a2l = dso->a2l; | ||
183 | |||
184 | if (!a2l) | ||
185 | return; | ||
186 | |||
187 | addr2line_cleanup(a2l); | ||
188 | |||
189 | dso->a2l = NULL; | ||
190 | } | ||
191 | |||
175 | #else /* HAVE_LIBBFD_SUPPORT */ | 192 | #else /* HAVE_LIBBFD_SUPPORT */ |
176 | 193 | ||
177 | static int addr2line(const char *dso_name, unsigned long addr, | 194 | static int addr2line(const char *dso_name, unsigned long addr, |
178 | char **file, unsigned int *line_nr) | 195 | char **file, unsigned int *line_nr, |
196 | struct dso *dso __maybe_unused) | ||
179 | { | 197 | { |
180 | FILE *fp; | 198 | FILE *fp; |
181 | char cmd[PATH_MAX]; | 199 | char cmd[PATH_MAX]; |
@@ -219,42 +237,58 @@ out: | |||
219 | pclose(fp); | 237 | pclose(fp); |
220 | return ret; | 238 | return ret; |
221 | } | 239 | } |
240 | |||
241 | void dso__free_a2l(struct dso *dso __maybe_unused) | ||
242 | { | ||
243 | } | ||
244 | |||
222 | #endif /* HAVE_LIBBFD_SUPPORT */ | 245 | #endif /* HAVE_LIBBFD_SUPPORT */ |
223 | 246 | ||
247 | /* | ||
248 | * Number of addr2line failures (without success) before disabling it for that | ||
249 | * dso. | ||
250 | */ | ||
251 | #define A2L_FAIL_LIMIT 123 | ||
252 | |||
224 | char *get_srcline(struct dso *dso, unsigned long addr) | 253 | char *get_srcline(struct dso *dso, unsigned long addr) |
225 | { | 254 | { |
226 | char *file = NULL; | 255 | char *file = NULL; |
227 | unsigned line = 0; | 256 | unsigned line = 0; |
228 | char *srcline; | 257 | char *srcline; |
229 | char *dso_name = dso->long_name; | 258 | const char *dso_name; |
230 | size_t size; | ||
231 | 259 | ||
232 | if (!dso->has_srcline) | 260 | if (!dso->has_srcline) |
233 | return SRCLINE_UNKNOWN; | 261 | return SRCLINE_UNKNOWN; |
234 | 262 | ||
263 | if (dso->symsrc_filename) | ||
264 | dso_name = dso->symsrc_filename; | ||
265 | else | ||
266 | dso_name = dso->long_name; | ||
267 | |||
235 | if (dso_name[0] == '[') | 268 | if (dso_name[0] == '[') |
236 | goto out; | 269 | goto out; |
237 | 270 | ||
238 | if (!strncmp(dso_name, "/tmp/perf-", 10)) | 271 | if (!strncmp(dso_name, "/tmp/perf-", 10)) |
239 | goto out; | 272 | goto out; |
240 | 273 | ||
241 | if (!addr2line(dso_name, addr, &file, &line)) | 274 | if (!addr2line(dso_name, addr, &file, &line, dso)) |
242 | goto out; | 275 | goto out; |
243 | 276 | ||
244 | /* just calculate actual length */ | 277 | if (asprintf(&srcline, "%s:%u", file, line) < 0) { |
245 | size = snprintf(NULL, 0, "%s:%u", file, line) + 1; | 278 | free(file); |
279 | goto out; | ||
280 | } | ||
246 | 281 | ||
247 | srcline = malloc(size); | 282 | dso->a2l_fails = 0; |
248 | if (srcline) | ||
249 | snprintf(srcline, size, "%s:%u", file, line); | ||
250 | else | ||
251 | srcline = SRCLINE_UNKNOWN; | ||
252 | 283 | ||
253 | free(file); | 284 | free(file); |
254 | return srcline; | 285 | return srcline; |
255 | 286 | ||
256 | out: | 287 | out: |
257 | dso->has_srcline = 0; | 288 | if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) { |
289 | dso->has_srcline = 0; | ||
290 | dso__free_a2l(dso); | ||
291 | } | ||
258 | return SRCLINE_UNKNOWN; | 292 | return SRCLINE_UNKNOWN; |
259 | } | 293 | } |
260 | 294 | ||
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c index cfa906882e2c..4abe23550c73 100644 --- a/tools/perf/util/strbuf.c +++ b/tools/perf/util/strbuf.c | |||
@@ -28,7 +28,7 @@ void strbuf_init(struct strbuf *sb, ssize_t hint) | |||
28 | void strbuf_release(struct strbuf *sb) | 28 | void strbuf_release(struct strbuf *sb) |
29 | { | 29 | { |
30 | if (sb->alloc) { | 30 | if (sb->alloc) { |
31 | free(sb->buf); | 31 | zfree(&sb->buf); |
32 | strbuf_init(sb, 0); | 32 | strbuf_init(sb, 0); |
33 | } | 33 | } |
34 | } | 34 | } |
diff --git a/tools/perf/util/strfilter.c b/tools/perf/util/strfilter.c index 3edd0538161f..79a757a2a15c 100644 --- a/tools/perf/util/strfilter.c +++ b/tools/perf/util/strfilter.c | |||
@@ -14,7 +14,7 @@ static void strfilter_node__delete(struct strfilter_node *node) | |||
14 | { | 14 | { |
15 | if (node) { | 15 | if (node) { |
16 | if (node->p && !is_operator(*node->p)) | 16 | if (node->p && !is_operator(*node->p)) |
17 | free((char *)node->p); | 17 | zfree((char **)&node->p); |
18 | strfilter_node__delete(node->l); | 18 | strfilter_node__delete(node->l); |
19 | strfilter_node__delete(node->r); | 19 | strfilter_node__delete(node->r); |
20 | free(node); | 20 | free(node); |
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c index f0b0c008c507..2553e5b55b89 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c | |||
@@ -128,7 +128,7 @@ void argv_free(char **argv) | |||
128 | { | 128 | { |
129 | char **p; | 129 | char **p; |
130 | for (p = argv; *p; p++) | 130 | for (p = argv; *p; p++) |
131 | free(*p); | 131 | zfree(p); |
132 | 132 | ||
133 | free(argv); | 133 | free(argv); |
134 | } | 134 | } |
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c index eabdce0a2daa..71f9d102b96f 100644 --- a/tools/perf/util/strlist.c +++ b/tools/perf/util/strlist.c | |||
@@ -5,6 +5,7 @@ | |||
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include "strlist.h" | 7 | #include "strlist.h" |
8 | #include "util.h" | ||
8 | #include <errno.h> | 9 | #include <errno.h> |
9 | #include <stdio.h> | 10 | #include <stdio.h> |
10 | #include <stdlib.h> | 11 | #include <stdlib.h> |
@@ -38,7 +39,7 @@ out_delete: | |||
38 | static void str_node__delete(struct str_node *snode, bool dupstr) | 39 | static void str_node__delete(struct str_node *snode, bool dupstr) |
39 | { | 40 | { |
40 | if (dupstr) | 41 | if (dupstr) |
41 | free((void *)snode->s); | 42 | zfree((char **)&snode->s); |
42 | free(snode); | 43 | free(snode); |
43 | } | 44 | } |
44 | 45 | ||
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index 96c866045d60..43262b83c541 100644 --- a/tools/perf/util/svghelper.c +++ b/tools/perf/util/svghelper.c | |||
@@ -17,8 +17,12 @@ | |||
17 | #include <stdlib.h> | 17 | #include <stdlib.h> |
18 | #include <unistd.h> | 18 | #include <unistd.h> |
19 | #include <string.h> | 19 | #include <string.h> |
20 | #include <linux/bitops.h> | ||
20 | 21 | ||
22 | #include "perf.h" | ||
21 | #include "svghelper.h" | 23 | #include "svghelper.h" |
24 | #include "util.h" | ||
25 | #include "cpumap.h" | ||
22 | 26 | ||
23 | static u64 first_time, last_time; | 27 | static u64 first_time, last_time; |
24 | static u64 turbo_frequency, max_freq; | 28 | static u64 turbo_frequency, max_freq; |
@@ -28,6 +32,8 @@ static u64 turbo_frequency, max_freq; | |||
28 | #define SLOT_HEIGHT 25.0 | 32 | #define SLOT_HEIGHT 25.0 |
29 | 33 | ||
30 | int svg_page_width = 1000; | 34 | int svg_page_width = 1000; |
35 | u64 svg_highlight; | ||
36 | const char *svg_highlight_name; | ||
31 | 37 | ||
32 | #define MIN_TEXT_SIZE 0.01 | 38 | #define MIN_TEXT_SIZE 0.01 |
33 | 39 | ||
@@ -39,9 +45,14 @@ static double cpu2slot(int cpu) | |||
39 | return 2 * cpu + 1; | 45 | return 2 * cpu + 1; |
40 | } | 46 | } |
41 | 47 | ||
48 | static int *topology_map; | ||
49 | |||
42 | static double cpu2y(int cpu) | 50 | static double cpu2y(int cpu) |
43 | { | 51 | { |
44 | return cpu2slot(cpu) * SLOT_MULT; | 52 | if (topology_map) |
53 | return cpu2slot(topology_map[cpu]) * SLOT_MULT; | ||
54 | else | ||
55 | return cpu2slot(cpu) * SLOT_MULT; | ||
45 | } | 56 | } |
46 | 57 | ||
47 | static double time2pixels(u64 __time) | 58 | static double time2pixels(u64 __time) |
@@ -95,6 +106,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end) | |||
95 | 106 | ||
96 | total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT; | 107 | total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT; |
97 | fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n"); | 108 | fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n"); |
109 | fprintf(svgfile, "<!DOCTYPE svg SYSTEM \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"); | ||
98 | fprintf(svgfile, "<svg width=\"%i\" height=\"%" PRIu64 "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height); | 110 | fprintf(svgfile, "<svg width=\"%i\" height=\"%" PRIu64 "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height); |
99 | 111 | ||
100 | fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n"); | 112 | fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n"); |
@@ -103,6 +115,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end) | |||
103 | fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n"); | 115 | fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n"); |
104 | fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); | 116 | fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); |
105 | fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); | 117 | fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); |
118 | fprintf(svgfile, " rect.sample_hi{ fill:rgb(255,128, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); | ||
106 | fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); | 119 | fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); |
107 | fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); | 120 | fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); |
108 | fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); | 121 | fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); |
@@ -128,14 +141,42 @@ void svg_box(int Yslot, u64 start, u64 end, const char *type) | |||
128 | time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); | 141 | time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); |
129 | } | 142 | } |
130 | 143 | ||
131 | void svg_sample(int Yslot, int cpu, u64 start, u64 end) | 144 | static char *time_to_string(u64 duration); |
145 | void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace) | ||
146 | { | ||
147 | if (!svgfile) | ||
148 | return; | ||
149 | |||
150 | fprintf(svgfile, "<g>\n"); | ||
151 | fprintf(svgfile, "<title>#%d blocked %s</title>\n", cpu, | ||
152 | time_to_string(end - start)); | ||
153 | if (backtrace) | ||
154 | fprintf(svgfile, "<desc>Blocked on:\n%s</desc>\n", backtrace); | ||
155 | svg_box(Yslot, start, end, "blocked"); | ||
156 | fprintf(svgfile, "</g>\n"); | ||
157 | } | ||
158 | |||
159 | void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace) | ||
132 | { | 160 | { |
133 | double text_size; | 161 | double text_size; |
162 | const char *type; | ||
163 | |||
134 | if (!svgfile) | 164 | if (!svgfile) |
135 | return; | 165 | return; |
136 | 166 | ||
137 | fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"sample\"/>\n", | 167 | if (svg_highlight && end - start > svg_highlight) |
138 | time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT); | 168 | type = "sample_hi"; |
169 | else | ||
170 | type = "sample"; | ||
171 | fprintf(svgfile, "<g>\n"); | ||
172 | |||
173 | fprintf(svgfile, "<title>#%d running %s</title>\n", | ||
174 | cpu, time_to_string(end - start)); | ||
175 | if (backtrace) | ||
176 | fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace); | ||
177 | fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", | ||
178 | time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, | ||
179 | type); | ||
139 | 180 | ||
140 | text_size = (time2pixels(end)-time2pixels(start)); | 181 | text_size = (time2pixels(end)-time2pixels(start)); |
141 | if (cpu > 9) | 182 | if (cpu > 9) |
@@ -148,6 +189,7 @@ void svg_sample(int Yslot, int cpu, u64 start, u64 end) | |||
148 | fprintf(svgfile, "<text x=\"%1.8f\" y=\"%1.8f\" font-size=\"%1.8fpt\">%i</text>\n", | 189 | fprintf(svgfile, "<text x=\"%1.8f\" y=\"%1.8f\" font-size=\"%1.8fpt\">%i</text>\n", |
149 | time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1); | 190 | time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1); |
150 | 191 | ||
192 | fprintf(svgfile, "</g>\n"); | ||
151 | } | 193 | } |
152 | 194 | ||
153 | static char *time_to_string(u64 duration) | 195 | static char *time_to_string(u64 duration) |
@@ -168,7 +210,7 @@ static char *time_to_string(u64 duration) | |||
168 | return text; | 210 | return text; |
169 | } | 211 | } |
170 | 212 | ||
171 | void svg_waiting(int Yslot, u64 start, u64 end) | 213 | void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace) |
172 | { | 214 | { |
173 | char *text; | 215 | char *text; |
174 | const char *style; | 216 | const char *style; |
@@ -192,6 +234,9 @@ void svg_waiting(int Yslot, u64 start, u64 end) | |||
192 | font_size = round_text_size(font_size); | 234 | font_size = round_text_size(font_size); |
193 | 235 | ||
194 | fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT); | 236 | fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT); |
237 | fprintf(svgfile, "<title>#%d waiting %s</title>\n", cpu, time_to_string(end - start)); | ||
238 | if (backtrace) | ||
239 | fprintf(svgfile, "<desc>Waiting on:\n%s</desc>\n", backtrace); | ||
195 | fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", | 240 | fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", |
196 | time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style); | 241 | time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style); |
197 | if (font_size > MIN_TEXT_SIZE) | 242 | if (font_size > MIN_TEXT_SIZE) |
@@ -242,28 +287,42 @@ void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq) | |||
242 | max_freq = __max_freq; | 287 | max_freq = __max_freq; |
243 | turbo_frequency = __turbo_freq; | 288 | turbo_frequency = __turbo_freq; |
244 | 289 | ||
290 | fprintf(svgfile, "<g>\n"); | ||
291 | |||
245 | fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n", | 292 | fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n", |
246 | time2pixels(first_time), | 293 | time2pixels(first_time), |
247 | time2pixels(last_time)-time2pixels(first_time), | 294 | time2pixels(last_time)-time2pixels(first_time), |
248 | cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); | 295 | cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); |
249 | 296 | ||
250 | sprintf(cpu_string, "CPU %i", (int)cpu+1); | 297 | sprintf(cpu_string, "CPU %i", (int)cpu); |
251 | fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", | 298 | fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", |
252 | 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string); | 299 | 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string); |
253 | 300 | ||
254 | fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n", | 301 | fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n", |
255 | 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model()); | 302 | 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model()); |
303 | |||
304 | fprintf(svgfile, "</g>\n"); | ||
256 | } | 305 | } |
257 | 306 | ||
258 | void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name) | 307 | void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const char *backtrace) |
259 | { | 308 | { |
260 | double width; | 309 | double width; |
310 | const char *type; | ||
261 | 311 | ||
262 | if (!svgfile) | 312 | if (!svgfile) |
263 | return; | 313 | return; |
264 | 314 | ||
315 | if (svg_highlight && end - start >= svg_highlight) | ||
316 | type = "sample_hi"; | ||
317 | else if (svg_highlight_name && strstr(name, svg_highlight_name)) | ||
318 | type = "sample_hi"; | ||
319 | else | ||
320 | type = "sample"; | ||
265 | 321 | ||
266 | fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu)); | 322 | fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu)); |
323 | fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start)); | ||
324 | if (backtrace) | ||
325 | fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace); | ||
267 | fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", | 326 | fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", |
268 | time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type); | 327 | time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type); |
269 | width = time2pixels(end)-time2pixels(start); | 328 | width = time2pixels(end)-time2pixels(start); |
@@ -288,6 +347,8 @@ void svg_cstate(int cpu, u64 start, u64 end, int type) | |||
288 | return; | 347 | return; |
289 | 348 | ||
290 | 349 | ||
350 | fprintf(svgfile, "<g>\n"); | ||
351 | |||
291 | if (type > 6) | 352 | if (type > 6) |
292 | type = 6; | 353 | type = 6; |
293 | sprintf(style, "c%i", type); | 354 | sprintf(style, "c%i", type); |
@@ -306,6 +367,8 @@ void svg_cstate(int cpu, u64 start, u64 end, int type) | |||
306 | if (width > MIN_TEXT_SIZE) | 367 | if (width > MIN_TEXT_SIZE) |
307 | fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"%3.8fpt\">C%i</text>\n", | 368 | fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"%3.8fpt\">C%i</text>\n", |
308 | time2pixels(start), cpu2y(cpu)+width, width, type); | 369 | time2pixels(start), cpu2y(cpu)+width, width, type); |
370 | |||
371 | fprintf(svgfile, "</g>\n"); | ||
309 | } | 372 | } |
310 | 373 | ||
311 | static char *HzToHuman(unsigned long hz) | 374 | static char *HzToHuman(unsigned long hz) |
@@ -339,6 +402,8 @@ void svg_pstate(int cpu, u64 start, u64 end, u64 freq) | |||
339 | if (!svgfile) | 402 | if (!svgfile) |
340 | return; | 403 | return; |
341 | 404 | ||
405 | fprintf(svgfile, "<g>\n"); | ||
406 | |||
342 | if (max_freq) | 407 | if (max_freq) |
343 | height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT); | 408 | height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT); |
344 | height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height; | 409 | height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height; |
@@ -347,10 +412,11 @@ void svg_pstate(int cpu, u64 start, u64 end, u64 freq) | |||
347 | fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"0.25pt\">%s</text>\n", | 412 | fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"0.25pt\">%s</text>\n", |
348 | time2pixels(start), height+0.9, HzToHuman(freq)); | 413 | time2pixels(start), height+0.9, HzToHuman(freq)); |
349 | 414 | ||
415 | fprintf(svgfile, "</g>\n"); | ||
350 | } | 416 | } |
351 | 417 | ||
352 | 418 | ||
353 | void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2) | 419 | void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace) |
354 | { | 420 | { |
355 | double height; | 421 | double height; |
356 | 422 | ||
@@ -358,6 +424,15 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc | |||
358 | return; | 424 | return; |
359 | 425 | ||
360 | 426 | ||
427 | fprintf(svgfile, "<g>\n"); | ||
428 | |||
429 | fprintf(svgfile, "<title>%s wakes up %s</title>\n", | ||
430 | desc1 ? desc1 : "?", | ||
431 | desc2 ? desc2 : "?"); | ||
432 | |||
433 | if (backtrace) | ||
434 | fprintf(svgfile, "<desc>%s</desc>\n", backtrace); | ||
435 | |||
361 | if (row1 < row2) { | 436 | if (row1 < row2) { |
362 | if (row1) { | 437 | if (row1) { |
363 | fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", | 438 | fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", |
@@ -395,9 +470,11 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc | |||
395 | if (row1) | 470 | if (row1) |
396 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", | 471 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", |
397 | time2pixels(start), height); | 472 | time2pixels(start), height); |
473 | |||
474 | fprintf(svgfile, "</g>\n"); | ||
398 | } | 475 | } |
399 | 476 | ||
400 | void svg_wakeline(u64 start, int row1, int row2) | 477 | void svg_wakeline(u64 start, int row1, int row2, const char *backtrace) |
401 | { | 478 | { |
402 | double height; | 479 | double height; |
403 | 480 | ||
@@ -405,6 +482,11 @@ void svg_wakeline(u64 start, int row1, int row2) | |||
405 | return; | 482 | return; |
406 | 483 | ||
407 | 484 | ||
485 | fprintf(svgfile, "<g>\n"); | ||
486 | |||
487 | if (backtrace) | ||
488 | fprintf(svgfile, "<desc>%s</desc>\n", backtrace); | ||
489 | |||
408 | if (row1 < row2) | 490 | if (row1 < row2) |
409 | fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", | 491 | fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", |
410 | time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT); | 492 | time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT); |
@@ -417,17 +499,28 @@ void svg_wakeline(u64 start, int row1, int row2) | |||
417 | height += SLOT_HEIGHT; | 499 | height += SLOT_HEIGHT; |
418 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", | 500 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", |
419 | time2pixels(start), height); | 501 | time2pixels(start), height); |
502 | |||
503 | fprintf(svgfile, "</g>\n"); | ||
420 | } | 504 | } |
421 | 505 | ||
422 | void svg_interrupt(u64 start, int row) | 506 | void svg_interrupt(u64 start, int row, const char *backtrace) |
423 | { | 507 | { |
424 | if (!svgfile) | 508 | if (!svgfile) |
425 | return; | 509 | return; |
426 | 510 | ||
511 | fprintf(svgfile, "<g>\n"); | ||
512 | |||
513 | fprintf(svgfile, "<title>Wakeup from interrupt</title>\n"); | ||
514 | |||
515 | if (backtrace) | ||
516 | fprintf(svgfile, "<desc>%s</desc>\n", backtrace); | ||
517 | |||
427 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", | 518 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", |
428 | time2pixels(start), row * SLOT_MULT); | 519 | time2pixels(start), row * SLOT_MULT); |
429 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", | 520 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", |
430 | time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT); | 521 | time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT); |
522 | |||
523 | fprintf(svgfile, "</g>\n"); | ||
431 | } | 524 | } |
432 | 525 | ||
433 | void svg_text(int Yslot, u64 start, const char *text) | 526 | void svg_text(int Yslot, u64 start, const char *text) |
@@ -455,6 +548,7 @@ void svg_legenda(void) | |||
455 | if (!svgfile) | 548 | if (!svgfile) |
456 | return; | 549 | return; |
457 | 550 | ||
551 | fprintf(svgfile, "<g>\n"); | ||
458 | svg_legenda_box(0, "Running", "sample"); | 552 | svg_legenda_box(0, "Running", "sample"); |
459 | svg_legenda_box(100, "Idle","c1"); | 553 | svg_legenda_box(100, "Idle","c1"); |
460 | svg_legenda_box(200, "Deeper Idle", "c3"); | 554 | svg_legenda_box(200, "Deeper Idle", "c3"); |
@@ -462,6 +556,7 @@ void svg_legenda(void) | |||
462 | svg_legenda_box(550, "Sleeping", "process2"); | 556 | svg_legenda_box(550, "Sleeping", "process2"); |
463 | svg_legenda_box(650, "Waiting for cpu", "waiting"); | 557 | svg_legenda_box(650, "Waiting for cpu", "waiting"); |
464 | svg_legenda_box(800, "Blocked on IO", "blocked"); | 558 | svg_legenda_box(800, "Blocked on IO", "blocked"); |
559 | fprintf(svgfile, "</g>\n"); | ||
465 | } | 560 | } |
466 | 561 | ||
467 | void svg_time_grid(void) | 562 | void svg_time_grid(void) |
@@ -499,3 +594,123 @@ void svg_close(void) | |||
499 | svgfile = NULL; | 594 | svgfile = NULL; |
500 | } | 595 | } |
501 | } | 596 | } |
597 | |||
598 | #define cpumask_bits(maskp) ((maskp)->bits) | ||
599 | typedef struct { DECLARE_BITMAP(bits, MAX_NR_CPUS); } cpumask_t; | ||
600 | |||
601 | struct topology { | ||
602 | cpumask_t *sib_core; | ||
603 | int sib_core_nr; | ||
604 | cpumask_t *sib_thr; | ||
605 | int sib_thr_nr; | ||
606 | }; | ||
607 | |||
608 | static void scan_thread_topology(int *map, struct topology *t, int cpu, int *pos) | ||
609 | { | ||
610 | int i; | ||
611 | int thr; | ||
612 | |||
613 | for (i = 0; i < t->sib_thr_nr; i++) { | ||
614 | if (!test_bit(cpu, cpumask_bits(&t->sib_thr[i]))) | ||
615 | continue; | ||
616 | |||
617 | for_each_set_bit(thr, | ||
618 | cpumask_bits(&t->sib_thr[i]), | ||
619 | MAX_NR_CPUS) | ||
620 | if (map[thr] == -1) | ||
621 | map[thr] = (*pos)++; | ||
622 | } | ||
623 | } | ||
624 | |||
625 | static void scan_core_topology(int *map, struct topology *t) | ||
626 | { | ||
627 | int pos = 0; | ||
628 | int i; | ||
629 | int cpu; | ||
630 | |||
631 | for (i = 0; i < t->sib_core_nr; i++) | ||
632 | for_each_set_bit(cpu, | ||
633 | cpumask_bits(&t->sib_core[i]), | ||
634 | MAX_NR_CPUS) | ||
635 | scan_thread_topology(map, t, cpu, &pos); | ||
636 | } | ||
637 | |||
638 | static int str_to_bitmap(char *s, cpumask_t *b) | ||
639 | { | ||
640 | int i; | ||
641 | int ret = 0; | ||
642 | struct cpu_map *m; | ||
643 | int c; | ||
644 | |||
645 | m = cpu_map__new(s); | ||
646 | if (!m) | ||
647 | return -1; | ||
648 | |||
649 | for (i = 0; i < m->nr; i++) { | ||
650 | c = m->map[i]; | ||
651 | if (c >= MAX_NR_CPUS) { | ||
652 | ret = -1; | ||
653 | break; | ||
654 | } | ||
655 | |||
656 | set_bit(c, cpumask_bits(b)); | ||
657 | } | ||
658 | |||
659 | cpu_map__delete(m); | ||
660 | |||
661 | return ret; | ||
662 | } | ||
663 | |||
664 | int svg_build_topology_map(char *sib_core, int sib_core_nr, | ||
665 | char *sib_thr, int sib_thr_nr) | ||
666 | { | ||
667 | int i; | ||
668 | struct topology t; | ||
669 | |||
670 | t.sib_core_nr = sib_core_nr; | ||
671 | t.sib_thr_nr = sib_thr_nr; | ||
672 | t.sib_core = calloc(sib_core_nr, sizeof(cpumask_t)); | ||
673 | t.sib_thr = calloc(sib_thr_nr, sizeof(cpumask_t)); | ||
674 | |||
675 | if (!t.sib_core || !t.sib_thr) { | ||
676 | fprintf(stderr, "topology: no memory\n"); | ||
677 | goto exit; | ||
678 | } | ||
679 | |||
680 | for (i = 0; i < sib_core_nr; i++) { | ||
681 | if (str_to_bitmap(sib_core, &t.sib_core[i])) { | ||
682 | fprintf(stderr, "topology: can't parse siblings map\n"); | ||
683 | goto exit; | ||
684 | } | ||
685 | |||
686 | sib_core += strlen(sib_core) + 1; | ||
687 | } | ||
688 | |||
689 | for (i = 0; i < sib_thr_nr; i++) { | ||
690 | if (str_to_bitmap(sib_thr, &t.sib_thr[i])) { | ||
691 | fprintf(stderr, "topology: can't parse siblings map\n"); | ||
692 | goto exit; | ||
693 | } | ||
694 | |||
695 | sib_thr += strlen(sib_thr) + 1; | ||
696 | } | ||
697 | |||
698 | topology_map = malloc(sizeof(int) * MAX_NR_CPUS); | ||
699 | if (!topology_map) { | ||
700 | fprintf(stderr, "topology: no memory\n"); | ||
701 | goto exit; | ||
702 | } | ||
703 | |||
704 | for (i = 0; i < MAX_NR_CPUS; i++) | ||
705 | topology_map[i] = -1; | ||
706 | |||
707 | scan_core_topology(topology_map, &t); | ||
708 | |||
709 | return 0; | ||
710 | |||
711 | exit: | ||
712 | zfree(&t.sib_core); | ||
713 | zfree(&t.sib_thr); | ||
714 | |||
715 | return -1; | ||
716 | } | ||
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h index e0781989cc31..f7b4d6e699ea 100644 --- a/tools/perf/util/svghelper.h +++ b/tools/perf/util/svghelper.h | |||
@@ -5,24 +5,29 @@ | |||
5 | 5 | ||
6 | extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end); | 6 | extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end); |
7 | extern void svg_box(int Yslot, u64 start, u64 end, const char *type); | 7 | extern void svg_box(int Yslot, u64 start, u64 end, const char *type); |
8 | extern void svg_sample(int Yslot, int cpu, u64 start, u64 end); | 8 | extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); |
9 | extern void svg_waiting(int Yslot, u64 start, u64 end); | 9 | extern void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); |
10 | extern void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); | ||
10 | extern void svg_cpu_box(int cpu, u64 max_frequency, u64 turbo_frequency); | 11 | extern void svg_cpu_box(int cpu, u64 max_frequency, u64 turbo_frequency); |
11 | 12 | ||
12 | 13 | ||
13 | extern void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name); | 14 | extern void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const char *backtrace); |
14 | extern void svg_cstate(int cpu, u64 start, u64 end, int type); | 15 | extern void svg_cstate(int cpu, u64 start, u64 end, int type); |
15 | extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); | 16 | extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); |
16 | 17 | ||
17 | 18 | ||
18 | extern void svg_time_grid(void); | 19 | extern void svg_time_grid(void); |
19 | extern void svg_legenda(void); | 20 | extern void svg_legenda(void); |
20 | extern void svg_wakeline(u64 start, int row1, int row2); | 21 | extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace); |
21 | extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2); | 22 | extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace); |
22 | extern void svg_interrupt(u64 start, int row); | 23 | extern void svg_interrupt(u64 start, int row, const char *backtrace); |
23 | extern void svg_text(int Yslot, u64 start, const char *text); | 24 | extern void svg_text(int Yslot, u64 start, const char *text); |
24 | extern void svg_close(void); | 25 | extern void svg_close(void); |
26 | extern int svg_build_topology_map(char *sib_core, int sib_core_nr, | ||
27 | char *sib_thr, int sib_thr_nr); | ||
25 | 28 | ||
26 | extern int svg_page_width; | 29 | extern int svg_page_width; |
30 | extern u64 svg_highlight; | ||
31 | extern const char *svg_highlight_name; | ||
27 | 32 | ||
28 | #endif /* __PERF_SVGHELPER_H */ | 33 | #endif /* __PERF_SVGHELPER_H */ |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index eed0b96302af..516d19fb999b 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <inttypes.h> | 6 | #include <inttypes.h> |
7 | 7 | ||
8 | #include "symbol.h" | 8 | #include "symbol.h" |
9 | #include <symbol/kallsyms.h> | ||
9 | #include "debug.h" | 10 | #include "debug.h" |
10 | 11 | ||
11 | #ifndef HAVE_ELF_GETPHDRNUM_SUPPORT | 12 | #ifndef HAVE_ELF_GETPHDRNUM_SUPPORT |
@@ -135,9 +136,8 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) | |||
135 | return -1; | 136 | return -1; |
136 | } | 137 | } |
137 | 138 | ||
138 | static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | 139 | Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, |
139 | GElf_Shdr *shp, const char *name, | 140 | GElf_Shdr *shp, const char *name, size_t *idx) |
140 | size_t *idx) | ||
141 | { | 141 | { |
142 | Elf_Scn *sec = NULL; | 142 | Elf_Scn *sec = NULL; |
143 | size_t cnt = 1; | 143 | size_t cnt = 1; |
@@ -151,15 +151,15 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | |||
151 | 151 | ||
152 | gelf_getshdr(sec, shp); | 152 | gelf_getshdr(sec, shp); |
153 | str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); | 153 | str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); |
154 | if (!strcmp(name, str)) { | 154 | if (str && !strcmp(name, str)) { |
155 | if (idx) | 155 | if (idx) |
156 | *idx = cnt; | 156 | *idx = cnt; |
157 | break; | 157 | return sec; |
158 | } | 158 | } |
159 | ++cnt; | 159 | ++cnt; |
160 | } | 160 | } |
161 | 161 | ||
162 | return sec; | 162 | return NULL; |
163 | } | 163 | } |
164 | 164 | ||
165 | #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ | 165 | #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ |
@@ -553,7 +553,7 @@ bool symsrc__has_symtab(struct symsrc *ss) | |||
553 | 553 | ||
554 | void symsrc__destroy(struct symsrc *ss) | 554 | void symsrc__destroy(struct symsrc *ss) |
555 | { | 555 | { |
556 | free(ss->name); | 556 | zfree(&ss->name); |
557 | elf_end(ss->elf); | 557 | elf_end(ss->elf); |
558 | close(ss->fd); | 558 | close(ss->fd); |
559 | } | 559 | } |
@@ -751,6 +751,8 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
751 | if (strcmp(elf_name, kmap->ref_reloc_sym->name)) | 751 | if (strcmp(elf_name, kmap->ref_reloc_sym->name)) |
752 | continue; | 752 | continue; |
753 | kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; | 753 | kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; |
754 | map->reloc = kmap->ref_reloc_sym->addr - | ||
755 | kmap->ref_reloc_sym->unrelocated_addr; | ||
754 | break; | 756 | break; |
755 | } | 757 | } |
756 | } | 758 | } |
@@ -922,6 +924,7 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
922 | (u64)shdr.sh_offset); | 924 | (u64)shdr.sh_offset); |
923 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; | 925 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; |
924 | } | 926 | } |
927 | new_symbol: | ||
925 | /* | 928 | /* |
926 | * We need to figure out if the object was created from C++ sources | 929 | * We need to figure out if the object was created from C++ sources |
927 | * DWARF DW_compile_unit has this, but we don't always have access | 930 | * DWARF DW_compile_unit has this, but we don't always have access |
@@ -933,7 +936,6 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
933 | if (demangled != NULL) | 936 | if (demangled != NULL) |
934 | elf_name = demangled; | 937 | elf_name = demangled; |
935 | } | 938 | } |
936 | new_symbol: | ||
937 | f = symbol__new(sym.st_value, sym.st_size, | 939 | f = symbol__new(sym.st_value, sym.st_size, |
938 | GELF_ST_BIND(sym.st_info), elf_name); | 940 | GELF_ST_BIND(sym.st_info), elf_name); |
939 | free(demangled); | 941 | free(demangled); |
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index 2d2dd0532b5a..bd15f490d04f 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include "symbol.h" | 1 | #include "symbol.h" |
2 | #include "util.h" | ||
2 | 3 | ||
3 | #include <stdio.h> | 4 | #include <stdio.h> |
4 | #include <fcntl.h> | 5 | #include <fcntl.h> |
@@ -253,6 +254,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused, | |||
253 | if (!ss->name) | 254 | if (!ss->name) |
254 | goto out_close; | 255 | goto out_close; |
255 | 256 | ||
257 | ss->fd = fd; | ||
256 | ss->type = type; | 258 | ss->type = type; |
257 | 259 | ||
258 | return 0; | 260 | return 0; |
@@ -274,7 +276,7 @@ bool symsrc__has_symtab(struct symsrc *ss __maybe_unused) | |||
274 | 276 | ||
275 | void symsrc__destroy(struct symsrc *ss) | 277 | void symsrc__destroy(struct symsrc *ss) |
276 | { | 278 | { |
277 | free(ss->name); | 279 | zfree(&ss->name); |
278 | close(ss->fd); | 280 | close(ss->fd); |
279 | } | 281 | } |
280 | 282 | ||
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index c0c36965fff0..e89afc097d8a 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -18,12 +18,9 @@ | |||
18 | 18 | ||
19 | #include <elf.h> | 19 | #include <elf.h> |
20 | #include <limits.h> | 20 | #include <limits.h> |
21 | #include <symbol/kallsyms.h> | ||
21 | #include <sys/utsname.h> | 22 | #include <sys/utsname.h> |
22 | 23 | ||
23 | #ifndef KSYM_NAME_LEN | ||
24 | #define KSYM_NAME_LEN 256 | ||
25 | #endif | ||
26 | |||
27 | static int dso__load_kernel_sym(struct dso *dso, struct map *map, | 24 | static int dso__load_kernel_sym(struct dso *dso, struct map *map, |
28 | symbol_filter_t filter); | 25 | symbol_filter_t filter); |
29 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | 26 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, |
@@ -446,62 +443,6 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso, | |||
446 | return ret; | 443 | return ret; |
447 | } | 444 | } |
448 | 445 | ||
449 | int kallsyms__parse(const char *filename, void *arg, | ||
450 | int (*process_symbol)(void *arg, const char *name, | ||
451 | char type, u64 start)) | ||
452 | { | ||
453 | char *line = NULL; | ||
454 | size_t n; | ||
455 | int err = -1; | ||
456 | FILE *file = fopen(filename, "r"); | ||
457 | |||
458 | if (file == NULL) | ||
459 | goto out_failure; | ||
460 | |||
461 | err = 0; | ||
462 | |||
463 | while (!feof(file)) { | ||
464 | u64 start; | ||
465 | int line_len, len; | ||
466 | char symbol_type; | ||
467 | char *symbol_name; | ||
468 | |||
469 | line_len = getline(&line, &n, file); | ||
470 | if (line_len < 0 || !line) | ||
471 | break; | ||
472 | |||
473 | line[--line_len] = '\0'; /* \n */ | ||
474 | |||
475 | len = hex2u64(line, &start); | ||
476 | |||
477 | len++; | ||
478 | if (len + 2 >= line_len) | ||
479 | continue; | ||
480 | |||
481 | symbol_type = line[len]; | ||
482 | len += 2; | ||
483 | symbol_name = line + len; | ||
484 | len = line_len - len; | ||
485 | |||
486 | if (len >= KSYM_NAME_LEN) { | ||
487 | err = -1; | ||
488 | break; | ||
489 | } | ||
490 | |||
491 | err = process_symbol(arg, symbol_name, | ||
492 | symbol_type, start); | ||
493 | if (err) | ||
494 | break; | ||
495 | } | ||
496 | |||
497 | free(line); | ||
498 | fclose(file); | ||
499 | return err; | ||
500 | |||
501 | out_failure: | ||
502 | return -1; | ||
503 | } | ||
504 | |||
505 | int modules__parse(const char *filename, void *arg, | 446 | int modules__parse(const char *filename, void *arg, |
506 | int (*process_module)(void *arg, const char *name, | 447 | int (*process_module)(void *arg, const char *name, |
507 | u64 start)) | 448 | u64 start)) |
@@ -565,12 +506,34 @@ struct process_kallsyms_args { | |||
565 | struct dso *dso; | 506 | struct dso *dso; |
566 | }; | 507 | }; |
567 | 508 | ||
568 | static u8 kallsyms2elf_type(char type) | 509 | bool symbol__is_idle(struct symbol *sym) |
569 | { | 510 | { |
570 | if (type == 'W') | 511 | const char * const idle_symbols[] = { |
571 | return STB_WEAK; | 512 | "cpu_idle", |
513 | "intel_idle", | ||
514 | "default_idle", | ||
515 | "native_safe_halt", | ||
516 | "enter_idle", | ||
517 | "exit_idle", | ||
518 | "mwait_idle", | ||
519 | "mwait_idle_with_hints", | ||
520 | "poll_idle", | ||
521 | "ppc64_runlatch_off", | ||
522 | "pseries_dedicated_idle_sleep", | ||
523 | NULL | ||
524 | }; | ||
525 | |||
526 | int i; | ||
527 | |||
528 | if (!sym) | ||
529 | return false; | ||
572 | 530 | ||
573 | return isupper(type) ? STB_GLOBAL : STB_LOCAL; | 531 | for (i = 0; idle_symbols[i]; i++) { |
532 | if (!strcmp(idle_symbols[i], sym->name)) | ||
533 | return true; | ||
534 | } | ||
535 | |||
536 | return false; | ||
574 | } | 537 | } |
575 | 538 | ||
576 | static int map__process_kallsym_symbol(void *arg, const char *name, | 539 | static int map__process_kallsym_symbol(void *arg, const char *name, |
@@ -664,7 +627,7 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, | |||
664 | * kernel range is broken in several maps, named [kernel].N, as we don't have | 627 | * kernel range is broken in several maps, named [kernel].N, as we don't have |
665 | * the original ELF section names vmlinux have. | 628 | * the original ELF section names vmlinux have. |
666 | */ | 629 | */ |
667 | static int dso__split_kallsyms(struct dso *dso, struct map *map, | 630 | static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta, |
668 | symbol_filter_t filter) | 631 | symbol_filter_t filter) |
669 | { | 632 | { |
670 | struct map_groups *kmaps = map__kmap(map)->kmaps; | 633 | struct map_groups *kmaps = map__kmap(map)->kmaps; |
@@ -729,6 +692,12 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, | |||
729 | char dso_name[PATH_MAX]; | 692 | char dso_name[PATH_MAX]; |
730 | struct dso *ndso; | 693 | struct dso *ndso; |
731 | 694 | ||
695 | if (delta) { | ||
696 | /* Kernel was relocated at boot time */ | ||
697 | pos->start -= delta; | ||
698 | pos->end -= delta; | ||
699 | } | ||
700 | |||
732 | if (count == 0) { | 701 | if (count == 0) { |
733 | curr_map = map; | 702 | curr_map = map; |
734 | goto filter_symbol; | 703 | goto filter_symbol; |
@@ -758,6 +727,10 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, | |||
758 | curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; | 727 | curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; |
759 | map_groups__insert(kmaps, curr_map); | 728 | map_groups__insert(kmaps, curr_map); |
760 | ++kernel_range; | 729 | ++kernel_range; |
730 | } else if (delta) { | ||
731 | /* Kernel was relocated at boot time */ | ||
732 | pos->start -= delta; | ||
733 | pos->end -= delta; | ||
761 | } | 734 | } |
762 | filter_symbol: | 735 | filter_symbol: |
763 | if (filter && filter(curr_map, pos)) { | 736 | if (filter && filter(curr_map, pos)) { |
@@ -833,7 +806,7 @@ static void delete_modules(struct rb_root *modules) | |||
833 | mi = rb_entry(next, struct module_info, rb_node); | 806 | mi = rb_entry(next, struct module_info, rb_node); |
834 | next = rb_next(&mi->rb_node); | 807 | next = rb_next(&mi->rb_node); |
835 | rb_erase(&mi->rb_node, modules); | 808 | rb_erase(&mi->rb_node, modules); |
836 | free(mi->name); | 809 | zfree(&mi->name); |
837 | free(mi); | 810 | free(mi); |
838 | } | 811 | } |
839 | } | 812 | } |
@@ -1013,6 +986,23 @@ static int validate_kcore_modules(const char *kallsyms_filename, | |||
1013 | return 0; | 986 | return 0; |
1014 | } | 987 | } |
1015 | 988 | ||
989 | static int validate_kcore_addresses(const char *kallsyms_filename, | ||
990 | struct map *map) | ||
991 | { | ||
992 | struct kmap *kmap = map__kmap(map); | ||
993 | |||
994 | if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) { | ||
995 | u64 start; | ||
996 | |||
997 | start = kallsyms__get_function_start(kallsyms_filename, | ||
998 | kmap->ref_reloc_sym->name); | ||
999 | if (start != kmap->ref_reloc_sym->addr) | ||
1000 | return -EINVAL; | ||
1001 | } | ||
1002 | |||
1003 | return validate_kcore_modules(kallsyms_filename, map); | ||
1004 | } | ||
1005 | |||
1016 | struct kcore_mapfn_data { | 1006 | struct kcore_mapfn_data { |
1017 | struct dso *dso; | 1007 | struct dso *dso; |
1018 | enum map_type type; | 1008 | enum map_type type; |
@@ -1056,8 +1046,8 @@ static int dso__load_kcore(struct dso *dso, struct map *map, | |||
1056 | kallsyms_filename)) | 1046 | kallsyms_filename)) |
1057 | return -EINVAL; | 1047 | return -EINVAL; |
1058 | 1048 | ||
1059 | /* All modules must be present at their original addresses */ | 1049 | /* Modules and kernel must be present at their original addresses */ |
1060 | if (validate_kcore_modules(kallsyms_filename, map)) | 1050 | if (validate_kcore_addresses(kallsyms_filename, map)) |
1061 | return -EINVAL; | 1051 | return -EINVAL; |
1062 | 1052 | ||
1063 | md.dso = dso; | 1053 | md.dso = dso; |
@@ -1126,10 +1116,10 @@ static int dso__load_kcore(struct dso *dso, struct map *map, | |||
1126 | * dso__data_read_addr(). | 1116 | * dso__data_read_addr(). |
1127 | */ | 1117 | */ |
1128 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) | 1118 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) |
1129 | dso->data_type = DSO_BINARY_TYPE__GUEST_KCORE; | 1119 | dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE; |
1130 | else | 1120 | else |
1131 | dso->data_type = DSO_BINARY_TYPE__KCORE; | 1121 | dso->binary_type = DSO_BINARY_TYPE__KCORE; |
1132 | dso__set_long_name(dso, strdup(kcore_filename)); | 1122 | dso__set_long_name(dso, strdup(kcore_filename), true); |
1133 | 1123 | ||
1134 | close(fd); | 1124 | close(fd); |
1135 | 1125 | ||
@@ -1150,15 +1140,41 @@ out_err: | |||
1150 | return -EINVAL; | 1140 | return -EINVAL; |
1151 | } | 1141 | } |
1152 | 1142 | ||
1143 | /* | ||
1144 | * If the kernel is relocated at boot time, kallsyms won't match. Compute the | ||
1145 | * delta based on the relocation reference symbol. | ||
1146 | */ | ||
1147 | static int kallsyms__delta(struct map *map, const char *filename, u64 *delta) | ||
1148 | { | ||
1149 | struct kmap *kmap = map__kmap(map); | ||
1150 | u64 addr; | ||
1151 | |||
1152 | if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name) | ||
1153 | return 0; | ||
1154 | |||
1155 | addr = kallsyms__get_function_start(filename, | ||
1156 | kmap->ref_reloc_sym->name); | ||
1157 | if (!addr) | ||
1158 | return -1; | ||
1159 | |||
1160 | *delta = addr - kmap->ref_reloc_sym->addr; | ||
1161 | return 0; | ||
1162 | } | ||
1163 | |||
1153 | int dso__load_kallsyms(struct dso *dso, const char *filename, | 1164 | int dso__load_kallsyms(struct dso *dso, const char *filename, |
1154 | struct map *map, symbol_filter_t filter) | 1165 | struct map *map, symbol_filter_t filter) |
1155 | { | 1166 | { |
1167 | u64 delta = 0; | ||
1168 | |||
1156 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) | 1169 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) |
1157 | return -1; | 1170 | return -1; |
1158 | 1171 | ||
1159 | if (dso__load_all_kallsyms(dso, filename, map) < 0) | 1172 | if (dso__load_all_kallsyms(dso, filename, map) < 0) |
1160 | return -1; | 1173 | return -1; |
1161 | 1174 | ||
1175 | if (kallsyms__delta(map, filename, &delta)) | ||
1176 | return -1; | ||
1177 | |||
1162 | symbols__fixup_duplicate(&dso->symbols[map->type]); | 1178 | symbols__fixup_duplicate(&dso->symbols[map->type]); |
1163 | symbols__fixup_end(&dso->symbols[map->type]); | 1179 | symbols__fixup_end(&dso->symbols[map->type]); |
1164 | 1180 | ||
@@ -1170,7 +1186,7 @@ int dso__load_kallsyms(struct dso *dso, const char *filename, | |||
1170 | if (!dso__load_kcore(dso, map, filename)) | 1186 | if (!dso__load_kcore(dso, map, filename)) |
1171 | return dso__split_kallsyms_for_kcore(dso, map, filter); | 1187 | return dso__split_kallsyms_for_kcore(dso, map, filter); |
1172 | else | 1188 | else |
1173 | return dso__split_kallsyms(dso, map, filter); | 1189 | return dso__split_kallsyms(dso, map, delta, filter); |
1174 | } | 1190 | } |
1175 | 1191 | ||
1176 | static int dso__load_perf_map(struct dso *dso, struct map *map, | 1192 | static int dso__load_perf_map(struct dso *dso, struct map *map, |
@@ -1295,8 +1311,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
1295 | 1311 | ||
1296 | enum dso_binary_type symtab_type = binary_type_symtab[i]; | 1312 | enum dso_binary_type symtab_type = binary_type_symtab[i]; |
1297 | 1313 | ||
1298 | if (dso__binary_type_file(dso, symtab_type, | 1314 | if (dso__read_binary_type_filename(dso, symtab_type, |
1299 | root_dir, name, PATH_MAX)) | 1315 | root_dir, name, PATH_MAX)) |
1300 | continue; | 1316 | continue; |
1301 | 1317 | ||
1302 | /* Name is now the name of the next image to try */ | 1318 | /* Name is now the name of the next image to try */ |
@@ -1306,6 +1322,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
1306 | if (!syms_ss && symsrc__has_symtab(ss)) { | 1322 | if (!syms_ss && symsrc__has_symtab(ss)) { |
1307 | syms_ss = ss; | 1323 | syms_ss = ss; |
1308 | next_slot = true; | 1324 | next_slot = true; |
1325 | if (!dso->symsrc_filename) | ||
1326 | dso->symsrc_filename = strdup(name); | ||
1309 | } | 1327 | } |
1310 | 1328 | ||
1311 | if (!runtime_ss && symsrc__possibly_runtime(ss)) { | 1329 | if (!runtime_ss && symsrc__possibly_runtime(ss)) { |
@@ -1318,6 +1336,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
1318 | 1336 | ||
1319 | if (syms_ss && runtime_ss) | 1337 | if (syms_ss && runtime_ss) |
1320 | break; | 1338 | break; |
1339 | } else { | ||
1340 | symsrc__destroy(ss); | ||
1321 | } | 1341 | } |
1322 | 1342 | ||
1323 | } | 1343 | } |
@@ -1376,7 +1396,8 @@ struct map *map_groups__find_by_name(struct map_groups *mg, | |||
1376 | } | 1396 | } |
1377 | 1397 | ||
1378 | int dso__load_vmlinux(struct dso *dso, struct map *map, | 1398 | int dso__load_vmlinux(struct dso *dso, struct map *map, |
1379 | const char *vmlinux, symbol_filter_t filter) | 1399 | const char *vmlinux, bool vmlinux_allocated, |
1400 | symbol_filter_t filter) | ||
1380 | { | 1401 | { |
1381 | int err = -1; | 1402 | int err = -1; |
1382 | struct symsrc ss; | 1403 | struct symsrc ss; |
@@ -1402,10 +1423,10 @@ int dso__load_vmlinux(struct dso *dso, struct map *map, | |||
1402 | 1423 | ||
1403 | if (err > 0) { | 1424 | if (err > 0) { |
1404 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) | 1425 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) |
1405 | dso->data_type = DSO_BINARY_TYPE__GUEST_VMLINUX; | 1426 | dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX; |
1406 | else | 1427 | else |
1407 | dso->data_type = DSO_BINARY_TYPE__VMLINUX; | 1428 | dso->binary_type = DSO_BINARY_TYPE__VMLINUX; |
1408 | dso__set_long_name(dso, (char *)vmlinux); | 1429 | dso__set_long_name(dso, vmlinux, vmlinux_allocated); |
1409 | dso__set_loaded(dso, map->type); | 1430 | dso__set_loaded(dso, map->type); |
1410 | pr_debug("Using %s for symbols\n", symfs_vmlinux); | 1431 | pr_debug("Using %s for symbols\n", symfs_vmlinux); |
1411 | } | 1432 | } |
@@ -1424,21 +1445,16 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, | |||
1424 | 1445 | ||
1425 | filename = dso__build_id_filename(dso, NULL, 0); | 1446 | filename = dso__build_id_filename(dso, NULL, 0); |
1426 | if (filename != NULL) { | 1447 | if (filename != NULL) { |
1427 | err = dso__load_vmlinux(dso, map, filename, filter); | 1448 | err = dso__load_vmlinux(dso, map, filename, true, filter); |
1428 | if (err > 0) { | 1449 | if (err > 0) |
1429 | dso->lname_alloc = 1; | ||
1430 | goto out; | 1450 | goto out; |
1431 | } | ||
1432 | free(filename); | 1451 | free(filename); |
1433 | } | 1452 | } |
1434 | 1453 | ||
1435 | for (i = 0; i < vmlinux_path__nr_entries; ++i) { | 1454 | for (i = 0; i < vmlinux_path__nr_entries; ++i) { |
1436 | err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); | 1455 | err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter); |
1437 | if (err > 0) { | 1456 | if (err > 0) |
1438 | dso__set_long_name(dso, strdup(vmlinux_path[i])); | ||
1439 | dso->lname_alloc = 1; | ||
1440 | break; | 1457 | break; |
1441 | } | ||
1442 | } | 1458 | } |
1443 | out: | 1459 | out: |
1444 | return err; | 1460 | return err; |
@@ -1463,7 +1479,7 @@ static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) | |||
1463 | continue; | 1479 | continue; |
1464 | scnprintf(kallsyms_filename, sizeof(kallsyms_filename), | 1480 | scnprintf(kallsyms_filename, sizeof(kallsyms_filename), |
1465 | "%s/%s/kallsyms", dir, dent->d_name); | 1481 | "%s/%s/kallsyms", dir, dent->d_name); |
1466 | if (!validate_kcore_modules(kallsyms_filename, map)) { | 1482 | if (!validate_kcore_addresses(kallsyms_filename, map)) { |
1467 | strlcpy(dir, kallsyms_filename, dir_sz); | 1483 | strlcpy(dir, kallsyms_filename, dir_sz); |
1468 | ret = 0; | 1484 | ret = 0; |
1469 | break; | 1485 | break; |
@@ -1496,14 +1512,15 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map) | |||
1496 | 1512 | ||
1497 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); | 1513 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); |
1498 | 1514 | ||
1515 | scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", buildid_dir, | ||
1516 | sbuild_id); | ||
1517 | |||
1499 | /* Use /proc/kallsyms if possible */ | 1518 | /* Use /proc/kallsyms if possible */ |
1500 | if (is_host) { | 1519 | if (is_host) { |
1501 | DIR *d; | 1520 | DIR *d; |
1502 | int fd; | 1521 | int fd; |
1503 | 1522 | ||
1504 | /* If no cached kcore go with /proc/kallsyms */ | 1523 | /* If no cached kcore go with /proc/kallsyms */ |
1505 | scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", | ||
1506 | buildid_dir, sbuild_id); | ||
1507 | d = opendir(path); | 1524 | d = opendir(path); |
1508 | if (!d) | 1525 | if (!d) |
1509 | goto proc_kallsyms; | 1526 | goto proc_kallsyms; |
@@ -1517,7 +1534,7 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map) | |||
1517 | if (fd != -1) { | 1534 | if (fd != -1) { |
1518 | close(fd); | 1535 | close(fd); |
1519 | /* If module maps match go with /proc/kallsyms */ | 1536 | /* If module maps match go with /proc/kallsyms */ |
1520 | if (!validate_kcore_modules("/proc/kallsyms", map)) | 1537 | if (!validate_kcore_addresses("/proc/kallsyms", map)) |
1521 | goto proc_kallsyms; | 1538 | goto proc_kallsyms; |
1522 | } | 1539 | } |
1523 | 1540 | ||
@@ -1528,6 +1545,10 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map) | |||
1528 | goto proc_kallsyms; | 1545 | goto proc_kallsyms; |
1529 | } | 1546 | } |
1530 | 1547 | ||
1548 | /* Find kallsyms in build-id cache with kcore */ | ||
1549 | if (!find_matching_kcore(map, path, sizeof(path))) | ||
1550 | return strdup(path); | ||
1551 | |||
1531 | scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s", | 1552 | scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s", |
1532 | buildid_dir, sbuild_id); | 1553 | buildid_dir, sbuild_id); |
1533 | 1554 | ||
@@ -1570,15 +1591,8 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, | |||
1570 | } | 1591 | } |
1571 | 1592 | ||
1572 | if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { | 1593 | if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { |
1573 | err = dso__load_vmlinux(dso, map, | 1594 | return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, |
1574 | symbol_conf.vmlinux_name, filter); | 1595 | false, filter); |
1575 | if (err > 0) { | ||
1576 | dso__set_long_name(dso, | ||
1577 | strdup(symbol_conf.vmlinux_name)); | ||
1578 | dso->lname_alloc = 1; | ||
1579 | return err; | ||
1580 | } | ||
1581 | return err; | ||
1582 | } | 1596 | } |
1583 | 1597 | ||
1584 | if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { | 1598 | if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { |
@@ -1604,7 +1618,7 @@ do_kallsyms: | |||
1604 | free(kallsyms_allocated_filename); | 1618 | free(kallsyms_allocated_filename); |
1605 | 1619 | ||
1606 | if (err > 0 && !dso__is_kcore(dso)) { | 1620 | if (err > 0 && !dso__is_kcore(dso)) { |
1607 | dso__set_long_name(dso, strdup("[kernel.kallsyms]")); | 1621 | dso__set_long_name(dso, "[kernel.kallsyms]", false); |
1608 | map__fixup_start(map); | 1622 | map__fixup_start(map); |
1609 | map__fixup_end(map); | 1623 | map__fixup_end(map); |
1610 | } | 1624 | } |
@@ -1634,7 +1648,8 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | |||
1634 | */ | 1648 | */ |
1635 | if (symbol_conf.default_guest_vmlinux_name != NULL) { | 1649 | if (symbol_conf.default_guest_vmlinux_name != NULL) { |
1636 | err = dso__load_vmlinux(dso, map, | 1650 | err = dso__load_vmlinux(dso, map, |
1637 | symbol_conf.default_guest_vmlinux_name, filter); | 1651 | symbol_conf.default_guest_vmlinux_name, |
1652 | false, filter); | ||
1638 | return err; | 1653 | return err; |
1639 | } | 1654 | } |
1640 | 1655 | ||
@@ -1651,7 +1666,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | |||
1651 | pr_debug("Using %s for symbols\n", kallsyms_filename); | 1666 | pr_debug("Using %s for symbols\n", kallsyms_filename); |
1652 | if (err > 0 && !dso__is_kcore(dso)) { | 1667 | if (err > 0 && !dso__is_kcore(dso)) { |
1653 | machine__mmap_name(machine, path, sizeof(path)); | 1668 | machine__mmap_name(machine, path, sizeof(path)); |
1654 | dso__set_long_name(dso, strdup(path)); | 1669 | dso__set_long_name(dso, strdup(path), true); |
1655 | map__fixup_start(map); | 1670 | map__fixup_start(map); |
1656 | map__fixup_end(map); | 1671 | map__fixup_end(map); |
1657 | } | 1672 | } |
@@ -1661,13 +1676,10 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | |||
1661 | 1676 | ||
1662 | static void vmlinux_path__exit(void) | 1677 | static void vmlinux_path__exit(void) |
1663 | { | 1678 | { |
1664 | while (--vmlinux_path__nr_entries >= 0) { | 1679 | while (--vmlinux_path__nr_entries >= 0) |
1665 | free(vmlinux_path[vmlinux_path__nr_entries]); | 1680 | zfree(&vmlinux_path[vmlinux_path__nr_entries]); |
1666 | vmlinux_path[vmlinux_path__nr_entries] = NULL; | ||
1667 | } | ||
1668 | 1681 | ||
1669 | free(vmlinux_path); | 1682 | zfree(&vmlinux_path); |
1670 | vmlinux_path = NULL; | ||
1671 | } | 1683 | } |
1672 | 1684 | ||
1673 | static int vmlinux_path__init(void) | 1685 | static int vmlinux_path__init(void) |
@@ -1719,7 +1731,7 @@ out_fail: | |||
1719 | return -1; | 1731 | return -1; |
1720 | } | 1732 | } |
1721 | 1733 | ||
1722 | static int setup_list(struct strlist **list, const char *list_str, | 1734 | int setup_list(struct strlist **list, const char *list_str, |
1723 | const char *list_name) | 1735 | const char *list_name) |
1724 | { | 1736 | { |
1725 | if (list_str == NULL) | 1737 | if (list_str == NULL) |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 07de8fea2f48..fffe2888a1c7 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -52,6 +52,11 @@ static inline char *bfd_demangle(void __maybe_unused *v, | |||
52 | # define PERF_ELF_C_READ_MMAP ELF_C_READ | 52 | # define PERF_ELF_C_READ_MMAP ELF_C_READ |
53 | #endif | 53 | #endif |
54 | 54 | ||
55 | #ifdef HAVE_LIBELF_SUPPORT | ||
56 | extern Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | ||
57 | GElf_Shdr *shp, const char *name, size_t *idx); | ||
58 | #endif | ||
59 | |||
55 | #ifndef DMGL_PARAMS | 60 | #ifndef DMGL_PARAMS |
56 | #define DMGL_PARAMS (1 << 0) /* Include function args */ | 61 | #define DMGL_PARAMS (1 << 0) /* Include function args */ |
57 | #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ | 62 | #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ |
@@ -164,6 +169,7 @@ struct mem_info { | |||
164 | }; | 169 | }; |
165 | 170 | ||
166 | struct addr_location { | 171 | struct addr_location { |
172 | struct machine *machine; | ||
167 | struct thread *thread; | 173 | struct thread *thread; |
168 | struct map *map; | 174 | struct map *map; |
169 | struct symbol *sym; | 175 | struct symbol *sym; |
@@ -206,7 +212,8 @@ bool symsrc__possibly_runtime(struct symsrc *ss); | |||
206 | 212 | ||
207 | int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); | 213 | int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); |
208 | int dso__load_vmlinux(struct dso *dso, struct map *map, | 214 | int dso__load_vmlinux(struct dso *dso, struct map *map, |
209 | const char *vmlinux, symbol_filter_t filter); | 215 | const char *vmlinux, bool vmlinux_allocated, |
216 | symbol_filter_t filter); | ||
210 | int dso__load_vmlinux_path(struct dso *dso, struct map *map, | 217 | int dso__load_vmlinux_path(struct dso *dso, struct map *map, |
211 | symbol_filter_t filter); | 218 | symbol_filter_t filter); |
212 | int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, | 219 | int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, |
@@ -220,9 +227,6 @@ struct symbol *dso__first_symbol(struct dso *dso, enum map_type type); | |||
220 | 227 | ||
221 | int filename__read_build_id(const char *filename, void *bf, size_t size); | 228 | int filename__read_build_id(const char *filename, void *bf, size_t size); |
222 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); | 229 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); |
223 | int kallsyms__parse(const char *filename, void *arg, | ||
224 | int (*process_symbol)(void *arg, const char *name, | ||
225 | char type, u64 start)); | ||
226 | int modules__parse(const char *filename, void *arg, | 230 | int modules__parse(const char *filename, void *arg, |
227 | int (*process_module)(void *arg, const char *name, | 231 | int (*process_module)(void *arg, const char *name, |
228 | u64 start)); | 232 | u64 start)); |
@@ -240,6 +244,7 @@ size_t symbol__fprintf(struct symbol *sym, FILE *fp); | |||
240 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); | 244 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); |
241 | bool symbol__restricted_filename(const char *filename, | 245 | bool symbol__restricted_filename(const char *filename, |
242 | const char *restricted_filename); | 246 | const char *restricted_filename); |
247 | bool symbol__is_idle(struct symbol *sym); | ||
243 | 248 | ||
244 | int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, | 249 | int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, |
245 | struct symsrc *runtime_ss, symbol_filter_t filter, | 250 | struct symsrc *runtime_ss, symbol_filter_t filter, |
@@ -273,4 +278,7 @@ void kcore_extract__delete(struct kcore_extract *kce); | |||
273 | int kcore_copy(const char *from_dir, const char *to_dir); | 278 | int kcore_copy(const char *from_dir, const char *to_dir); |
274 | int compare_proc_modules(const char *from, const char *to); | 279 | int compare_proc_modules(const char *from, const char *to); |
275 | 280 | ||
281 | int setup_list(struct strlist **list, const char *list_str, | ||
282 | const char *list_name); | ||
283 | |||
276 | #endif /* __PERF_SYMBOL */ | 284 | #endif /* __PERF_SYMBOL */ |
diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c index 3c778a07b7cc..e74c5963dc7a 100644 --- a/tools/perf/util/target.c +++ b/tools/perf/util/target.c | |||
@@ -55,6 +55,13 @@ enum target_errno target__validate(struct target *target) | |||
55 | ret = TARGET_ERRNO__UID_OVERRIDE_SYSTEM; | 55 | ret = TARGET_ERRNO__UID_OVERRIDE_SYSTEM; |
56 | } | 56 | } |
57 | 57 | ||
58 | /* THREAD and SYSTEM/CPU are mutually exclusive */ | ||
59 | if (target->per_thread && (target->system_wide || target->cpu_list)) { | ||
60 | target->per_thread = false; | ||
61 | if (ret == TARGET_ERRNO__SUCCESS) | ||
62 | ret = TARGET_ERRNO__SYSTEM_OVERRIDE_THREAD; | ||
63 | } | ||
64 | |||
58 | return ret; | 65 | return ret; |
59 | } | 66 | } |
60 | 67 | ||
@@ -100,6 +107,7 @@ static const char *target__error_str[] = { | |||
100 | "UID switch overriding CPU", | 107 | "UID switch overriding CPU", |
101 | "PID/TID switch overriding SYSTEM", | 108 | "PID/TID switch overriding SYSTEM", |
102 | "UID switch overriding SYSTEM", | 109 | "UID switch overriding SYSTEM", |
110 | "SYSTEM/CPU switch overriding PER-THREAD", | ||
103 | "Invalid User: %s", | 111 | "Invalid User: %s", |
104 | "Problems obtaining information for user %s", | 112 | "Problems obtaining information for user %s", |
105 | }; | 113 | }; |
@@ -131,7 +139,8 @@ int target__strerror(struct target *target, int errnum, | |||
131 | msg = target__error_str[idx]; | 139 | msg = target__error_str[idx]; |
132 | 140 | ||
133 | switch (errnum) { | 141 | switch (errnum) { |
134 | case TARGET_ERRNO__PID_OVERRIDE_CPU ... TARGET_ERRNO__UID_OVERRIDE_SYSTEM: | 142 | case TARGET_ERRNO__PID_OVERRIDE_CPU ... |
143 | TARGET_ERRNO__SYSTEM_OVERRIDE_THREAD: | ||
135 | snprintf(buf, buflen, "%s", msg); | 144 | snprintf(buf, buflen, "%s", msg); |
136 | break; | 145 | break; |
137 | 146 | ||
diff --git a/tools/perf/util/target.h b/tools/perf/util/target.h index 2d0c50690892..7381b1ca4041 100644 --- a/tools/perf/util/target.h +++ b/tools/perf/util/target.h | |||
@@ -12,7 +12,8 @@ struct target { | |||
12 | uid_t uid; | 12 | uid_t uid; |
13 | bool system_wide; | 13 | bool system_wide; |
14 | bool uses_mmap; | 14 | bool uses_mmap; |
15 | bool force_per_cpu; | 15 | bool default_per_cpu; |
16 | bool per_thread; | ||
16 | }; | 17 | }; |
17 | 18 | ||
18 | enum target_errno { | 19 | enum target_errno { |
@@ -33,6 +34,7 @@ enum target_errno { | |||
33 | TARGET_ERRNO__UID_OVERRIDE_CPU, | 34 | TARGET_ERRNO__UID_OVERRIDE_CPU, |
34 | TARGET_ERRNO__PID_OVERRIDE_SYSTEM, | 35 | TARGET_ERRNO__PID_OVERRIDE_SYSTEM, |
35 | TARGET_ERRNO__UID_OVERRIDE_SYSTEM, | 36 | TARGET_ERRNO__UID_OVERRIDE_SYSTEM, |
37 | TARGET_ERRNO__SYSTEM_OVERRIDE_THREAD, | ||
36 | 38 | ||
37 | /* for target__parse_uid() */ | 39 | /* for target__parse_uid() */ |
38 | TARGET_ERRNO__INVALID_UID, | 40 | TARGET_ERRNO__INVALID_UID, |
@@ -61,4 +63,17 @@ static inline bool target__none(struct target *target) | |||
61 | return !target__has_task(target) && !target__has_cpu(target); | 63 | return !target__has_task(target) && !target__has_cpu(target); |
62 | } | 64 | } |
63 | 65 | ||
66 | static inline bool target__uses_dummy_map(struct target *target) | ||
67 | { | ||
68 | bool use_dummy = false; | ||
69 | |||
70 | if (target->default_per_cpu) | ||
71 | use_dummy = target->per_thread ? true : false; | ||
72 | else if (target__has_task(target) || | ||
73 | (!target__has_cpu(target) && !target->uses_mmap)) | ||
74 | use_dummy = true; | ||
75 | |||
76 | return use_dummy; | ||
77 | } | ||
78 | |||
64 | #endif /* _PERF_TARGET_H */ | 79 | #endif /* _PERF_TARGET_H */ |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 49eaf1d7d89d..0358882c8910 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -66,10 +66,13 @@ struct comm *thread__comm(const struct thread *thread) | |||
66 | int thread__set_comm(struct thread *thread, const char *str, u64 timestamp) | 66 | int thread__set_comm(struct thread *thread, const char *str, u64 timestamp) |
67 | { | 67 | { |
68 | struct comm *new, *curr = thread__comm(thread); | 68 | struct comm *new, *curr = thread__comm(thread); |
69 | int err; | ||
69 | 70 | ||
70 | /* Override latest entry if it had no specific time coverage */ | 71 | /* Override latest entry if it had no specific time coverage */ |
71 | if (!curr->start) { | 72 | if (!curr->start) { |
72 | comm__override(curr, str, timestamp); | 73 | err = comm__override(curr, str, timestamp); |
74 | if (err) | ||
75 | return err; | ||
73 | } else { | 76 | } else { |
74 | new = comm__new(str, timestamp); | 77 | new = comm__new(str, timestamp); |
75 | if (!new) | 78 | if (!new) |
@@ -126,7 +129,7 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) | |||
126 | if (!comm) | 129 | if (!comm) |
127 | return -ENOMEM; | 130 | return -ENOMEM; |
128 | err = thread__set_comm(thread, comm, timestamp); | 131 | err = thread__set_comm(thread, comm, timestamp); |
129 | if (!err) | 132 | if (err) |
130 | return err; | 133 | return err; |
131 | thread->comm_set = true; | 134 | thread->comm_set = true; |
132 | } | 135 | } |
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 897c1b2a750a..5b856bf942e1 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <unistd.h> | 6 | #include <unistd.h> |
7 | #include <sys/types.h> | 7 | #include <sys/types.h> |
8 | #include "symbol.h" | 8 | #include "symbol.h" |
9 | #include <strlist.h> | ||
9 | 10 | ||
10 | struct thread { | 11 | struct thread { |
11 | union { | 12 | union { |
@@ -66,4 +67,15 @@ static inline void thread__set_priv(struct thread *thread, void *p) | |||
66 | { | 67 | { |
67 | thread->priv = p; | 68 | thread->priv = p; |
68 | } | 69 | } |
70 | |||
71 | static inline bool thread__is_filtered(struct thread *thread) | ||
72 | { | ||
73 | if (symbol_conf.comm_list && | ||
74 | !strlist__has_entry(symbol_conf.comm_list, thread__comm_str(thread))) { | ||
75 | return true; | ||
76 | } | ||
77 | |||
78 | return false; | ||
79 | } | ||
80 | |||
69 | #endif /* __PERF_THREAD_H */ | 81 | #endif /* __PERF_THREAD_H */ |
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index 9b5f856cc280..5d3215912105 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include "strlist.h" | 9 | #include "strlist.h" |
10 | #include <string.h> | 10 | #include <string.h> |
11 | #include "thread_map.h" | 11 | #include "thread_map.h" |
12 | #include "util.h" | ||
12 | 13 | ||
13 | /* Skip "." and ".." directories */ | 14 | /* Skip "." and ".." directories */ |
14 | static int filter(const struct dirent *dir) | 15 | static int filter(const struct dirent *dir) |
@@ -40,7 +41,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid) | |||
40 | } | 41 | } |
41 | 42 | ||
42 | for (i=0; i<items; i++) | 43 | for (i=0; i<items; i++) |
43 | free(namelist[i]); | 44 | zfree(&namelist[i]); |
44 | free(namelist); | 45 | free(namelist); |
45 | 46 | ||
46 | return threads; | 47 | return threads; |
@@ -117,7 +118,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) | |||
117 | threads->map[threads->nr + i] = atoi(namelist[i]->d_name); | 118 | threads->map[threads->nr + i] = atoi(namelist[i]->d_name); |
118 | 119 | ||
119 | for (i = 0; i < items; i++) | 120 | for (i = 0; i < items; i++) |
120 | free(namelist[i]); | 121 | zfree(&namelist[i]); |
121 | free(namelist); | 122 | free(namelist); |
122 | 123 | ||
123 | threads->nr += items; | 124 | threads->nr += items; |
@@ -134,12 +135,11 @@ out_free_threads: | |||
134 | 135 | ||
135 | out_free_namelist: | 136 | out_free_namelist: |
136 | for (i = 0; i < items; i++) | 137 | for (i = 0; i < items; i++) |
137 | free(namelist[i]); | 138 | zfree(&namelist[i]); |
138 | free(namelist); | 139 | free(namelist); |
139 | 140 | ||
140 | out_free_closedir: | 141 | out_free_closedir: |
141 | free(threads); | 142 | zfree(&threads); |
142 | threads = NULL; | ||
143 | goto out_closedir; | 143 | goto out_closedir; |
144 | } | 144 | } |
145 | 145 | ||
@@ -194,7 +194,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) | |||
194 | 194 | ||
195 | for (i = 0; i < items; i++) { | 195 | for (i = 0; i < items; i++) { |
196 | threads->map[j++] = atoi(namelist[i]->d_name); | 196 | threads->map[j++] = atoi(namelist[i]->d_name); |
197 | free(namelist[i]); | 197 | zfree(&namelist[i]); |
198 | } | 198 | } |
199 | threads->nr = total_tasks; | 199 | threads->nr = total_tasks; |
200 | free(namelist); | 200 | free(namelist); |
@@ -206,12 +206,11 @@ out: | |||
206 | 206 | ||
207 | out_free_namelist: | 207 | out_free_namelist: |
208 | for (i = 0; i < items; i++) | 208 | for (i = 0; i < items; i++) |
209 | free(namelist[i]); | 209 | zfree(&namelist[i]); |
210 | free(namelist); | 210 | free(namelist); |
211 | 211 | ||
212 | out_free_threads: | 212 | out_free_threads: |
213 | free(threads); | 213 | zfree(&threads); |
214 | threads = NULL; | ||
215 | goto out; | 214 | goto out; |
216 | } | 215 | } |
217 | 216 | ||
@@ -262,8 +261,7 @@ out: | |||
262 | return threads; | 261 | return threads; |
263 | 262 | ||
264 | out_free_threads: | 263 | out_free_threads: |
265 | free(threads); | 264 | zfree(&threads); |
266 | threads = NULL; | ||
267 | goto out; | 265 | goto out; |
268 | } | 266 | } |
269 | 267 | ||
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index ce793c7dd23c..8e517def925b 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c | |||
@@ -26,7 +26,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) | |||
26 | float samples_per_sec; | 26 | float samples_per_sec; |
27 | float ksamples_per_sec; | 27 | float ksamples_per_sec; |
28 | float esamples_percent; | 28 | float esamples_percent; |
29 | struct perf_record_opts *opts = &top->record_opts; | 29 | struct record_opts *opts = &top->record_opts; |
30 | struct target *target = &opts->target; | 30 | struct target *target = &opts->target; |
31 | size_t ret = 0; | 31 | size_t ret = 0; |
32 | 32 | ||
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 88cfeaff600b..dab14d0ad3d0 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h | |||
@@ -14,7 +14,7 @@ struct perf_session; | |||
14 | struct perf_top { | 14 | struct perf_top { |
15 | struct perf_tool tool; | 15 | struct perf_tool tool; |
16 | struct perf_evlist *evlist; | 16 | struct perf_evlist *evlist; |
17 | struct perf_record_opts record_opts; | 17 | struct record_opts record_opts; |
18 | /* | 18 | /* |
19 | * Symbols will be added here in perf_event__process_sample and will | 19 | * Symbols will be added here in perf_event__process_sample and will |
20 | * get out after decayed. | 20 | * get out after decayed. |
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index f3c9e551bd35..7e6fcfe8b438 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c | |||
@@ -38,7 +38,7 @@ | |||
38 | 38 | ||
39 | #include "../perf.h" | 39 | #include "../perf.h" |
40 | #include "trace-event.h" | 40 | #include "trace-event.h" |
41 | #include <lk/debugfs.h> | 41 | #include <api/fs/debugfs.h> |
42 | #include "evsel.h" | 42 | #include "evsel.h" |
43 | 43 | ||
44 | #define VERSION "0.5" | 44 | #define VERSION "0.5" |
@@ -397,8 +397,8 @@ put_tracepoints_path(struct tracepoint_path *tps) | |||
397 | struct tracepoint_path *t = tps; | 397 | struct tracepoint_path *t = tps; |
398 | 398 | ||
399 | tps = tps->next; | 399 | tps = tps->next; |
400 | free(t->name); | 400 | zfree(&t->name); |
401 | free(t->system); | 401 | zfree(&t->system); |
402 | free(t); | 402 | free(t); |
403 | } | 403 | } |
404 | } | 404 | } |
@@ -562,10 +562,8 @@ out: | |||
562 | output_fd = fd; | 562 | output_fd = fd; |
563 | } | 563 | } |
564 | 564 | ||
565 | if (err) { | 565 | if (err) |
566 | free(tdata); | 566 | zfree(&tdata); |
567 | tdata = NULL; | ||
568 | } | ||
569 | 567 | ||
570 | put_tracepoints_path(tps); | 568 | put_tracepoints_path(tps); |
571 | return tdata; | 569 | return tdata; |
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 6681f71f2f95..e0d6d07f6848 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
@@ -28,19 +28,6 @@ | |||
28 | #include "util.h" | 28 | #include "util.h" |
29 | #include "trace-event.h" | 29 | #include "trace-event.h" |
30 | 30 | ||
31 | struct pevent *read_trace_init(int file_bigendian, int host_bigendian) | ||
32 | { | ||
33 | struct pevent *pevent = pevent_alloc(); | ||
34 | |||
35 | if (pevent != NULL) { | ||
36 | pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); | ||
37 | pevent_set_file_bigendian(pevent, file_bigendian); | ||
38 | pevent_set_host_bigendian(pevent, host_bigendian); | ||
39 | } | ||
40 | |||
41 | return pevent; | ||
42 | } | ||
43 | |||
44 | static int get_common_field(struct scripting_context *context, | 31 | static int get_common_field(struct scripting_context *context, |
45 | int *offset, int *size, const char *type) | 32 | int *offset, int *size, const char *type) |
46 | { | 33 | { |
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index f2112270c663..e113e180c48f 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c | |||
@@ -343,7 +343,7 @@ static int read_event_files(struct pevent *pevent) | |||
343 | return 0; | 343 | return 0; |
344 | } | 344 | } |
345 | 345 | ||
346 | ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) | 346 | ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) |
347 | { | 347 | { |
348 | char buf[BUFSIZ]; | 348 | char buf[BUFSIZ]; |
349 | char test[] = { 23, 8, 68 }; | 349 | char test[] = { 23, 8, 68 }; |
@@ -356,11 +356,9 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) | |||
356 | int host_bigendian; | 356 | int host_bigendian; |
357 | int file_long_size; | 357 | int file_long_size; |
358 | int file_page_size; | 358 | int file_page_size; |
359 | struct pevent *pevent; | 359 | struct pevent *pevent = NULL; |
360 | int err; | 360 | int err; |
361 | 361 | ||
362 | *ppevent = NULL; | ||
363 | |||
364 | repipe = __repipe; | 362 | repipe = __repipe; |
365 | input_fd = fd; | 363 | input_fd = fd; |
366 | 364 | ||
@@ -390,12 +388,17 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) | |||
390 | file_bigendian = buf[0]; | 388 | file_bigendian = buf[0]; |
391 | host_bigendian = bigendian(); | 389 | host_bigendian = bigendian(); |
392 | 390 | ||
393 | pevent = read_trace_init(file_bigendian, host_bigendian); | 391 | if (trace_event__init(tevent)) { |
394 | if (pevent == NULL) { | 392 | pr_debug("trace_event__init failed"); |
395 | pr_debug("read_trace_init failed"); | ||
396 | goto out; | 393 | goto out; |
397 | } | 394 | } |
398 | 395 | ||
396 | pevent = tevent->pevent; | ||
397 | |||
398 | pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); | ||
399 | pevent_set_file_bigendian(pevent, file_bigendian); | ||
400 | pevent_set_host_bigendian(pevent, host_bigendian); | ||
401 | |||
399 | if (do_read(buf, 1) < 0) | 402 | if (do_read(buf, 1) < 0) |
400 | goto out; | 403 | goto out; |
401 | file_long_size = buf[0]; | 404 | file_long_size = buf[0]; |
@@ -432,11 +435,10 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) | |||
432 | pevent_print_printk(pevent); | 435 | pevent_print_printk(pevent); |
433 | } | 436 | } |
434 | 437 | ||
435 | *ppevent = pevent; | ||
436 | pevent = NULL; | 438 | pevent = NULL; |
437 | 439 | ||
438 | out: | 440 | out: |
439 | if (pevent) | 441 | if (pevent) |
440 | pevent_free(pevent); | 442 | trace_event__cleanup(tevent); |
441 | return size; | 443 | return size; |
442 | } | 444 | } |
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index 95199e4eea97..57aaccc1692e 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c | |||
@@ -38,9 +38,8 @@ static int stop_script_unsupported(void) | |||
38 | static void process_event_unsupported(union perf_event *event __maybe_unused, | 38 | static void process_event_unsupported(union perf_event *event __maybe_unused, |
39 | struct perf_sample *sample __maybe_unused, | 39 | struct perf_sample *sample __maybe_unused, |
40 | struct perf_evsel *evsel __maybe_unused, | 40 | struct perf_evsel *evsel __maybe_unused, |
41 | struct machine *machine __maybe_unused, | ||
42 | struct thread *thread __maybe_unused, | 41 | struct thread *thread __maybe_unused, |
43 | struct addr_location *al __maybe_unused) | 42 | struct addr_location *al __maybe_unused) |
44 | { | 43 | { |
45 | } | 44 | } |
46 | 45 | ||
diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c new file mode 100644 index 000000000000..6322d37164c5 --- /dev/null +++ b/tools/perf/util/trace-event.c | |||
@@ -0,0 +1,82 @@ | |||
1 | |||
2 | #include <stdio.h> | ||
3 | #include <unistd.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <errno.h> | ||
6 | #include <sys/types.h> | ||
7 | #include <sys/stat.h> | ||
8 | #include <fcntl.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <traceevent/event-parse.h> | ||
11 | #include "trace-event.h" | ||
12 | #include "util.h" | ||
13 | |||
14 | /* | ||
15 | * global trace_event object used by trace_event__tp_format | ||
16 | * | ||
17 | * TODO There's no cleanup call for this. Add some sort of | ||
18 | * __exit function support and call trace_event__cleanup | ||
19 | * there. | ||
20 | */ | ||
21 | static struct trace_event tevent; | ||
22 | |||
23 | int trace_event__init(struct trace_event *t) | ||
24 | { | ||
25 | struct pevent *pevent = pevent_alloc(); | ||
26 | |||
27 | if (pevent) { | ||
28 | t->plugin_list = traceevent_load_plugins(pevent); | ||
29 | t->pevent = pevent; | ||
30 | } | ||
31 | |||
32 | return pevent ? 0 : -1; | ||
33 | } | ||
34 | |||
35 | void trace_event__cleanup(struct trace_event *t) | ||
36 | { | ||
37 | traceevent_unload_plugins(t->plugin_list, t->pevent); | ||
38 | pevent_free(t->pevent); | ||
39 | } | ||
40 | |||
41 | static struct event_format* | ||
42 | tp_format(const char *sys, const char *name) | ||
43 | { | ||
44 | struct pevent *pevent = tevent.pevent; | ||
45 | struct event_format *event = NULL; | ||
46 | char path[PATH_MAX]; | ||
47 | size_t size; | ||
48 | char *data; | ||
49 | |||
50 | scnprintf(path, PATH_MAX, "%s/%s/%s/format", | ||
51 | tracing_events_path, sys, name); | ||
52 | |||
53 | if (filename__read_str(path, &data, &size)) | ||
54 | return NULL; | ||
55 | |||
56 | pevent_parse_format(pevent, &event, data, size, sys); | ||
57 | |||
58 | free(data); | ||
59 | return event; | ||
60 | } | ||
61 | |||
62 | struct event_format* | ||
63 | trace_event__tp_format(const char *sys, const char *name) | ||
64 | { | ||
65 | static bool initialized; | ||
66 | |||
67 | if (!initialized) { | ||
68 | int be = traceevent_host_bigendian(); | ||
69 | struct pevent *pevent; | ||
70 | |||
71 | if (trace_event__init(&tevent)) | ||
72 | return NULL; | ||
73 | |||
74 | pevent = tevent.pevent; | ||
75 | pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); | ||
76 | pevent_set_file_bigendian(pevent, be); | ||
77 | pevent_set_host_bigendian(pevent, be); | ||
78 | initialized = true; | ||
79 | } | ||
80 | |||
81 | return tp_format(sys, name); | ||
82 | } | ||
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 04df63114109..7b6d68688327 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h | |||
@@ -3,17 +3,26 @@ | |||
3 | 3 | ||
4 | #include <traceevent/event-parse.h> | 4 | #include <traceevent/event-parse.h> |
5 | #include "parse-events.h" | 5 | #include "parse-events.h" |
6 | #include "session.h" | ||
7 | 6 | ||
8 | struct machine; | 7 | struct machine; |
9 | struct perf_sample; | 8 | struct perf_sample; |
10 | union perf_event; | 9 | union perf_event; |
11 | struct perf_tool; | 10 | struct perf_tool; |
12 | struct thread; | 11 | struct thread; |
12 | struct plugin_list; | ||
13 | |||
14 | struct trace_event { | ||
15 | struct pevent *pevent; | ||
16 | struct plugin_list *plugin_list; | ||
17 | }; | ||
18 | |||
19 | int trace_event__init(struct trace_event *t); | ||
20 | void trace_event__cleanup(struct trace_event *t); | ||
21 | struct event_format* | ||
22 | trace_event__tp_format(const char *sys, const char *name); | ||
13 | 23 | ||
14 | int bigendian(void); | 24 | int bigendian(void); |
15 | 25 | ||
16 | struct pevent *read_trace_init(int file_bigendian, int host_bigendian); | ||
17 | void event_format__print(struct event_format *event, | 26 | void event_format__print(struct event_format *event, |
18 | int cpu, void *data, int size); | 27 | int cpu, void *data, int size); |
19 | 28 | ||
@@ -27,7 +36,7 @@ raw_field_value(struct event_format *event, const char *name, void *data); | |||
27 | void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); | 36 | void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); |
28 | void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); | 37 | void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); |
29 | 38 | ||
30 | ssize_t trace_report(int fd, struct pevent **pevent, bool repipe); | 39 | ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe); |
31 | 40 | ||
32 | struct event_format *trace_find_next_event(struct pevent *pevent, | 41 | struct event_format *trace_find_next_event(struct pevent *pevent, |
33 | struct event_format *event); | 42 | struct event_format *event); |
@@ -59,7 +68,6 @@ struct scripting_ops { | |||
59 | void (*process_event) (union perf_event *event, | 68 | void (*process_event) (union perf_event *event, |
60 | struct perf_sample *sample, | 69 | struct perf_sample *sample, |
61 | struct perf_evsel *evsel, | 70 | struct perf_evsel *evsel, |
62 | struct machine *machine, | ||
63 | struct thread *thread, | 71 | struct thread *thread, |
64 | struct addr_location *al); | 72 | struct addr_location *al); |
65 | int (*generate_script) (struct pevent *pevent, const char *outfile); | 73 | int (*generate_script) (struct pevent *pevent, const char *outfile); |
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c index 0efd5393de85..742f23bf35ff 100644 --- a/tools/perf/util/unwind.c +++ b/tools/perf/util/unwind.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "session.h" | 28 | #include "session.h" |
29 | #include "perf_regs.h" | 29 | #include "perf_regs.h" |
30 | #include "unwind.h" | 30 | #include "unwind.h" |
31 | #include "symbol.h" | ||
31 | #include "util.h" | 32 | #include "util.h" |
32 | 33 | ||
33 | extern int | 34 | extern int |
@@ -158,23 +159,6 @@ static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, | |||
158 | __v; \ | 159 | __v; \ |
159 | }) | 160 | }) |
160 | 161 | ||
161 | static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | ||
162 | GElf_Shdr *shp, const char *name) | ||
163 | { | ||
164 | Elf_Scn *sec = NULL; | ||
165 | |||
166 | while ((sec = elf_nextscn(elf, sec)) != NULL) { | ||
167 | char *str; | ||
168 | |||
169 | gelf_getshdr(sec, shp); | ||
170 | str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); | ||
171 | if (!strcmp(name, str)) | ||
172 | break; | ||
173 | } | ||
174 | |||
175 | return sec; | ||
176 | } | ||
177 | |||
178 | static u64 elf_section_offset(int fd, const char *name) | 162 | static u64 elf_section_offset(int fd, const char *name) |
179 | { | 163 | { |
180 | Elf *elf; | 164 | Elf *elf; |
@@ -190,7 +174,7 @@ static u64 elf_section_offset(int fd, const char *name) | |||
190 | if (gelf_getehdr(elf, &ehdr) == NULL) | 174 | if (gelf_getehdr(elf, &ehdr) == NULL) |
191 | break; | 175 | break; |
192 | 176 | ||
193 | if (!elf_section_by_name(elf, &ehdr, &shdr, name)) | 177 | if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL)) |
194 | break; | 178 | break; |
195 | 179 | ||
196 | offset = shdr.sh_offset; | 180 | offset = shdr.sh_offset; |
@@ -340,10 +324,10 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, | |||
340 | /* Check the .debug_frame section for unwinding info */ | 324 | /* Check the .debug_frame section for unwinding info */ |
341 | if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { | 325 | if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { |
342 | memset(&di, 0, sizeof(di)); | 326 | memset(&di, 0, sizeof(di)); |
343 | dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name, | 327 | if (dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name, |
344 | map->start, map->end); | 328 | map->start, map->end)) |
345 | return dwarf_search_unwind_table(as, ip, &di, pi, | 329 | return dwarf_search_unwind_table(as, ip, &di, pi, |
346 | need_unwind_info, arg); | 330 | need_unwind_info, arg); |
347 | } | 331 | } |
348 | #endif | 332 | #endif |
349 | 333 | ||
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 28a0a89c1f73..42ad667bb317 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -1,11 +1,17 @@ | |||
1 | #include "../perf.h" | 1 | #include "../perf.h" |
2 | #include "util.h" | 2 | #include "util.h" |
3 | #include "fs.h" | ||
3 | #include <sys/mman.h> | 4 | #include <sys/mman.h> |
4 | #ifdef HAVE_BACKTRACE_SUPPORT | 5 | #ifdef HAVE_BACKTRACE_SUPPORT |
5 | #include <execinfo.h> | 6 | #include <execinfo.h> |
6 | #endif | 7 | #endif |
7 | #include <stdio.h> | 8 | #include <stdio.h> |
8 | #include <stdlib.h> | 9 | #include <stdlib.h> |
10 | #include <string.h> | ||
11 | #include <errno.h> | ||
12 | #include <limits.h> | ||
13 | #include <byteswap.h> | ||
14 | #include <linux/kernel.h> | ||
9 | 15 | ||
10 | /* | 16 | /* |
11 | * XXX We need to find a better place for these things... | 17 | * XXX We need to find a better place for these things... |
@@ -151,21 +157,40 @@ unsigned long convert_unit(unsigned long value, char *unit) | |||
151 | return value; | 157 | return value; |
152 | } | 158 | } |
153 | 159 | ||
154 | int readn(int fd, void *buf, size_t n) | 160 | static ssize_t ion(bool is_read, int fd, void *buf, size_t n) |
155 | { | 161 | { |
156 | void *buf_start = buf; | 162 | void *buf_start = buf; |
163 | size_t left = n; | ||
157 | 164 | ||
158 | while (n) { | 165 | while (left) { |
159 | int ret = read(fd, buf, n); | 166 | ssize_t ret = is_read ? read(fd, buf, left) : |
167 | write(fd, buf, left); | ||
160 | 168 | ||
161 | if (ret <= 0) | 169 | if (ret <= 0) |
162 | return ret; | 170 | return ret; |
163 | 171 | ||
164 | n -= ret; | 172 | left -= ret; |
165 | buf += ret; | 173 | buf += ret; |
166 | } | 174 | } |
167 | 175 | ||
168 | return buf - buf_start; | 176 | BUG_ON((size_t)(buf - buf_start) != n); |
177 | return n; | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * Read exactly 'n' bytes or return an error. | ||
182 | */ | ||
183 | ssize_t readn(int fd, void *buf, size_t n) | ||
184 | { | ||
185 | return ion(true, fd, buf, n); | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | * Write exactly 'n' bytes or return an error. | ||
190 | */ | ||
191 | ssize_t writen(int fd, void *buf, size_t n) | ||
192 | { | ||
193 | return ion(false, fd, buf, n); | ||
169 | } | 194 | } |
170 | 195 | ||
171 | size_t hex_width(u64 v) | 196 | size_t hex_width(u64 v) |
@@ -413,3 +438,102 @@ int filename__read_int(const char *filename, int *value) | |||
413 | close(fd); | 438 | close(fd); |
414 | return err; | 439 | return err; |
415 | } | 440 | } |
441 | |||
442 | int filename__read_str(const char *filename, char **buf, size_t *sizep) | ||
443 | { | ||
444 | size_t size = 0, alloc_size = 0; | ||
445 | void *bf = NULL, *nbf; | ||
446 | int fd, n, err = 0; | ||
447 | |||
448 | fd = open(filename, O_RDONLY); | ||
449 | if (fd < 0) | ||
450 | return -errno; | ||
451 | |||
452 | do { | ||
453 | if (size == alloc_size) { | ||
454 | alloc_size += BUFSIZ; | ||
455 | nbf = realloc(bf, alloc_size); | ||
456 | if (!nbf) { | ||
457 | err = -ENOMEM; | ||
458 | break; | ||
459 | } | ||
460 | |||
461 | bf = nbf; | ||
462 | } | ||
463 | |||
464 | n = read(fd, bf + size, alloc_size - size); | ||
465 | if (n < 0) { | ||
466 | if (size) { | ||
467 | pr_warning("read failed %d: %s\n", | ||
468 | errno, strerror(errno)); | ||
469 | err = 0; | ||
470 | } else | ||
471 | err = -errno; | ||
472 | |||
473 | break; | ||
474 | } | ||
475 | |||
476 | size += n; | ||
477 | } while (n > 0); | ||
478 | |||
479 | if (!err) { | ||
480 | *sizep = size; | ||
481 | *buf = bf; | ||
482 | } else | ||
483 | free(bf); | ||
484 | |||
485 | close(fd); | ||
486 | return err; | ||
487 | } | ||
488 | |||
489 | const char *get_filename_for_perf_kvm(void) | ||
490 | { | ||
491 | const char *filename; | ||
492 | |||
493 | if (perf_host && !perf_guest) | ||
494 | filename = strdup("perf.data.host"); | ||
495 | else if (!perf_host && perf_guest) | ||
496 | filename = strdup("perf.data.guest"); | ||
497 | else | ||
498 | filename = strdup("perf.data.kvm"); | ||
499 | |||
500 | return filename; | ||
501 | } | ||
502 | |||
503 | int perf_event_paranoid(void) | ||
504 | { | ||
505 | char path[PATH_MAX]; | ||
506 | const char *procfs = procfs__mountpoint(); | ||
507 | int value; | ||
508 | |||
509 | if (!procfs) | ||
510 | return INT_MAX; | ||
511 | |||
512 | scnprintf(path, PATH_MAX, "%s/sys/kernel/perf_event_paranoid", procfs); | ||
513 | |||
514 | if (filename__read_int(path, &value)) | ||
515 | return INT_MAX; | ||
516 | |||
517 | return value; | ||
518 | } | ||
519 | |||
520 | void mem_bswap_32(void *src, int byte_size) | ||
521 | { | ||
522 | u32 *m = src; | ||
523 | while (byte_size > 0) { | ||
524 | *m = bswap_32(*m); | ||
525 | byte_size -= sizeof(u32); | ||
526 | ++m; | ||
527 | } | ||
528 | } | ||
529 | |||
530 | void mem_bswap_64(void *src, int byte_size) | ||
531 | { | ||
532 | u64 *m = src; | ||
533 | |||
534 | while (byte_size > 0) { | ||
535 | *m = bswap_64(*m); | ||
536 | byte_size -= sizeof(u64); | ||
537 | ++m; | ||
538 | } | ||
539 | } | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index c8f362daba87..6995d66f225c 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -71,8 +71,9 @@ | |||
71 | #include <linux/magic.h> | 71 | #include <linux/magic.h> |
72 | #include "types.h" | 72 | #include "types.h" |
73 | #include <sys/ttydefaults.h> | 73 | #include <sys/ttydefaults.h> |
74 | #include <lk/debugfs.h> | 74 | #include <api/fs/debugfs.h> |
75 | #include <termios.h> | 75 | #include <termios.h> |
76 | #include <linux/bitops.h> | ||
76 | 77 | ||
77 | extern const char *graph_line; | 78 | extern const char *graph_line; |
78 | extern const char *graph_dotted_line; | 79 | extern const char *graph_dotted_line; |
@@ -185,6 +186,8 @@ static inline void *zalloc(size_t size) | |||
185 | return calloc(1, size); | 186 | return calloc(1, size); |
186 | } | 187 | } |
187 | 188 | ||
189 | #define zfree(ptr) ({ free(*ptr); *ptr = NULL; }) | ||
190 | |||
188 | static inline int has_extension(const char *filename, const char *ext) | 191 | static inline int has_extension(const char *filename, const char *ext) |
189 | { | 192 | { |
190 | size_t len = strlen(filename); | 193 | size_t len = strlen(filename); |
@@ -253,7 +256,8 @@ bool strlazymatch(const char *str, const char *pat); | |||
253 | int strtailcmp(const char *s1, const char *s2); | 256 | int strtailcmp(const char *s1, const char *s2); |
254 | char *strxfrchar(char *s, char from, char to); | 257 | char *strxfrchar(char *s, char from, char to); |
255 | unsigned long convert_unit(unsigned long value, char *unit); | 258 | unsigned long convert_unit(unsigned long value, char *unit); |
256 | int readn(int fd, void *buf, size_t size); | 259 | ssize_t readn(int fd, void *buf, size_t n); |
260 | ssize_t writen(int fd, void *buf, size_t n); | ||
257 | 261 | ||
258 | struct perf_event_attr; | 262 | struct perf_event_attr; |
259 | 263 | ||
@@ -280,6 +284,17 @@ static inline unsigned next_pow2(unsigned x) | |||
280 | return 1ULL << (32 - __builtin_clz(x - 1)); | 284 | return 1ULL << (32 - __builtin_clz(x - 1)); |
281 | } | 285 | } |
282 | 286 | ||
287 | static inline unsigned long next_pow2_l(unsigned long x) | ||
288 | { | ||
289 | #if BITS_PER_LONG == 64 | ||
290 | if (x <= (1UL << 31)) | ||
291 | return next_pow2(x); | ||
292 | return (unsigned long)next_pow2(x >> 32) << 32; | ||
293 | #else | ||
294 | return next_pow2(x); | ||
295 | #endif | ||
296 | } | ||
297 | |||
283 | size_t hex_width(u64 v); | 298 | size_t hex_width(u64 v); |
284 | int hex2u64(const char *ptr, u64 *val); | 299 | int hex2u64(const char *ptr, u64 *val); |
285 | 300 | ||
@@ -307,4 +322,11 @@ char *get_srcline(struct dso *dso, unsigned long addr); | |||
307 | void free_srcline(char *srcline); | 322 | void free_srcline(char *srcline); |
308 | 323 | ||
309 | int filename__read_int(const char *filename, int *value); | 324 | int filename__read_int(const char *filename, int *value); |
325 | int filename__read_str(const char *filename, char **buf, size_t *sizep); | ||
326 | int perf_event_paranoid(void); | ||
327 | |||
328 | void mem_bswap_64(void *src, int byte_size); | ||
329 | void mem_bswap_32(void *src, int byte_size); | ||
330 | |||
331 | const char *get_filename_for_perf_kvm(void); | ||
310 | #endif /* GIT_COMPAT_UTIL_H */ | 332 | #endif /* GIT_COMPAT_UTIL_H */ |
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c index 697c8b4e59cc..0fb3c1fcd3e6 100644 --- a/tools/perf/util/values.c +++ b/tools/perf/util/values.c | |||
@@ -31,14 +31,14 @@ void perf_read_values_destroy(struct perf_read_values *values) | |||
31 | return; | 31 | return; |
32 | 32 | ||
33 | for (i = 0; i < values->threads; i++) | 33 | for (i = 0; i < values->threads; i++) |
34 | free(values->value[i]); | 34 | zfree(&values->value[i]); |
35 | free(values->value); | 35 | zfree(&values->value); |
36 | free(values->pid); | 36 | zfree(&values->pid); |
37 | free(values->tid); | 37 | zfree(&values->tid); |
38 | free(values->counterrawid); | 38 | zfree(&values->counterrawid); |
39 | for (i = 0; i < values->counters; i++) | 39 | for (i = 0; i < values->counters; i++) |
40 | free(values->countername[i]); | 40 | zfree(&values->countername[i]); |
41 | free(values->countername); | 41 | zfree(&values->countername); |
42 | } | 42 | } |
43 | 43 | ||
44 | static void perf_read_values__enlarge_threads(struct perf_read_values *values) | 44 | static void perf_read_values__enlarge_threads(struct perf_read_values *values) |
diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index 39159822d58f..0ddb3b8a89ec 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c | |||
@@ -103,7 +103,7 @@ struct dso *vdso__dso_findnew(struct list_head *head) | |||
103 | dso = dso__new(VDSO__MAP_NAME); | 103 | dso = dso__new(VDSO__MAP_NAME); |
104 | if (dso != NULL) { | 104 | if (dso != NULL) { |
105 | dsos__add(head, dso); | 105 | dsos__add(head, dso); |
106 | dso__set_long_name(dso, file); | 106 | dso__set_long_name(dso, file, false); |
107 | } | 107 | } |
108 | } | 108 | } |
109 | 109 | ||