Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'perf-core-for-mingo-2' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

User visible changes:

- List perf probes to stdout. (Masami Hiramatsu)

- Return error when none of the requested probes were
installed. (Masami Hiramatsu)

- Cut off the gcc optimization postfixes from
function name in 'perf probe'. (Masami Hiramatsu)

- Allow disabling/enabling events dynamicly in 'perf top':
a 'perf top' session can instantly become a 'perf report'
one, i.e. going from dynamic analysis to a static one,
returning to a dynamic one is possible, to toogle the
modes, just press CTRL+z. (Arnaldo Carvalho de Melo)

- Greatly speed up 'perf probe --list' by caching debuginfo.
(Masami Hiramatsu)

- Fix 'perf trace' race condition at the end of started
workloads. (Sukadev Bhattiprolu)

- Fix a problem when opening old perf.data with different
byte order. (Wang Nan)

Infrastructure changes:

- Replace map->referenced & maps->removed_maps with
map->refcnt. (Arnaldo Carvalho de Melo)

- Introduce the xyarray__reset() function. (Jiri Olsa)

- Add thread_map__(alloc|realloc)() helpers. (Jiri Olsa)

- Move perf_evsel__(alloc|free|reset)_counts into stat object. (Jiri Olsa)

- Introduce perf_counts__(new|delete|reset)() functions. (Jiri Olsa)

- Ignore .config-detected in .gitignore. (Wang Nan)

- Move libtraceevent dynamic list to separated LDFLAGS
variable. (Wang Nan)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>

+377 -222
+1
tools/perf/.gitignore
··· 28 28 *-flex.* 29 29 *.pyc 30 30 *.pyo 31 + .config-detected
+6 -4
tools/perf/Makefile.perf
··· 174 174 export LIBTRACEEVENT 175 175 176 176 LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)libtraceevent-dynamic-list 177 - LDFLAGS += -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYNAMIC_LIST) 177 + LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS = -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYNAMIC_LIST) 178 178 179 179 LIBAPI = $(LIB_PATH)libapi.a 180 180 export LIBAPI ··· 190 190 PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) 191 191 PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBAPI) 192 192 193 - $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) 194 - $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \ 193 + $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) $(LIBTRACEEVENT_DYNAMIC_LIST) 194 + $(QUIET_GEN)CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS)' \ 195 + $(PYTHON_WORD) util/setup.py \ 195 196 --quiet build_ext; \ 196 197 mkdir -p $(OUTPUT)python && \ 197 198 cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/ ··· 283 282 $(Q)$(MAKE) $(build)=perf 284 283 285 284 $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) 286 - $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(PERF_IN) $(LIBS) -o $@ 285 + $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS) \ 286 + $(PERF_IN) $(LIBS) -o $@ 287 287 288 288 $(GTK_IN): FORCE 289 289 $(Q)$(MAKE) $(build)=gtk
+7 -12
tools/perf/builtin-stat.c
··· 178 178 179 179 static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel) 180 180 { 181 - void *addr; 182 - size_t sz; 181 + struct perf_counts *counts; 183 182 184 - sz = sizeof(*evsel->counts) + 185 - (perf_evsel__nr_cpus(evsel) * sizeof(struct perf_counts_values)); 183 + counts = perf_counts__new(perf_evsel__nr_cpus(evsel)); 184 + if (counts) 185 + evsel->prev_raw_counts = counts; 186 186 187 - addr = zalloc(sz); 188 - if (!addr) 189 - return -ENOMEM; 190 - 191 - evsel->prev_raw_counts = addr; 192 - 193 - return 0; 187 + return counts ? 0 : -ENOMEM; 194 188 } 195 189 196 190 static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) 197 191 { 198 - zfree(&evsel->prev_raw_counts); 192 + perf_counts__delete(evsel->prev_raw_counts); 193 + evsel->prev_raw_counts = NULL; 199 194 } 200 195 201 196 static void perf_evlist__free_stats(struct perf_evlist *evlist)
+36 -16
tools/perf/builtin-top.c
··· 235 235 236 236 more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel, 237 237 0, top->sym_pcnt_filter, top->print_entries, 4); 238 - if (top->zero) 239 - symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); 240 - else 241 - symbol__annotate_decay_histogram(symbol, top->sym_evsel->idx); 238 + 239 + if (top->evlist->enabled) { 240 + if (top->zero) 241 + symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); 242 + else 243 + symbol__annotate_decay_histogram(symbol, top->sym_evsel->idx); 244 + } 242 245 if (more != 0) 243 246 printf("%d lines not displayed, maybe increase display entries [e]\n", more); 244 247 out_unlock: ··· 279 276 return; 280 277 } 281 278 282 - if (top->zero) { 283 - hists__delete_entries(hists); 284 - } else { 285 - hists__decay_entries(hists, top->hide_user_symbols, 286 - top->hide_kernel_symbols); 279 + if (top->evlist->enabled) { 280 + if (top->zero) { 281 + hists__delete_entries(hists); 282 + } else { 283 + hists__decay_entries(hists, top->hide_user_symbols, 284 + top->hide_kernel_symbols); 285 + } 287 286 } 288 287 289 288 hists__collapse_resort(hists, NULL); ··· 550 545 551 546 hists = evsel__hists(t->sym_evsel); 552 547 553 - if (t->zero) { 554 - hists__delete_entries(hists); 555 - } else { 556 - hists__decay_entries(hists, t->hide_user_symbols, 557 - t->hide_kernel_symbols); 548 + if (t->evlist->enabled) { 549 + if (t->zero) { 550 + hists__delete_entries(hists); 551 + } else { 552 + hists__decay_entries(hists, t->hide_user_symbols, 553 + t->hide_kernel_symbols); 554 + } 558 555 } 559 556 560 557 hists__collapse_resort(hists, NULL); ··· 586 579 hists->uid_filter_str = top->record_opts.target.uid_str; 587 580 } 588 581 589 - perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, 590 - &top->session->header.env); 582 + while (true) { 583 + int key = perf_evlist__tui_browse_hists(top->evlist, help, &hbt, 584 + top->min_percent, 585 + &top->session->header.env); 586 + 587 + if (key != CTRL('z')) 588 + break; 589 + 590 + perf_evlist__toggle_enable(top->evlist); 591 + /* 592 + * No need to refresh, resort/decay histogram entries 593 + * if we are not collecting samples: 594 + */ 595 + hbt.refresh = top->evlist->enabled ? top->delay_secs : 0; 596 + } 591 597 592 598 done = 1; 593 599 return NULL;
+1
tools/perf/tests/openat-syscall-all-cpus.c
··· 3 3 #include "thread_map.h" 4 4 #include "cpumap.h" 5 5 #include "debug.h" 6 + #include "stat.h" 6 7 7 8 int test__openat_syscall_event_on_all_cpus(void) 8 9 {
+2
tools/perf/ui/browsers/hists.c
··· 1736 1736 "t Zoom into current Thread\n" 1737 1737 "V Verbose (DSO names in callchains, etc)\n" 1738 1738 "z Toggle zeroing of samples\n" 1739 + "CTRL+z Enable/Disable events\n" 1739 1740 "/ Filter symbol by name"; 1740 1741 1741 1742 if (browser == NULL) ··· 1901 1900 /* Fall thru */ 1902 1901 case 'q': 1903 1902 case CTRL('c'): 1903 + case CTRL('z'): 1904 1904 goto out_free_stack; 1905 1905 default: 1906 1906 continue;
+17 -1
tools/perf/util/evlist.c
··· 297 297 PERF_EVENT_IOC_DISABLE, 0); 298 298 } 299 299 } 300 + 301 + evlist->enabled = false; 300 302 } 301 303 302 304 void perf_evlist__enable(struct perf_evlist *evlist) ··· 318 316 PERF_EVENT_IOC_ENABLE, 0); 319 317 } 320 318 } 319 + 320 + evlist->enabled = true; 321 + } 322 + 323 + void perf_evlist__toggle_enable(struct perf_evlist *evlist) 324 + { 325 + (evlist->enabled ? perf_evlist__disable : perf_evlist__enable)(evlist); 321 326 } 322 327 323 328 int perf_evlist__disable_event(struct perf_evlist *evlist, ··· 643 634 union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) 644 635 { 645 636 struct perf_mmap *md = &evlist->mmap[idx]; 646 - u64 head = perf_mmap__read_head(md); 637 + u64 head; 647 638 u64 old = md->prev; 648 639 unsigned char *data = md->base + page_size; 649 640 union perf_event *event = NULL; 650 641 642 + /* 643 + * Check if event was unmapped due to a POLLHUP/POLLERR. 644 + */ 645 + if (!atomic_read(&md->refcnt)) 646 + return NULL; 647 + 648 + head = perf_mmap__read_head(md); 651 649 if (evlist->overwrite) { 652 650 /* 653 651 * If we're further behind than half the buffer, there's a chance
+2
tools/perf/util/evlist.h
··· 41 41 int nr_groups; 42 42 int nr_mmaps; 43 43 bool overwrite; 44 + bool enabled; 44 45 size_t mmap_len; 45 46 int id_pos; 46 47 int is_pos; ··· 140 139 141 140 void perf_evlist__disable(struct perf_evlist *evlist); 142 141 void perf_evlist__enable(struct perf_evlist *evlist); 142 + void perf_evlist__toggle_enable(struct perf_evlist *evlist); 143 143 144 144 int perf_evlist__disable_event(struct perf_evlist *evlist, 145 145 struct perf_evsel *evsel);
+1 -18
tools/perf/util/evsel.c
··· 26 26 #include "perf_regs.h" 27 27 #include "debug.h" 28 28 #include "trace-event.h" 29 + #include "stat.h" 29 30 30 31 static struct { 31 32 bool sample_id_all; ··· 852 851 return 0; 853 852 } 854 853 855 - void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus) 856 - { 857 - memset(evsel->counts, 0, (sizeof(*evsel->counts) + 858 - (ncpus * sizeof(struct perf_counts_values)))); 859 - } 860 - 861 - int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) 862 - { 863 - evsel->counts = zalloc((sizeof(*evsel->counts) + 864 - (ncpus * sizeof(struct perf_counts_values)))); 865 - return evsel->counts != NULL ? 0 : -ENOMEM; 866 - } 867 - 868 854 static void perf_evsel__free_fd(struct perf_evsel *evsel) 869 855 { 870 856 xyarray__delete(evsel->fd); ··· 877 889 close(FD(evsel, cpu, thread)); 878 890 FD(evsel, cpu, thread) = -1; 879 891 } 880 - } 881 - 882 - void perf_evsel__free_counts(struct perf_evsel *evsel) 883 - { 884 - zfree(&evsel->counts); 885 892 } 886 893 887 894 void perf_evsel__exit(struct perf_evsel *evsel)
-3
tools/perf/util/evsel.h
··· 170 170 int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); 171 171 172 172 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 173 - int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 174 - void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus); 175 - void perf_evsel__free_counts(struct perf_evsel *evsel); 176 173 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 177 174 178 175 void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
+22 -15
tools/perf/util/hist.c
··· 313 313 memset(&he->stat, 0, sizeof(he->stat)); 314 314 } 315 315 316 - if (he->ms.map) 317 - he->ms.map->referenced = true; 316 + map__get(he->ms.map); 318 317 319 318 if (he->branch_info) { 320 319 /* ··· 323 324 */ 324 325 he->branch_info = malloc(sizeof(*he->branch_info)); 325 326 if (he->branch_info == NULL) { 327 + map__zput(he->ms.map); 326 328 free(he->stat_acc); 327 329 free(he); 328 330 return NULL; ··· 332 332 memcpy(he->branch_info, template->branch_info, 333 333 sizeof(*he->branch_info)); 334 334 335 - if (he->branch_info->from.map) 336 - he->branch_info->from.map->referenced = true; 337 - if (he->branch_info->to.map) 338 - he->branch_info->to.map->referenced = true; 335 + map__get(he->branch_info->from.map); 336 + map__get(he->branch_info->to.map); 339 337 } 340 338 341 339 if (he->mem_info) { 342 - if (he->mem_info->iaddr.map) 343 - he->mem_info->iaddr.map->referenced = true; 344 - if (he->mem_info->daddr.map) 345 - he->mem_info->daddr.map->referenced = true; 340 + map__get(he->mem_info->iaddr.map); 341 + map__get(he->mem_info->daddr.map); 346 342 } 347 343 348 344 if (symbol_conf.use_callchain) ··· 403 407 * the history counter to increment. 404 408 */ 405 409 if (he->ms.map != entry->ms.map) { 406 - he->ms.map = entry->ms.map; 407 - if (he->ms.map) 408 - he->ms.map->referenced = true; 410 + map__put(he->ms.map); 411 + he->ms.map = map__get(entry->ms.map); 409 412 } 410 413 goto out; 411 414 } ··· 928 933 void hist_entry__delete(struct hist_entry *he) 929 934 { 930 935 thread__zput(he->thread); 931 - zfree(&he->branch_info); 932 - zfree(&he->mem_info); 936 + map__zput(he->ms.map); 937 + 938 + if (he->branch_info) { 939 + map__zput(he->branch_info->from.map); 940 + map__zput(he->branch_info->to.map); 941 + zfree(&he->branch_info); 942 + } 943 + 944 + if (he->mem_info) { 945 + map__zput(he->mem_info->iaddr.map); 946 + map__zput(he->mem_info->daddr.map); 947 + zfree(&he->mem_info); 948 + } 949 + 933 950 zfree(&he->stat_acc); 934 951 free_srcline(he->srcline); 935 952 free_callchain(he->callchain);
+2 -56
tools/perf/util/map.c
··· 137 137 map->unmap_ip = map__unmap_ip; 138 138 RB_CLEAR_NODE(&map->rb_node); 139 139 map->groups = NULL; 140 - map->referenced = false; 141 140 map->erange_warned = false; 142 141 atomic_set(&map->refcnt, 1); 143 142 } ··· 438 439 { 439 440 maps->entries = RB_ROOT; 440 441 pthread_rwlock_init(&maps->lock, NULL); 441 - INIT_LIST_HEAD(&maps->removed_maps); 442 442 } 443 443 444 444 void map_groups__init(struct map_groups *mg, struct machine *machine) ··· 464 466 } 465 467 } 466 468 467 - static void __maps__purge_removed_maps(struct maps *maps) 468 - { 469 - struct map *pos, *n; 470 - 471 - list_for_each_entry_safe(pos, n, &maps->removed_maps, node) { 472 - list_del_init(&pos->node); 473 - map__put(pos); 474 - } 475 - } 476 - 477 469 static void maps__exit(struct maps *maps) 478 470 { 479 471 pthread_rwlock_wrlock(&maps->lock); 480 472 __maps__purge(maps); 481 - __maps__purge_removed_maps(maps); 482 473 pthread_rwlock_unlock(&maps->lock); 483 474 } 484 475 ··· 485 498 486 499 for (i = 0; i < MAP__NR_TYPES; ++i) { 487 500 if (maps__first(&mg->maps[i])) 488 - return false; 489 - if (!list_empty(&mg->maps[i].removed_maps)) 490 501 return false; 491 502 } 492 503 ··· 606 621 return printed += maps__fprintf(&mg->maps[type], fp); 607 622 } 608 623 609 - static size_t map_groups__fprintf_maps(struct map_groups *mg, FILE *fp) 624 + size_t map_groups__fprintf(struct map_groups *mg, FILE *fp) 610 625 { 611 626 size_t printed = 0, i; 612 627 for (i = 0; i < MAP__NR_TYPES; ++i) 613 628 printed += __map_groups__fprintf_maps(mg, i, fp); 614 629 return printed; 615 - } 616 - 617 - static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg, 618 - enum map_type type, FILE *fp) 619 - { 620 - struct map *pos; 621 - size_t printed = 0; 622 - 623 - list_for_each_entry(pos, &mg->maps[type].removed_maps, node) { 624 - printed += fprintf(fp, "Map:"); 625 - printed += map__fprintf(pos, fp); 626 - if (verbose > 1) { 627 - printed += dso__fprintf(pos->dso, type, fp); 628 - printed += fprintf(fp, "--\n"); 629 - } 630 - } 631 - return printed; 632 - } 633 - 634 - static size_t map_groups__fprintf_removed_maps(struct map_groups *mg, 635 - FILE *fp) 636 - { 637 - size_t printed = 0, i; 638 - for (i = 0; i < MAP__NR_TYPES; ++i) 639 - printed += __map_groups__fprintf_removed_maps(mg, i, fp); 640 - return printed; 641 - } 642 - 643 - size_t map_groups__fprintf(struct map_groups *mg, FILE *fp) 644 - { 645 - size_t printed = map_groups__fprintf_maps(mg, fp); 646 - printed += fprintf(fp, "Removed maps:\n"); 647 - return printed + map_groups__fprintf_removed_maps(mg, fp); 648 630 } 649 631 650 632 static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) ··· 671 719 map__fprintf(after, fp); 672 720 } 673 721 put_map: 674 - /* 675 - * If we have references, just move them to a separate list. 676 - */ 677 - if (pos->referenced) 678 - list_add_tail(&pos->node, &maps->removed_maps); 679 - else 680 - map__put(pos); 722 + map__put(pos); 681 723 682 724 if (err) 683 725 goto out;
+8 -2
tools/perf/util/map.h
··· 34 34 u64 start; 35 35 u64 end; 36 36 u8 /* enum map_type */ type; 37 - bool referenced; 38 37 bool erange_warned; 39 38 u32 priv; 40 39 u32 prot; ··· 62 63 struct maps { 63 64 struct rb_root entries; 64 65 pthread_rwlock_t lock; 65 - struct list_head removed_maps; 66 66 }; 67 67 68 68 struct map_groups { ··· 158 160 } 159 161 160 162 void map__put(struct map *map); 163 + 164 + static inline void __map__zput(struct map **map) 165 + { 166 + map__put(*map); 167 + *map = NULL; 168 + } 169 + 170 + #define map__zput(map) __map__zput(&map) 161 171 162 172 int map__overlap(struct map *l, struct map *r); 163 173 size_t map__fprintf(struct map *map, FILE *fp);
+167 -73
tools/perf/util/probe-event.c
··· 246 246 clear_probe_trace_event(tevs + i); 247 247 } 248 248 249 + static bool kprobe_blacklist__listed(unsigned long address); 250 + static bool kprobe_warn_out_range(const char *symbol, unsigned long address) 251 + { 252 + /* Get the address of _etext for checking non-probable text symbol */ 253 + if (kernel_get_symbol_address_by_name("_etext", false) < address) 254 + pr_warning("%s is out of .text, skip it.\n", symbol); 255 + else if (kprobe_blacklist__listed(address)) 256 + pr_warning("%s is blacklisted function, skip it.\n", symbol); 257 + else 258 + return false; 259 + 260 + return true; 261 + } 262 + 249 263 #ifdef HAVE_DWARF_SUPPORT 250 264 251 265 static int kernel_get_module_dso(const char *module, struct dso **pdso) ··· 429 415 return ret; 430 416 } 431 417 418 + /* For caching the last debuginfo */ 419 + static struct debuginfo *debuginfo_cache; 420 + static char *debuginfo_cache_path; 421 + 422 + static struct debuginfo *debuginfo_cache__open(const char *module, bool silent) 423 + { 424 + if ((debuginfo_cache_path && !strcmp(debuginfo_cache_path, module)) || 425 + (!debuginfo_cache_path && !module && debuginfo_cache)) 426 + goto out; 427 + 428 + /* Copy module path */ 429 + free(debuginfo_cache_path); 430 + if (module) { 431 + debuginfo_cache_path = strdup(module); 432 + if (!debuginfo_cache_path) { 433 + debuginfo__delete(debuginfo_cache); 434 + debuginfo_cache = NULL; 435 + goto out; 436 + } 437 + } 438 + 439 + debuginfo_cache = open_debuginfo(module, silent); 440 + if (!debuginfo_cache) 441 + zfree(&debuginfo_cache_path); 442 + out: 443 + return debuginfo_cache; 444 + } 445 + 446 + static void debuginfo_cache__exit(void) 447 + { 448 + debuginfo__delete(debuginfo_cache); 449 + debuginfo_cache = NULL; 450 + zfree(&debuginfo_cache_path); 451 + } 452 + 432 453 433 454 static int get_text_start_address(const char *exec, unsigned long *address) 434 455 { ··· 525 476 pr_debug("try to find information at %" PRIx64 " in %s\n", addr, 526 477 tp->module ? : "kernel"); 527 478 528 - dinfo = open_debuginfo(tp->module, verbose == 0); 529 - if (dinfo) { 479 + dinfo = debuginfo_cache__open(tp->module, verbose == 0); 480 + if (dinfo) 530 481 ret = debuginfo__find_probe_point(dinfo, 531 482 (unsigned long)addr, pp); 532 - debuginfo__delete(dinfo); 533 - } else 483 + else 534 484 ret = -ENOENT; 535 485 536 486 if (ret > 0) { ··· 607 559 bool uprobe) 608 560 { 609 561 struct ref_reloc_sym *reloc_sym; 610 - u64 etext_addr; 611 562 char *tmp; 612 563 int i, skipped = 0; 613 564 ··· 622 575 pr_warning("Relocated base symbol is not found!\n"); 623 576 return -EINVAL; 624 577 } 625 - /* Get the address of _etext for checking non-probable text symbol */ 626 - etext_addr = kernel_get_symbol_address_by_name("_etext", false); 627 578 628 579 for (i = 0; i < ntevs; i++) { 629 - if (tevs[i].point.address && !tevs[i].point.retprobe) { 630 - /* If we found a wrong one, mark it by NULL symbol */ 631 - if (etext_addr < tevs[i].point.address) { 632 - pr_warning("%s+%lu is out of .text, skip it.\n", 633 - tevs[i].point.symbol, tevs[i].point.offset); 634 - tmp = NULL; 635 - skipped++; 636 - } else { 637 - tmp = strdup(reloc_sym->name); 638 - if (!tmp) 639 - return -ENOMEM; 640 - } 641 - /* If we have no realname, use symbol for it */ 642 - if (!tevs[i].point.realname) 643 - tevs[i].point.realname = tevs[i].point.symbol; 644 - else 645 - free(tevs[i].point.symbol); 646 - tevs[i].point.symbol = tmp; 647 - tevs[i].point.offset = tevs[i].point.address - 648 - reloc_sym->unrelocated_addr; 580 + if (!tevs[i].point.address || tevs[i].point.retprobe) 581 + continue; 582 + /* If we found a wrong one, mark it by NULL symbol */ 583 + if (kprobe_warn_out_range(tevs[i].point.symbol, 584 + tevs[i].point.address)) { 585 + tmp = NULL; 586 + skipped++; 587 + } else { 588 + tmp = strdup(reloc_sym->name); 589 + if (!tmp) 590 + return -ENOMEM; 649 591 } 592 + /* If we have no realname, use symbol for it */ 593 + if (!tevs[i].point.realname) 594 + tevs[i].point.realname = tevs[i].point.symbol; 595 + else 596 + free(tevs[i].point.symbol); 597 + tevs[i].point.symbol = tmp; 598 + tevs[i].point.offset = tevs[i].point.address - 599 + reloc_sym->unrelocated_addr; 650 600 } 651 601 return skipped; 652 602 } ··· 963 919 } 964 920 965 921 #else /* !HAVE_DWARF_SUPPORT */ 922 + 923 + static void debuginfo_cache__exit(void) 924 + { 925 + } 966 926 967 927 static int 968 928 find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused, ··· 2174 2126 return NULL; 2175 2127 } 2176 2128 2177 - /* Show an event */ 2178 - static int show_perf_probe_event(struct perf_probe_event *pev, 2179 - const char *module) 2129 + static LIST_HEAD(kprobe_blacklist); 2130 + 2131 + static void kprobe_blacklist__init(void) 2132 + { 2133 + if (!list_empty(&kprobe_blacklist)) 2134 + return; 2135 + 2136 + if (kprobe_blacklist__load(&kprobe_blacklist) < 0) 2137 + pr_debug("No kprobe blacklist support, ignored\n"); 2138 + } 2139 + 2140 + static void kprobe_blacklist__release(void) 2141 + { 2142 + kprobe_blacklist__delete(&kprobe_blacklist); 2143 + } 2144 + 2145 + static bool kprobe_blacklist__listed(unsigned long address) 2146 + { 2147 + return !!kprobe_blacklist__find_by_address(&kprobe_blacklist, address); 2148 + } 2149 + 2150 + static int perf_probe_event__sprintf(const char *group, const char *event, 2151 + struct perf_probe_event *pev, 2152 + const char *module, 2153 + struct strbuf *result) 2180 2154 { 2181 2155 int i, ret; 2182 2156 char buf[128]; ··· 2209 2139 if (!place) 2210 2140 return -EINVAL; 2211 2141 2212 - ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); 2142 + ret = e_snprintf(buf, 128, "%s:%s", group, event); 2213 2143 if (ret < 0) 2214 - return ret; 2144 + goto out; 2215 2145 2216 - pr_info(" %-20s (on %s", buf, place); 2146 + strbuf_addf(result, " %-20s (on %s", buf, place); 2217 2147 if (module) 2218 - pr_info(" in %s", module); 2148 + strbuf_addf(result, " in %s", module); 2219 2149 2220 2150 if (pev->nargs > 0) { 2221 - pr_info(" with"); 2151 + strbuf_addstr(result, " with"); 2222 2152 for (i = 0; i < pev->nargs; i++) { 2223 2153 ret = synthesize_perf_probe_arg(&pev->args[i], 2224 2154 buf, 128); 2225 2155 if (ret < 0) 2226 - break; 2227 - pr_info(" %s", buf); 2156 + goto out; 2157 + strbuf_addf(result, " %s", buf); 2228 2158 } 2229 2159 } 2230 - pr_info(")\n"); 2160 + strbuf_addch(result, ')'); 2161 + out: 2231 2162 free(place); 2163 + return ret; 2164 + } 2165 + 2166 + /* Show an event */ 2167 + static int show_perf_probe_event(const char *group, const char *event, 2168 + struct perf_probe_event *pev, 2169 + const char *module, bool use_stdout) 2170 + { 2171 + struct strbuf buf = STRBUF_INIT; 2172 + int ret; 2173 + 2174 + ret = perf_probe_event__sprintf(group, event, pev, module, &buf); 2175 + if (ret >= 0) { 2176 + if (use_stdout) 2177 + printf("%s\n", buf.buf); 2178 + else 2179 + pr_info("%s\n", buf.buf); 2180 + } 2181 + strbuf_release(&buf); 2182 + 2232 2183 return ret; 2233 2184 } 2234 2185 ··· 2291 2200 goto next; 2292 2201 ret = convert_to_perf_probe_event(&tev, &pev, 2293 2202 is_kprobe); 2294 - if (ret >= 0) 2295 - ret = show_perf_probe_event(&pev, 2296 - tev.point.module); 2203 + if (ret < 0) 2204 + goto next; 2205 + ret = show_perf_probe_event(pev.group, pev.event, 2206 + &pev, tev.point.module, 2207 + true); 2297 2208 } 2298 2209 next: 2299 2210 clear_perf_probe_event(&pev); ··· 2304 2211 break; 2305 2212 } 2306 2213 strlist__delete(rawlist); 2214 + /* Cleanup cached debuginfo if needed */ 2215 + debuginfo_cache__exit(); 2307 2216 2308 2217 return ret; 2309 2218 } ··· 2411 2316 struct strlist *namelist, bool allow_suffix) 2412 2317 { 2413 2318 int i, ret; 2319 + char *p; 2414 2320 2415 2321 if (*base == '.') 2416 2322 base++; ··· 2422 2326 pr_debug("snprintf() failed: %d\n", ret); 2423 2327 return ret; 2424 2328 } 2329 + /* Cut off the postfixes (e.g. .const, .isra)*/ 2330 + p = strchr(buf, '.'); 2331 + if (p && p != buf) 2332 + *p = '\0'; 2425 2333 if (!strlist__has_entry(namelist, buf)) 2426 2334 return 0; 2427 2335 ··· 2481 2381 int i, fd, ret; 2482 2382 struct probe_trace_event *tev = NULL; 2483 2383 char buf[64]; 2484 - const char *event, *group; 2384 + const char *event = NULL, *group = NULL; 2485 2385 struct strlist *namelist; 2486 - LIST_HEAD(blacklist); 2487 - struct kprobe_blacklist_node *node; 2488 2386 bool safename; 2489 2387 2490 2388 if (pev->uprobes) ··· 2502 2404 ret = -ENOMEM; 2503 2405 goto close_out; 2504 2406 } 2505 - /* Get kprobe blacklist if exists */ 2506 - if (!pev->uprobes) { 2507 - ret = kprobe_blacklist__load(&blacklist); 2508 - if (ret < 0) 2509 - pr_debug("No kprobe blacklist support, ignored\n"); 2510 - } 2511 2407 2512 2408 safename = (pev->point.function && !strisglob(pev->point.function)); 2513 2409 ret = 0; 2514 2410 pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":"); 2515 2411 for (i = 0; i < ntevs; i++) { 2516 2412 tev = &tevs[i]; 2517 - /* Skip if the symbol is out of .text (marked previously) */ 2413 + /* Skip if the symbol is out of .text or blacklisted */ 2518 2414 if (!tev->point.symbol) 2519 2415 continue; 2520 - /* Ensure that the address is NOT blacklisted */ 2521 - node = kprobe_blacklist__find_by_address(&blacklist, 2522 - tev->point.address); 2523 - if (node) { 2524 - pr_warning("Warning: Skipped probing on blacklisted function: %s\n", node->symbol); 2525 - continue; 2526 - } 2527 2416 2528 2417 if (pev->event) 2529 2418 event = pev->event; ··· 2543 2458 /* Add added event name to namelist */ 2544 2459 strlist__add(namelist, event); 2545 2460 2546 - /* Trick here - save current event/group */ 2547 - event = pev->event; 2548 - group = pev->group; 2549 - pev->event = tev->event; 2550 - pev->group = tev->group; 2551 - show_perf_probe_event(pev, tev->point.module); 2552 - /* Trick here - restore current event/group */ 2553 - pev->event = (char *)event; 2554 - pev->group = (char *)group; 2461 + /* We use tev's name for showing new events */ 2462 + show_perf_probe_event(tev->group, tev->event, pev, 2463 + tev->point.module, false); 2464 + /* Save the last valid name */ 2465 + event = tev->event; 2466 + group = tev->group; 2555 2467 2556 2468 /* 2557 2469 * Probes after the first probe which comes from same ··· 2562 2480 warn_uprobe_event_compat(tev); 2563 2481 2564 2482 /* Note that it is possible to skip all events because of blacklist */ 2565 - if (ret >= 0 && tev->event) { 2483 + if (ret >= 0 && event) { 2566 2484 /* Show how to use the event. */ 2567 2485 pr_info("\nYou can now use it in all perf tools, such as:\n\n"); 2568 - pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, 2569 - tev->event); 2486 + pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", group, event); 2570 2487 } 2571 2488 2572 - kprobe_blacklist__delete(&blacklist); 2573 2489 strlist__delete(namelist); 2574 2490 close_out: 2575 2491 close(fd); ··· 2617 2537 struct perf_probe_point *pp = &pev->point; 2618 2538 struct probe_trace_point *tp; 2619 2539 int num_matched_functions; 2620 - int ret, i, j; 2540 + int ret, i, j, skipped = 0; 2621 2541 2622 2542 map = get_target_map(pev->target, pev->uprobes); 2623 2543 if (!map) { ··· 2685 2605 } 2686 2606 /* Add one probe point */ 2687 2607 tp->address = map->unmap_ip(map, sym->start) + pp->offset; 2688 - if (reloc_sym) { 2608 + /* If we found a wrong one, mark it by NULL symbol */ 2609 + if (!pev->uprobes && 2610 + kprobe_warn_out_range(sym->name, tp->address)) { 2611 + tp->symbol = NULL; /* Skip it */ 2612 + skipped++; 2613 + } else if (reloc_sym) { 2689 2614 tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out); 2690 2615 tp->offset = tp->address - reloc_sym->addr; 2691 2616 } else { ··· 2725 2640 nomem_out); 2726 2641 } 2727 2642 arch__fix_tev_from_maps(pev, tev, map); 2643 + } 2644 + if (ret == skipped) { 2645 + ret = -ENOENT; 2646 + goto err_out; 2728 2647 } 2729 2648 2730 2649 out: ··· 2800 2711 /* Loop 1: convert all events */ 2801 2712 for (i = 0; i < npevs; i++) { 2802 2713 pkgs[i].pev = &pevs[i]; 2714 + /* Init kprobe blacklist if needed */ 2715 + if (!pkgs[i].pev->uprobes) 2716 + kprobe_blacklist__init(); 2803 2717 /* Convert with or without debuginfo */ 2804 2718 ret = convert_to_probe_trace_events(pkgs[i].pev, 2805 2719 &pkgs[i].tevs); ··· 2810 2718 goto end; 2811 2719 pkgs[i].ntevs = ret; 2812 2720 } 2721 + /* This just release blacklist only if allocated */ 2722 + kprobe_blacklist__release(); 2813 2723 2814 2724 /* Loop 2: add all events */ 2815 2725 for (i = 0; i < npevs; i++) {
+1
tools/perf/util/python-ext-sources
··· 16 16 util/xyarray.c 17 17 util/cgroup.c 18 18 util/rblist.c 19 + util/stat.c 19 20 util/strlist.c 20 21 util/trace-event.c 21 22 ../../lib/rbtree.c
+35 -13
tools/perf/util/session.c
··· 517 517 { 518 518 attr->type = bswap_32(attr->type); 519 519 attr->size = bswap_32(attr->size); 520 - attr->config = bswap_64(attr->config); 521 - attr->sample_period = bswap_64(attr->sample_period); 522 - attr->sample_type = bswap_64(attr->sample_type); 523 - attr->read_format = bswap_64(attr->read_format); 524 - attr->wakeup_events = bswap_32(attr->wakeup_events); 525 - attr->bp_type = bswap_32(attr->bp_type); 526 - attr->bp_addr = bswap_64(attr->bp_addr); 527 - attr->bp_len = bswap_64(attr->bp_len); 528 - attr->branch_sample_type = bswap_64(attr->branch_sample_type); 529 - attr->sample_regs_user = bswap_64(attr->sample_regs_user); 530 - attr->sample_stack_user = bswap_32(attr->sample_stack_user); 531 - attr->aux_watermark = bswap_32(attr->aux_watermark); 532 520 533 - swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64)); 521 + #define bswap_safe(f, n) \ 522 + (attr->size > (offsetof(struct perf_event_attr, f) + \ 523 + sizeof(attr->f) * (n))) 524 + #define bswap_field(f, sz) \ 525 + do { \ 526 + if (bswap_safe(f, 0)) \ 527 + attr->f = bswap_##sz(attr->f); \ 528 + } while(0) 529 + #define bswap_field_32(f) bswap_field(f, 32) 530 + #define bswap_field_64(f) bswap_field(f, 64) 531 + 532 + bswap_field_64(config); 533 + bswap_field_64(sample_period); 534 + bswap_field_64(sample_type); 535 + bswap_field_64(read_format); 536 + bswap_field_32(wakeup_events); 537 + bswap_field_32(bp_type); 538 + bswap_field_64(bp_addr); 539 + bswap_field_64(bp_len); 540 + bswap_field_64(branch_sample_type); 541 + bswap_field_64(sample_regs_user); 542 + bswap_field_32(sample_stack_user); 543 + bswap_field_32(aux_watermark); 544 + 545 + /* 546 + * After read_format are bitfields. Check read_format because 547 + * we are unable to use offsetof on bitfield. 548 + */ 549 + if (bswap_safe(read_format, 1)) 550 + swap_bitfield((u8 *) (&attr->read_format + 1), 551 + sizeof(u64)); 552 + #undef bswap_field_64 553 + #undef bswap_field_32 554 + #undef bswap_field 555 + #undef bswap_safe 534 556 } 535 557 536 558 static void perf_event__hdr_attr_swap(union perf_event *event,
+36
tools/perf/util/stat.c
··· 94 94 } 95 95 } 96 96 } 97 + 98 + struct perf_counts *perf_counts__new(int ncpus) 99 + { 100 + int size = sizeof(struct perf_counts) + 101 + ncpus * sizeof(struct perf_counts_values); 102 + 103 + return zalloc(size); 104 + } 105 + 106 + void perf_counts__delete(struct perf_counts *counts) 107 + { 108 + free(counts); 109 + } 110 + 111 + static void perf_counts__reset(struct perf_counts *counts, int ncpus) 112 + { 113 + memset(counts, 0, (sizeof(*counts) + 114 + (ncpus * sizeof(struct perf_counts_values)))); 115 + } 116 + 117 + void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus) 118 + { 119 + perf_counts__reset(evsel->counts, ncpus); 120 + } 121 + 122 + int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) 123 + { 124 + evsel->counts = perf_counts__new(ncpus); 125 + return evsel->counts != NULL ? 0 : -ENOMEM; 126 + } 127 + 128 + void perf_evsel__free_counts(struct perf_evsel *evsel) 129 + { 130 + perf_counts__delete(evsel->counts); 131 + evsel->counts = NULL; 132 + }
+6
tools/perf/util/stat.h
··· 62 62 void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, 63 63 double avg, int cpu, enum aggr_mode aggr); 64 64 65 + struct perf_counts *perf_counts__new(int ncpus); 66 + void perf_counts__delete(struct perf_counts *counts); 67 + 68 + void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus); 69 + int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 70 + void perf_evsel__free_counts(struct perf_evsel *evsel); 65 71 #endif
+16 -8
tools/perf/util/thread_map.c
··· 20 20 return 1; 21 21 } 22 22 23 + static struct thread_map *thread_map__realloc(struct thread_map *map, int nr) 24 + { 25 + size_t size = sizeof(*map) + sizeof(pid_t) * nr; 26 + 27 + return realloc(map, size); 28 + } 29 + 30 + #define thread_map__alloc(__nr) thread_map__realloc(NULL, __nr) 31 + 23 32 struct thread_map *thread_map__new_by_pid(pid_t pid) 24 33 { 25 34 struct thread_map *threads; ··· 42 33 if (items <= 0) 43 34 return NULL; 44 35 45 - threads = malloc(sizeof(*threads) + sizeof(pid_t) * items); 36 + threads = thread_map__alloc(items); 46 37 if (threads != NULL) { 47 38 for (i = 0; i < items; i++) 48 39 threads->map[i] = atoi(namelist[i]->d_name); ··· 58 49 59 50 struct thread_map *thread_map__new_by_tid(pid_t tid) 60 51 { 61 - struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t)); 52 + struct thread_map *threads = thread_map__alloc(1); 62 53 63 54 if (threads != NULL) { 64 55 threads->map[0] = tid; ··· 74 65 int max_threads = 32, items, i; 75 66 char path[256]; 76 67 struct dirent dirent, *next, **namelist = NULL; 77 - struct thread_map *threads = malloc(sizeof(*threads) + 78 - max_threads * sizeof(pid_t)); 68 + struct thread_map *threads = thread_map__alloc(max_threads); 69 + 79 70 if (threads == NULL) 80 71 goto out; 81 72 ··· 194 185 goto out_free_threads; 195 186 196 187 total_tasks += items; 197 - nt = realloc(threads, (sizeof(*threads) + 198 - sizeof(pid_t) * total_tasks)); 188 + nt = thread_map__realloc(threads, total_tasks); 199 189 if (nt == NULL) 200 190 goto out_free_namelist; 201 191 ··· 224 216 225 217 struct thread_map *thread_map__new_dummy(void) 226 218 { 227 - struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t)); 219 + struct thread_map *threads = thread_map__alloc(1); 228 220 229 221 if (threads != NULL) { 230 222 threads->map[0] = -1; ··· 261 253 continue; 262 254 263 255 ntasks++; 264 - nt = realloc(threads, sizeof(*threads) + sizeof(pid_t) * ntasks); 256 + nt = thread_map__realloc(threads, ntasks); 265 257 266 258 if (nt == NULL) 267 259 goto out_free_threads;
+1 -1
tools/perf/util/unwind-libunwind.c
··· 360 360 unw_word_t base = is_exec ? 0 : map->start; 361 361 362 362 if (fd >= 0) 363 - dso__data_put_fd(dso); 363 + dso__data_put_fd(map->dso); 364 364 365 365 memset(&di, 0, sizeof(di)); 366 366 if (dwarf_find_debug_frame(0, &di, ip, base, map->dso->name,
+8
tools/perf/util/xyarray.c
··· 9 9 if (xy != NULL) { 10 10 xy->entry_size = entry_size; 11 11 xy->row_size = row_size; 12 + xy->entries = xlen * ylen; 12 13 } 13 14 14 15 return xy; 16 + } 17 + 18 + void xyarray__reset(struct xyarray *xy) 19 + { 20 + size_t n = xy->entries * xy->entry_size; 21 + 22 + memset(xy->contents, 0, n); 15 23 } 16 24 17 25 void xyarray__delete(struct xyarray *xy)
+2
tools/perf/util/xyarray.h
··· 6 6 struct xyarray { 7 7 size_t row_size; 8 8 size_t entry_size; 9 + size_t entries; 9 10 char contents[]; 10 11 }; 11 12 12 13 struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size); 13 14 void xyarray__delete(struct xyarray *xy); 15 + void xyarray__reset(struct xyarray *xy); 14 16 15 17 static inline void *xyarray__entry(struct xyarray *xy, int x, int y) 16 18 {