diff options
Diffstat (limited to 'tools/perf')
40 files changed, 743 insertions, 251 deletions
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore index e1d60d780784..cb43289e447f 100644 --- a/tools/perf/.gitignore +++ b/tools/perf/.gitignore | |||
@@ -18,3 +18,5 @@ perf-archive | |||
18 | tags | 18 | tags |
19 | TAGS | 19 | TAGS |
20 | cscope* | 20 | cscope* |
21 | config.mak | ||
22 | config.mak.autogen | ||
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 94a258c96a44..ea531d9d975c 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt | |||
@@ -31,6 +31,10 @@ OPTIONS | |||
31 | --vmlinux=PATH:: | 31 | --vmlinux=PATH:: |
32 | Specify vmlinux path which has debuginfo (Dwarf binary). | 32 | Specify vmlinux path which has debuginfo (Dwarf binary). |
33 | 33 | ||
34 | -s:: | ||
35 | --source=PATH:: | ||
36 | Specify path to kernel source. | ||
37 | |||
34 | -v:: | 38 | -v:: |
35 | --verbose:: | 39 | --verbose:: |
36 | Be more verbose (show parsed arguments, etc). | 40 | Be more verbose (show parsed arguments, etc). |
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 34e255fc3e2f..3ee27dccfde9 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -103,6 +103,19 @@ OPTIONS | |||
103 | --raw-samples:: | 103 | --raw-samples:: |
104 | Collect raw sample records from all opened counters (default for tracepoint counters). | 104 | Collect raw sample records from all opened counters (default for tracepoint counters). |
105 | 105 | ||
106 | -C:: | ||
107 | --cpu:: | ||
108 | Collect samples only on the list of cpus provided. Multiple CPUs can be provided as a | ||
109 | comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. | ||
110 | In per-thread mode with inheritance mode on (default), samples are captured only when | ||
111 | the thread executes on the designated CPUs. Default is to monitor all CPUs. | ||
112 | |||
113 | -N:: | ||
114 | --no-buildid-cache:: | ||
115 | Do not update the builid cache. This saves some overhead in situations | ||
116 | where the information in the perf.data file (which includes buildids) | ||
117 | is sufficient. | ||
118 | |||
106 | SEE ALSO | 119 | SEE ALSO |
107 | -------- | 120 | -------- |
108 | linkperf:perf-stat[1], linkperf:perf-list[1] | 121 | linkperf:perf-stat[1], linkperf:perf-list[1] |
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 909fa766fa1c..4b3a2d46b437 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt | |||
@@ -46,6 +46,13 @@ OPTIONS | |||
46 | -B:: | 46 | -B:: |
47 | print large numbers with thousands' separators according to locale | 47 | print large numbers with thousands' separators according to locale |
48 | 48 | ||
49 | -C:: | ||
50 | --cpu=:: | ||
51 | Count only on the list of cpus provided. Multiple CPUs can be provided as a | ||
52 | comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. | ||
53 | In per-thread mode, this option is ignored. The -a option is still necessary | ||
54 | to activate system-wide monitoring. Default is to count on all CPUs. | ||
55 | |||
49 | EXAMPLES | 56 | EXAMPLES |
50 | -------- | 57 | -------- |
51 | 58 | ||
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 785b9fc32a46..1f9687663f2a 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
@@ -25,9 +25,11 @@ OPTIONS | |||
25 | --count=<count>:: | 25 | --count=<count>:: |
26 | Event period to sample. | 26 | Event period to sample. |
27 | 27 | ||
28 | -C <cpu>:: | 28 | -C <cpu-list>:: |
29 | --CPU=<cpu>:: | 29 | --cpu=<cpu>:: |
30 | CPU to profile. | 30 | Monitor only on the list of cpus provided. Multiple CPUs can be provided as a |
31 | comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. | ||
32 | Default is to monitor all CPUS. | ||
31 | 33 | ||
32 | -d <seconds>:: | 34 | -d <seconds>:: |
33 | --delay=<seconds>:: | 35 | --delay=<seconds>:: |
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST new file mode 100644 index 000000000000..8c7fc0c8f0b8 --- /dev/null +++ b/tools/perf/MANIFEST | |||
@@ -0,0 +1,12 @@ | |||
1 | tools/perf | ||
2 | include/linux/perf_event.h | ||
3 | include/linux/rbtree.h | ||
4 | include/linux/list.h | ||
5 | include/linux/hash.h | ||
6 | include/linux/stringify.h | ||
7 | lib/rbtree.c | ||
8 | include/linux/swab.h | ||
9 | arch/*/include/asm/unistd*.h | ||
10 | include/linux/poison.h | ||
11 | include/linux/magic.h | ||
12 | include/linux/hw_breakpoint.h | ||
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 3d8f31ed771d..17a3692397c5 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -285,14 +285,10 @@ else | |||
285 | QUIET_STDERR = ">/dev/null 2>&1" | 285 | QUIET_STDERR = ">/dev/null 2>&1" |
286 | endif | 286 | endif |
287 | 287 | ||
288 | BITBUCKET = "/dev/null" | 288 | -include feature-tests.mak |
289 | 289 | ||
290 | ifneq ($(shell sh -c "(echo '\#include <stdio.h>'; echo 'int main(void) { return puts(\"hi\"); }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) "$(QUIET_STDERR)" && echo y"), y) | 290 | ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y) |
291 | BITBUCKET = .perf.dev.null | 291 | CFLAGS := $(CFLAGS) -fstack-protector-all |
292 | endif | ||
293 | |||
294 | ifeq ($(shell sh -c "echo 'int foo(void) {char X[2]; return 3;}' | $(CC) -x c -c -Werror -fstack-protector-all - -o $(BITBUCKET) "$(QUIET_STDERR)" && echo y"), y) | ||
295 | CFLAGS := $(CFLAGS) -fstack-protector-all | ||
296 | endif | 292 | endif |
297 | 293 | ||
298 | 294 | ||
@@ -508,7 +504,8 @@ PERFLIBS = $(LIB_FILE) | |||
508 | -include config.mak | 504 | -include config.mak |
509 | 505 | ||
510 | ifndef NO_DWARF | 506 | ifndef NO_DWARF |
511 | ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo '\#include <version.h>'; echo '\#ifndef _ELFUTILS_PREREQ'; echo '\#error'; echo '\#endif'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) | 507 | FLAGS_DWARF=$(ALL_CFLAGS) -I/usr/include/elfutils -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS) |
508 | ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y) | ||
512 | msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); | 509 | msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); |
513 | NO_DWARF := 1 | 510 | NO_DWARF := 1 |
514 | endif # Dwarf support | 511 | endif # Dwarf support |
@@ -536,16 +533,18 @@ ifneq ($(OUTPUT),) | |||
536 | BASIC_CFLAGS += -I$(OUTPUT) | 533 | BASIC_CFLAGS += -I$(OUTPUT) |
537 | endif | 534 | endif |
538 | 535 | ||
539 | ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) | 536 | FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) |
540 | ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) | 537 | ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y) |
541 | msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); | 538 | FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS) |
539 | ifneq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC)),y) | ||
540 | msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); | ||
541 | else | ||
542 | msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel); | ||
543 | endif | ||
542 | endif | 544 | endif |
543 | 545 | ||
544 | ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) | 546 | ifneq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y) |
545 | BASIC_CFLAGS += -DLIBELF_NO_MMAP | 547 | BASIC_CFLAGS += -DLIBELF_NO_MMAP |
546 | endif | ||
547 | else | ||
548 | msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); | ||
549 | endif | 548 | endif |
550 | 549 | ||
551 | ifndef NO_DWARF | 550 | ifndef NO_DWARF |
@@ -561,41 +560,47 @@ endif # NO_DWARF | |||
561 | ifdef NO_NEWT | 560 | ifdef NO_NEWT |
562 | BASIC_CFLAGS += -DNO_NEWT_SUPPORT | 561 | BASIC_CFLAGS += -DNO_NEWT_SUPPORT |
563 | else | 562 | else |
564 | ifneq ($(shell sh -c "(echo '\#include <newt.h>'; echo 'int main(void) { newtInit(); newtCls(); return newtFinished(); }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -lnewt -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) | 563 | FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt |
565 | msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev); | 564 | ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT)),y) |
566 | BASIC_CFLAGS += -DNO_NEWT_SUPPORT | 565 | msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev); |
567 | else | 566 | BASIC_CFLAGS += -DNO_NEWT_SUPPORT |
568 | # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h | 567 | else |
569 | BASIC_CFLAGS += -I/usr/include/slang | 568 | # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h |
570 | EXTLIBS += -lnewt -lslang | 569 | BASIC_CFLAGS += -I/usr/include/slang |
571 | LIB_OBJS += $(OUTPUT)util/newt.o | 570 | EXTLIBS += -lnewt -lslang |
572 | endif | 571 | LIB_OBJS += $(OUTPUT)util/newt.o |
573 | endif # NO_NEWT | 572 | endif |
574 | |||
575 | ifndef NO_LIBPERL | ||
576 | PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null` | ||
577 | PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` | ||
578 | endif | 573 | endif |
579 | 574 | ||
580 | ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o $(BITBUCKET) $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y) | 575 | ifdef NO_LIBPERL |
581 | BASIC_CFLAGS += -DNO_LIBPERL | 576 | BASIC_CFLAGS += -DNO_LIBPERL |
582 | else | 577 | else |
583 | ALL_LDFLAGS += $(PERL_EMBED_LDOPTS) | 578 | PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null` |
584 | LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o | 579 | PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` |
585 | LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o | 580 | FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) |
586 | endif | ||
587 | 581 | ||
588 | ifndef NO_LIBPYTHON | 582 | ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED)),y) |
589 | PYTHON_EMBED_LDOPTS = `python-config --ldflags 2>/dev/null` | 583 | BASIC_CFLAGS += -DNO_LIBPERL |
590 | PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null` | 584 | else |
585 | ALL_LDFLAGS += $(PERL_EMBED_LDOPTS) | ||
586 | LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o | ||
587 | LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o | ||
588 | endif | ||
591 | endif | 589 | endif |
592 | 590 | ||
593 | ifneq ($(shell sh -c "(echo '\#include <Python.h>'; echo 'int main(void) { Py_Initialize(); return 0; }') | $(CC) -x c - $(PYTHON_EMBED_CCOPTS) -o $(BITBUCKET) $(PYTHON_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y) | 591 | ifdef NO_LIBPYTHON |
594 | BASIC_CFLAGS += -DNO_LIBPYTHON | 592 | BASIC_CFLAGS += -DNO_LIBPYTHON |
595 | else | 593 | else |
596 | ALL_LDFLAGS += $(PYTHON_EMBED_LDOPTS) | 594 | PYTHON_EMBED_LDOPTS = `python-config --ldflags 2>/dev/null` |
597 | LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o | 595 | PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null` |
598 | LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o | 596 | FLAGS_PYTHON_EMBED=$(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) |
597 | ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y) | ||
598 | BASIC_CFLAGS += -DNO_LIBPYTHON | ||
599 | else | ||
600 | ALL_LDFLAGS += $(PYTHON_EMBED_LDOPTS) | ||
601 | LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o | ||
602 | LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o | ||
603 | endif | ||
599 | endif | 604 | endif |
600 | 605 | ||
601 | ifdef NO_DEMANGLE | 606 | ifdef NO_DEMANGLE |
@@ -604,20 +609,23 @@ else ifdef HAVE_CPLUS_DEMANGLE | |||
604 | EXTLIBS += -liberty | 609 | EXTLIBS += -liberty |
605 | BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE | 610 | BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE |
606 | else | 611 | else |
607 | has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd "$(QUIET_STDERR)" && echo y") | 612 | FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd |
608 | 613 | has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD)) | |
609 | ifeq ($(has_bfd),y) | 614 | ifeq ($(has_bfd),y) |
610 | EXTLIBS += -lbfd | 615 | EXTLIBS += -lbfd |
611 | else | 616 | else |
612 | has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty "$(QUIET_STDERR)" && echo y") | 617 | FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty |
618 | has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY)) | ||
613 | ifeq ($(has_bfd_iberty),y) | 619 | ifeq ($(has_bfd_iberty),y) |
614 | EXTLIBS += -lbfd -liberty | 620 | EXTLIBS += -lbfd -liberty |
615 | else | 621 | else |
616 | has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty -lz "$(QUIET_STDERR)" && echo y") | 622 | FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz |
623 | has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z)) | ||
617 | ifeq ($(has_bfd_iberty_z),y) | 624 | ifeq ($(has_bfd_iberty_z),y) |
618 | EXTLIBS += -lbfd -liberty -lz | 625 | EXTLIBS += -lbfd -liberty -lz |
619 | else | 626 | else |
620 | has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -liberty "$(QUIET_STDERR)" && echo y") | 627 | FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty |
628 | has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE)) | ||
621 | ifeq ($(has_cplus_demangle),y) | 629 | ifeq ($(has_cplus_demangle),y) |
622 | EXTLIBS += -liberty | 630 | EXTLIBS += -liberty |
623 | BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE | 631 | BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE |
@@ -865,7 +873,7 @@ export TAR INSTALL DESTDIR SHELL_PATH | |||
865 | 873 | ||
866 | SHELL = $(SHELL_PATH) | 874 | SHELL = $(SHELL_PATH) |
867 | 875 | ||
868 | all:: .perf.dev.null shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) $(OUTPUT)PERF-BUILD-OPTIONS | 876 | all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) $(OUTPUT)PERF-BUILD-OPTIONS |
869 | ifneq (,$X) | 877 | ifneq (,$X) |
870 | $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';) | 878 | $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';) |
871 | endif | 879 | endif |
@@ -1195,11 +1203,6 @@ clean: | |||
1195 | .PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS | 1203 | .PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS |
1196 | .PHONY: .FORCE-PERF-BUILD-OPTIONS | 1204 | .PHONY: .FORCE-PERF-BUILD-OPTIONS |
1197 | 1205 | ||
1198 | .perf.dev.null: | ||
1199 | touch .perf.dev.null | ||
1200 | |||
1201 | .INTERMEDIATE: .perf.dev.null | ||
1202 | |||
1203 | ### Make sure built-ins do not have dups and listed in perf.c | 1206 | ### Make sure built-ins do not have dups and listed in perf.c |
1204 | # | 1207 | # |
1205 | check-builtins:: | 1208 | check-builtins:: |
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 96db5248e995..fd20670ce986 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -61,11 +61,9 @@ static int hists__add_entry(struct hists *self, struct addr_location *al) | |||
61 | static int process_sample_event(event_t *event, struct perf_session *session) | 61 | static int process_sample_event(event_t *event, struct perf_session *session) |
62 | { | 62 | { |
63 | struct addr_location al; | 63 | struct addr_location al; |
64 | struct sample_data data; | ||
64 | 65 | ||
65 | dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc, | 66 | if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) { |
66 | event->ip.pid, event->ip.ip); | ||
67 | |||
68 | if (event__preprocess_sample(event, session, &al, NULL) < 0) { | ||
69 | pr_warning("problem processing %d event, skipping it.\n", | 67 | pr_warning("problem processing %d event, skipping it.\n", |
70 | event->header.type); | 68 | event->header.type); |
71 | return -1; | 69 | return -1; |
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index f8e3d1852029..29ad20e67919 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c | |||
@@ -78,8 +78,7 @@ static int __cmd_buildid_cache(void) | |||
78 | struct str_node *pos; | 78 | struct str_node *pos; |
79 | char debugdir[PATH_MAX]; | 79 | char debugdir[PATH_MAX]; |
80 | 80 | ||
81 | snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"), | 81 | snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir); |
82 | DEBUG_CACHE_DIR); | ||
83 | 82 | ||
84 | if (add_name_list_str) { | 83 | if (add_name_list_str) { |
85 | list = strlist__new(true, add_name_list_str); | 84 | list = strlist__new(true, add_name_list_str); |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index a6e2fdc7a04e..39e6627ebb96 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -35,10 +35,7 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi | |||
35 | struct addr_location al; | 35 | struct addr_location al; |
36 | struct sample_data data = { .period = 1, }; | 36 | struct sample_data data = { .period = 1, }; |
37 | 37 | ||
38 | dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc, | 38 | if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) { |
39 | event->ip.pid, event->ip.ip); | ||
40 | |||
41 | if (event__preprocess_sample(event, session, &al, NULL) < 0) { | ||
42 | pr_warning("problem processing %d event, skipping it.\n", | 39 | pr_warning("problem processing %d event, skipping it.\n", |
43 | event->header.type); | 40 | event->header.type); |
44 | return -1; | 41 | return -1; |
@@ -47,8 +44,6 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi | |||
47 | if (al.filtered || al.sym == NULL) | 44 | if (al.filtered || al.sym == NULL) |
48 | return 0; | 45 | return 0; |
49 | 46 | ||
50 | event__parse_sample(event, session->sample_type, &data); | ||
51 | |||
52 | if (hists__add_entry(&session->hists, &al, data.period)) { | 47 | if (hists__add_entry(&session->hists, &al, data.period)) { |
53 | pr_warning("problem incrementing symbol period, skipping event\n"); | 48 | pr_warning("problem incrementing symbol period, skipping event\n"); |
54 | return -1; | 49 | return -1; |
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index e4a4da32a568..54551867e7e0 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -182,6 +182,8 @@ static const struct option options[] = { | |||
182 | "Show source code lines.", opt_show_lines), | 182 | "Show source code lines.", opt_show_lines), |
183 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 183 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
184 | "file", "vmlinux pathname"), | 184 | "file", "vmlinux pathname"), |
185 | OPT_STRING('s', "source", &symbol_conf.source_prefix, | ||
186 | "directory", "path to kernel source"), | ||
185 | #endif | 187 | #endif |
186 | OPT__DRY_RUN(&probe_event_dry_run), | 188 | OPT__DRY_RUN(&probe_event_dry_run), |
187 | OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, | 189 | OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 711745f56bba..b93879677cca 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -49,7 +49,6 @@ static int group = 0; | |||
49 | static int realtime_prio = 0; | 49 | static int realtime_prio = 0; |
50 | static bool raw_samples = false; | 50 | static bool raw_samples = false; |
51 | static bool system_wide = false; | 51 | static bool system_wide = false; |
52 | static int profile_cpu = -1; | ||
53 | static pid_t target_pid = -1; | 52 | static pid_t target_pid = -1; |
54 | static pid_t target_tid = -1; | 53 | static pid_t target_tid = -1; |
55 | static pid_t *all_tids = NULL; | 54 | static pid_t *all_tids = NULL; |
@@ -61,6 +60,7 @@ static bool call_graph = false; | |||
61 | static bool inherit_stat = false; | 60 | static bool inherit_stat = false; |
62 | static bool no_samples = false; | 61 | static bool no_samples = false; |
63 | static bool sample_address = false; | 62 | static bool sample_address = false; |
63 | static bool no_buildid = false; | ||
64 | 64 | ||
65 | static long samples = 0; | 65 | static long samples = 0; |
66 | static u64 bytes_written = 0; | 66 | static u64 bytes_written = 0; |
@@ -74,6 +74,7 @@ static int file_new = 1; | |||
74 | static off_t post_processing_offset; | 74 | static off_t post_processing_offset; |
75 | 75 | ||
76 | static struct perf_session *session; | 76 | static struct perf_session *session; |
77 | static const char *cpu_list; | ||
77 | 78 | ||
78 | struct mmap_data { | 79 | struct mmap_data { |
79 | int counter; | 80 | int counter; |
@@ -268,12 +269,17 @@ static void create_counter(int counter, int cpu) | |||
268 | if (inherit_stat) | 269 | if (inherit_stat) |
269 | attr->inherit_stat = 1; | 270 | attr->inherit_stat = 1; |
270 | 271 | ||
271 | if (sample_address) | 272 | if (sample_address) { |
272 | attr->sample_type |= PERF_SAMPLE_ADDR; | 273 | attr->sample_type |= PERF_SAMPLE_ADDR; |
274 | attr->mmap_data = track; | ||
275 | } | ||
273 | 276 | ||
274 | if (call_graph) | 277 | if (call_graph) |
275 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; | 278 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; |
276 | 279 | ||
280 | if (system_wide) | ||
281 | attr->sample_type |= PERF_SAMPLE_CPU; | ||
282 | |||
277 | if (raw_samples) { | 283 | if (raw_samples) { |
278 | attr->sample_type |= PERF_SAMPLE_TIME; | 284 | attr->sample_type |= PERF_SAMPLE_TIME; |
279 | attr->sample_type |= PERF_SAMPLE_RAW; | 285 | attr->sample_type |= PERF_SAMPLE_RAW; |
@@ -300,7 +306,7 @@ try_again: | |||
300 | die("Permission error - are you root?\n" | 306 | die("Permission error - are you root?\n" |
301 | "\t Consider tweaking" | 307 | "\t Consider tweaking" |
302 | " /proc/sys/kernel/perf_event_paranoid.\n"); | 308 | " /proc/sys/kernel/perf_event_paranoid.\n"); |
303 | else if (err == ENODEV && profile_cpu != -1) { | 309 | else if (err == ENODEV && cpu_list) { |
304 | die("No such device - did you specify" | 310 | die("No such device - did you specify" |
305 | " an out-of-range profile CPU?\n"); | 311 | " an out-of-range profile CPU?\n"); |
306 | } | 312 | } |
@@ -439,8 +445,6 @@ static void atexit_header(void) | |||
439 | static void event__synthesize_guest_os(struct machine *machine, void *data) | 445 | static void event__synthesize_guest_os(struct machine *machine, void *data) |
440 | { | 446 | { |
441 | int err; | 447 | int err; |
442 | char *guest_kallsyms; | ||
443 | char path[PATH_MAX]; | ||
444 | struct perf_session *psession = data; | 448 | struct perf_session *psession = data; |
445 | 449 | ||
446 | if (machine__is_host(machine)) | 450 | if (machine__is_host(machine)) |
@@ -460,13 +464,6 @@ static void event__synthesize_guest_os(struct machine *machine, void *data) | |||
460 | pr_err("Couldn't record guest kernel [%d]'s reference" | 464 | pr_err("Couldn't record guest kernel [%d]'s reference" |
461 | " relocation symbol.\n", machine->pid); | 465 | " relocation symbol.\n", machine->pid); |
462 | 466 | ||
463 | if (machine__is_default_guest(machine)) | ||
464 | guest_kallsyms = (char *) symbol_conf.default_guest_kallsyms; | ||
465 | else { | ||
466 | sprintf(path, "%s/proc/kallsyms", machine->root_dir); | ||
467 | guest_kallsyms = path; | ||
468 | } | ||
469 | |||
470 | /* | 467 | /* |
471 | * We use _stext for guest kernel because guest kernel's /proc/kallsyms | 468 | * We use _stext for guest kernel because guest kernel's /proc/kallsyms |
472 | * have no _text sometimes. | 469 | * have no _text sometimes. |
@@ -622,10 +619,15 @@ static int __cmd_record(int argc, const char **argv) | |||
622 | close(child_ready_pipe[0]); | 619 | close(child_ready_pipe[0]); |
623 | } | 620 | } |
624 | 621 | ||
625 | if ((!system_wide && no_inherit) || profile_cpu != -1) { | 622 | nr_cpus = read_cpu_map(cpu_list); |
626 | open_counters(profile_cpu); | 623 | if (nr_cpus < 1) { |
624 | perror("failed to collect number of CPUs\n"); | ||
625 | return -1; | ||
626 | } | ||
627 | |||
628 | if (!system_wide && no_inherit && !cpu_list) { | ||
629 | open_counters(-1); | ||
627 | } else { | 630 | } else { |
628 | nr_cpus = read_cpu_map(); | ||
629 | for (i = 0; i < nr_cpus; i++) | 631 | for (i = 0; i < nr_cpus; i++) |
630 | open_counters(cpumap[i]); | 632 | open_counters(cpumap[i]); |
631 | } | 633 | } |
@@ -704,7 +706,7 @@ static int __cmd_record(int argc, const char **argv) | |||
704 | if (perf_guest) | 706 | if (perf_guest) |
705 | perf_session__process_machines(session, event__synthesize_guest_os); | 707 | perf_session__process_machines(session, event__synthesize_guest_os); |
706 | 708 | ||
707 | if (!system_wide && profile_cpu == -1) | 709 | if (!system_wide) |
708 | event__synthesize_thread(target_tid, process_synthesized_event, | 710 | event__synthesize_thread(target_tid, process_synthesized_event, |
709 | session); | 711 | session); |
710 | else | 712 | else |
@@ -794,8 +796,8 @@ static const struct option options[] = { | |||
794 | "system-wide collection from all CPUs"), | 796 | "system-wide collection from all CPUs"), |
795 | OPT_BOOLEAN('A', "append", &append_file, | 797 | OPT_BOOLEAN('A', "append", &append_file, |
796 | "append to the output file to do incremental profiling"), | 798 | "append to the output file to do incremental profiling"), |
797 | OPT_INTEGER('C', "profile_cpu", &profile_cpu, | 799 | OPT_STRING('C', "cpu", &cpu_list, "cpu", |
798 | "CPU to profile on"), | 800 | "list of cpus to monitor"), |
799 | OPT_BOOLEAN('f', "force", &force, | 801 | OPT_BOOLEAN('f', "force", &force, |
800 | "overwrite existing data file (deprecated)"), | 802 | "overwrite existing data file (deprecated)"), |
801 | OPT_U64('c', "count", &user_interval, "event period to sample"), | 803 | OPT_U64('c', "count", &user_interval, "event period to sample"), |
@@ -815,6 +817,8 @@ static const struct option options[] = { | |||
815 | "Sample addresses"), | 817 | "Sample addresses"), |
816 | OPT_BOOLEAN('n', "no-samples", &no_samples, | 818 | OPT_BOOLEAN('n', "no-samples", &no_samples, |
817 | "don't sample"), | 819 | "don't sample"), |
820 | OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid, | ||
821 | "do not update the buildid cache"), | ||
818 | OPT_END() | 822 | OPT_END() |
819 | }; | 823 | }; |
820 | 824 | ||
@@ -825,7 +829,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
825 | argc = parse_options(argc, argv, options, record_usage, | 829 | argc = parse_options(argc, argv, options, record_usage, |
826 | PARSE_OPT_STOP_AT_NON_OPTION); | 830 | PARSE_OPT_STOP_AT_NON_OPTION); |
827 | if (!argc && target_pid == -1 && target_tid == -1 && | 831 | if (!argc && target_pid == -1 && target_tid == -1 && |
828 | !system_wide && profile_cpu == -1) | 832 | !system_wide && !cpu_list) |
829 | usage_with_options(record_usage, options); | 833 | usage_with_options(record_usage, options); |
830 | 834 | ||
831 | if (force && append_file) { | 835 | if (force && append_file) { |
@@ -839,6 +843,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
839 | } | 843 | } |
840 | 844 | ||
841 | symbol__init(); | 845 | symbol__init(); |
846 | if (no_buildid) | ||
847 | disable_buildid_cache(); | ||
842 | 848 | ||
843 | if (!nr_counters) { | 849 | if (!nr_counters) { |
844 | nr_counters = 1; | 850 | nr_counters = 1; |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 359205782964..371a3c995806 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -155,30 +155,7 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
155 | struct addr_location al; | 155 | struct addr_location al; |
156 | struct perf_event_attr *attr; | 156 | struct perf_event_attr *attr; |
157 | 157 | ||
158 | event__parse_sample(event, session->sample_type, &data); | 158 | if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) { |
159 | |||
160 | dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, | ||
161 | data.pid, data.tid, data.ip, data.period); | ||
162 | |||
163 | if (session->sample_type & PERF_SAMPLE_CALLCHAIN) { | ||
164 | unsigned int i; | ||
165 | |||
166 | dump_printf("... chain: nr:%Lu\n", data.callchain->nr); | ||
167 | |||
168 | if (!ip_callchain__valid(data.callchain, event)) { | ||
169 | pr_debug("call-chain problem with event, " | ||
170 | "skipping it.\n"); | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | if (dump_trace) { | ||
175 | for (i = 0; i < data.callchain->nr; i++) | ||
176 | dump_printf("..... %2d: %016Lx\n", | ||
177 | i, data.callchain->ips[i]); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | if (event__preprocess_sample(event, session, &al, NULL) < 0) { | ||
182 | fprintf(stderr, "problem processing %d event, skipping it.\n", | 159 | fprintf(stderr, "problem processing %d event, skipping it.\n", |
183 | event->header.type); | 160 | event->header.type); |
184 | return -1; | 161 | return -1; |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 9a39ca3c3ac4..a6b4d44f9502 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -69,7 +69,7 @@ static struct perf_event_attr default_attrs[] = { | |||
69 | }; | 69 | }; |
70 | 70 | ||
71 | static bool system_wide = false; | 71 | static bool system_wide = false; |
72 | static unsigned int nr_cpus = 0; | 72 | static int nr_cpus = 0; |
73 | static int run_idx = 0; | 73 | static int run_idx = 0; |
74 | 74 | ||
75 | static int run_count = 1; | 75 | static int run_count = 1; |
@@ -82,6 +82,7 @@ static int thread_num = 0; | |||
82 | static pid_t child_pid = -1; | 82 | static pid_t child_pid = -1; |
83 | static bool null_run = false; | 83 | static bool null_run = false; |
84 | static bool big_num = false; | 84 | static bool big_num = false; |
85 | static const char *cpu_list; | ||
85 | 86 | ||
86 | 87 | ||
87 | static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; | 88 | static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; |
@@ -158,7 +159,7 @@ static int create_perf_stat_counter(int counter) | |||
158 | PERF_FORMAT_TOTAL_TIME_RUNNING; | 159 | PERF_FORMAT_TOTAL_TIME_RUNNING; |
159 | 160 | ||
160 | if (system_wide) { | 161 | if (system_wide) { |
161 | unsigned int cpu; | 162 | int cpu; |
162 | 163 | ||
163 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 164 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
164 | fd[cpu][counter][0] = sys_perf_event_open(attr, | 165 | fd[cpu][counter][0] = sys_perf_event_open(attr, |
@@ -208,7 +209,7 @@ static inline int nsec_counter(int counter) | |||
208 | static void read_counter(int counter) | 209 | static void read_counter(int counter) |
209 | { | 210 | { |
210 | u64 count[3], single_count[3]; | 211 | u64 count[3], single_count[3]; |
211 | unsigned int cpu; | 212 | int cpu; |
212 | size_t res, nv; | 213 | size_t res, nv; |
213 | int scaled; | 214 | int scaled; |
214 | int i, thread; | 215 | int i, thread; |
@@ -542,6 +543,8 @@ static const struct option options[] = { | |||
542 | "null run - dont start any counters"), | 543 | "null run - dont start any counters"), |
543 | OPT_BOOLEAN('B', "big-num", &big_num, | 544 | OPT_BOOLEAN('B', "big-num", &big_num, |
544 | "print large numbers with thousands\' separators"), | 545 | "print large numbers with thousands\' separators"), |
546 | OPT_STRING('C', "cpu", &cpu_list, "cpu", | ||
547 | "list of cpus to monitor in system-wide"), | ||
545 | OPT_END() | 548 | OPT_END() |
546 | }; | 549 | }; |
547 | 550 | ||
@@ -566,10 +569,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
566 | } | 569 | } |
567 | 570 | ||
568 | if (system_wide) | 571 | if (system_wide) |
569 | nr_cpus = read_cpu_map(); | 572 | nr_cpus = read_cpu_map(cpu_list); |
570 | else | 573 | else |
571 | nr_cpus = 1; | 574 | nr_cpus = 1; |
572 | 575 | ||
576 | if (nr_cpus < 1) | ||
577 | usage_with_options(stat_usage, options); | ||
578 | |||
573 | if (target_pid != -1) { | 579 | if (target_pid != -1) { |
574 | target_tid = target_pid; | 580 | target_tid = target_pid; |
575 | thread_num = find_all_tid(target_pid, &all_tids); | 581 | thread_num = find_all_tid(target_pid, &all_tids); |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index a66f4272b994..1e8e92e317b9 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -102,6 +102,7 @@ struct sym_entry *sym_filter_entry_sched = NULL; | |||
102 | static int sym_pcnt_filter = 5; | 102 | static int sym_pcnt_filter = 5; |
103 | static int sym_counter = 0; | 103 | static int sym_counter = 0; |
104 | static int display_weighted = -1; | 104 | static int display_weighted = -1; |
105 | static const char *cpu_list; | ||
105 | 106 | ||
106 | /* | 107 | /* |
107 | * Symbols | 108 | * Symbols |
@@ -982,6 +983,7 @@ static void event__process_sample(const event_t *self, | |||
982 | u64 ip = self->ip.ip; | 983 | u64 ip = self->ip.ip; |
983 | struct sym_entry *syme; | 984 | struct sym_entry *syme; |
984 | struct addr_location al; | 985 | struct addr_location al; |
986 | struct sample_data data; | ||
985 | struct machine *machine; | 987 | struct machine *machine; |
986 | u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 988 | u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
987 | 989 | ||
@@ -1024,7 +1026,8 @@ static void event__process_sample(const event_t *self, | |||
1024 | if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) | 1026 | if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) |
1025 | exact_samples++; | 1027 | exact_samples++; |
1026 | 1028 | ||
1027 | if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 || | 1029 | if (event__preprocess_sample(self, session, &al, &data, |
1030 | symbol_filter) < 0 || | ||
1028 | al.filtered) | 1031 | al.filtered) |
1029 | return; | 1032 | return; |
1030 | 1033 | ||
@@ -1351,8 +1354,8 @@ static const struct option options[] = { | |||
1351 | "profile events on existing thread id"), | 1354 | "profile events on existing thread id"), |
1352 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 1355 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
1353 | "system-wide collection from all CPUs"), | 1356 | "system-wide collection from all CPUs"), |
1354 | OPT_INTEGER('C', "CPU", &profile_cpu, | 1357 | OPT_STRING('C', "cpu", &cpu_list, "cpu", |
1355 | "CPU to profile on"), | 1358 | "list of cpus to monitor"), |
1356 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 1359 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
1357 | "file", "vmlinux pathname"), | 1360 | "file", "vmlinux pathname"), |
1358 | OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, | 1361 | OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, |
@@ -1428,10 +1431,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1428 | return -ENOMEM; | 1431 | return -ENOMEM; |
1429 | 1432 | ||
1430 | /* CPU and PID are mutually exclusive */ | 1433 | /* CPU and PID are mutually exclusive */ |
1431 | if (target_tid > 0 && profile_cpu != -1) { | 1434 | if (target_tid > 0 && cpu_list) { |
1432 | printf("WARNING: PID switch overriding CPU\n"); | 1435 | printf("WARNING: PID switch overriding CPU\n"); |
1433 | sleep(1); | 1436 | sleep(1); |
1434 | profile_cpu = -1; | 1437 | cpu_list = NULL; |
1435 | } | 1438 | } |
1436 | 1439 | ||
1437 | if (!nr_counters) | 1440 | if (!nr_counters) |
@@ -1469,10 +1472,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1469 | attrs[counter].sample_period = default_interval; | 1472 | attrs[counter].sample_period = default_interval; |
1470 | } | 1473 | } |
1471 | 1474 | ||
1472 | if (target_tid != -1 || profile_cpu != -1) | 1475 | if (target_tid != -1) |
1473 | nr_cpus = 1; | 1476 | nr_cpus = 1; |
1474 | else | 1477 | else |
1475 | nr_cpus = read_cpu_map(); | 1478 | nr_cpus = read_cpu_map(cpu_list); |
1479 | |||
1480 | if (nr_cpus < 1) | ||
1481 | usage_with_options(top_usage, options); | ||
1476 | 1482 | ||
1477 | get_term_dimensions(&winsize); | 1483 | get_term_dimensions(&winsize); |
1478 | if (print_entries == 0) { | 1484 | if (print_entries == 0) { |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index dddf3f01b5ab..294da725a57d 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -11,8 +11,9 @@ | |||
11 | 11 | ||
12 | static char const *script_name; | 12 | static char const *script_name; |
13 | static char const *generate_script_lang; | 13 | static char const *generate_script_lang; |
14 | static bool debug_ordering; | 14 | static bool debug_mode; |
15 | static u64 last_timestamp; | 15 | static u64 last_timestamp; |
16 | static u64 nr_unordered; | ||
16 | 17 | ||
17 | static int default_start_script(const char *script __unused, | 18 | static int default_start_script(const char *script __unused, |
18 | int argc __unused, | 19 | int argc __unused, |
@@ -91,13 +92,15 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
91 | } | 92 | } |
92 | 93 | ||
93 | if (session->sample_type & PERF_SAMPLE_RAW) { | 94 | if (session->sample_type & PERF_SAMPLE_RAW) { |
94 | if (debug_ordering) { | 95 | if (debug_mode) { |
95 | if (data.time < last_timestamp) { | 96 | if (data.time < last_timestamp) { |
96 | pr_err("Samples misordered, previous: %llu " | 97 | pr_err("Samples misordered, previous: %llu " |
97 | "this: %llu\n", last_timestamp, | 98 | "this: %llu\n", last_timestamp, |
98 | data.time); | 99 | data.time); |
100 | nr_unordered++; | ||
99 | } | 101 | } |
100 | last_timestamp = data.time; | 102 | last_timestamp = data.time; |
103 | return 0; | ||
101 | } | 104 | } |
102 | /* | 105 | /* |
103 | * FIXME: better resolve from pid from the struct trace_entry | 106 | * FIXME: better resolve from pid from the struct trace_entry |
@@ -113,6 +116,15 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
113 | return 0; | 116 | return 0; |
114 | } | 117 | } |
115 | 118 | ||
119 | static u64 nr_lost; | ||
120 | |||
121 | static int process_lost_event(event_t *event, struct perf_session *session __used) | ||
122 | { | ||
123 | nr_lost += event->lost.lost; | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
116 | static struct perf_event_ops event_ops = { | 128 | static struct perf_event_ops event_ops = { |
117 | .sample = process_sample_event, | 129 | .sample = process_sample_event, |
118 | .comm = event__process_comm, | 130 | .comm = event__process_comm, |
@@ -120,6 +132,7 @@ static struct perf_event_ops event_ops = { | |||
120 | .event_type = event__process_event_type, | 132 | .event_type = event__process_event_type, |
121 | .tracing_data = event__process_tracing_data, | 133 | .tracing_data = event__process_tracing_data, |
122 | .build_id = event__process_build_id, | 134 | .build_id = event__process_build_id, |
135 | .lost = process_lost_event, | ||
123 | .ordered_samples = true, | 136 | .ordered_samples = true, |
124 | }; | 137 | }; |
125 | 138 | ||
@@ -132,9 +145,18 @@ static void sig_handler(int sig __unused) | |||
132 | 145 | ||
133 | static int __cmd_trace(struct perf_session *session) | 146 | static int __cmd_trace(struct perf_session *session) |
134 | { | 147 | { |
148 | int ret; | ||
149 | |||
135 | signal(SIGINT, sig_handler); | 150 | signal(SIGINT, sig_handler); |
136 | 151 | ||
137 | return perf_session__process_events(session, &event_ops); | 152 | ret = perf_session__process_events(session, &event_ops); |
153 | |||
154 | if (debug_mode) { | ||
155 | pr_err("Misordered timestamps: %llu\n", nr_unordered); | ||
156 | pr_err("Lost events: %llu\n", nr_lost); | ||
157 | } | ||
158 | |||
159 | return ret; | ||
138 | } | 160 | } |
139 | 161 | ||
140 | struct script_spec { | 162 | struct script_spec { |
@@ -544,8 +566,8 @@ static const struct option options[] = { | |||
544 | "generate perf-trace.xx script in specified language"), | 566 | "generate perf-trace.xx script in specified language"), |
545 | OPT_STRING('i', "input", &input_name, "file", | 567 | OPT_STRING('i', "input", &input_name, "file", |
546 | "input file name"), | 568 | "input file name"), |
547 | OPT_BOOLEAN('d', "debug-ordering", &debug_ordering, | 569 | OPT_BOOLEAN('d', "debug-mode", &debug_mode, |
548 | "check that samples time ordering is monotonic"), | 570 | "do various checks like samples ordering and lost events"), |
549 | 571 | ||
550 | OPT_END() | 572 | OPT_END() |
551 | }; | 573 | }; |
diff --git a/tools/perf/feature-tests.mak b/tools/perf/feature-tests.mak new file mode 100644 index 000000000000..ddb68e601f0e --- /dev/null +++ b/tools/perf/feature-tests.mak | |||
@@ -0,0 +1,119 @@ | |||
1 | define SOURCE_HELLO | ||
2 | #include <stdio.h> | ||
3 | int main(void) | ||
4 | { | ||
5 | return puts(\"hi\"); | ||
6 | } | ||
7 | endef | ||
8 | |||
9 | ifndef NO_DWARF | ||
10 | define SOURCE_DWARF | ||
11 | #include <dwarf.h> | ||
12 | #include <libdw.h> | ||
13 | #include <version.h> | ||
14 | #ifndef _ELFUTILS_PREREQ | ||
15 | #error | ||
16 | #endif | ||
17 | |||
18 | int main(void) | ||
19 | { | ||
20 | Dwarf *dbg = dwarf_begin(0, DWARF_C_READ); | ||
21 | return (long)dbg; | ||
22 | } | ||
23 | endef | ||
24 | endif | ||
25 | |||
26 | define SOURCE_LIBELF | ||
27 | #include <libelf.h> | ||
28 | |||
29 | int main(void) | ||
30 | { | ||
31 | Elf *elf = elf_begin(0, ELF_C_READ, 0); | ||
32 | return (long)elf; | ||
33 | } | ||
34 | endef | ||
35 | |||
36 | define SOURCE_GLIBC | ||
37 | #include <gnu/libc-version.h> | ||
38 | |||
39 | int main(void) | ||
40 | { | ||
41 | const char *version = gnu_get_libc_version(); | ||
42 | return (long)version; | ||
43 | } | ||
44 | endef | ||
45 | |||
46 | define SOURCE_ELF_MMAP | ||
47 | #include <libelf.h> | ||
48 | int main(void) | ||
49 | { | ||
50 | Elf *elf = elf_begin(0, ELF_C_READ_MMAP, 0); | ||
51 | return (long)elf; | ||
52 | } | ||
53 | endef | ||
54 | |||
55 | ifndef NO_NEWT | ||
56 | define SOURCE_NEWT | ||
57 | #include <newt.h> | ||
58 | |||
59 | int main(void) | ||
60 | { | ||
61 | newtInit(); | ||
62 | newtCls(); | ||
63 | return newtFinished(); | ||
64 | } | ||
65 | endef | ||
66 | endif | ||
67 | |||
68 | ifndef NO_LIBPERL | ||
69 | define SOURCE_PERL_EMBED | ||
70 | #include <EXTERN.h> | ||
71 | #include <perl.h> | ||
72 | |||
73 | int main(void) | ||
74 | { | ||
75 | perl_alloc(); | ||
76 | return 0; | ||
77 | } | ||
78 | endef | ||
79 | endif | ||
80 | |||
81 | ifndef NO_LIBPYTHON | ||
82 | define SOURCE_PYTHON_EMBED | ||
83 | #include <Python.h> | ||
84 | |||
85 | int main(void) | ||
86 | { | ||
87 | Py_Initialize(); | ||
88 | return 0; | ||
89 | } | ||
90 | endef | ||
91 | endif | ||
92 | |||
93 | define SOURCE_BFD | ||
94 | #include <bfd.h> | ||
95 | |||
96 | int main(void) | ||
97 | { | ||
98 | bfd_demangle(0, 0, 0); | ||
99 | return 0; | ||
100 | } | ||
101 | endef | ||
102 | |||
103 | define SOURCE_CPLUS_DEMANGLE | ||
104 | extern char *cplus_demangle(const char *, int); | ||
105 | |||
106 | int main(void) | ||
107 | { | ||
108 | cplus_demangle(0, 0); | ||
109 | return 0; | ||
110 | } | ||
111 | endef | ||
112 | |||
113 | # try-cc | ||
114 | # Usage: option = $(call try-cc, source-to-build, cc-options) | ||
115 | try-cc = $(shell sh -c \ | ||
116 | 'TMP="$(TMPOUT).$$$$"; \ | ||
117 | echo "$(1)" | \ | ||
118 | $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \ | ||
119 | rm -f "$$TMP"') | ||
diff --git a/tools/perf/perf-archive.sh b/tools/perf/perf-archive.sh index 2e7a4f417e20..677e59d62a8d 100644 --- a/tools/perf/perf-archive.sh +++ b/tools/perf/perf-archive.sh | |||
@@ -7,7 +7,17 @@ if [ $# -ne 0 ] ; then | |||
7 | PERF_DATA=$1 | 7 | PERF_DATA=$1 |
8 | fi | 8 | fi |
9 | 9 | ||
10 | DEBUGDIR=~/.debug/ | 10 | # |
11 | # PERF_BUILDID_DIR environment variable set by perf | ||
12 | # path to buildid directory, default to $HOME/.debug | ||
13 | # | ||
14 | if [ -z $PERF_BUILDID_DIR ]; then | ||
15 | PERF_BUILDID_DIR=~/.debug/ | ||
16 | else | ||
17 | # append / to make substitutions work | ||
18 | PERF_BUILDID_DIR=$PERF_BUILDID_DIR/ | ||
19 | fi | ||
20 | |||
11 | BUILDIDS=$(mktemp /tmp/perf-archive-buildids.XXXXXX) | 21 | BUILDIDS=$(mktemp /tmp/perf-archive-buildids.XXXXXX) |
12 | NOBUILDID=0000000000000000000000000000000000000000 | 22 | NOBUILDID=0000000000000000000000000000000000000000 |
13 | 23 | ||
@@ -22,13 +32,13 @@ MANIFEST=$(mktemp /tmp/perf-archive-manifest.XXXXXX) | |||
22 | 32 | ||
23 | cut -d ' ' -f 1 $BUILDIDS | \ | 33 | cut -d ' ' -f 1 $BUILDIDS | \ |
24 | while read build_id ; do | 34 | while read build_id ; do |
25 | linkname=$DEBUGDIR.build-id/${build_id:0:2}/${build_id:2} | 35 | linkname=$PERF_BUILDID_DIR.build-id/${build_id:0:2}/${build_id:2} |
26 | filename=$(readlink -f $linkname) | 36 | filename=$(readlink -f $linkname) |
27 | echo ${linkname#$DEBUGDIR} >> $MANIFEST | 37 | echo ${linkname#$PERF_BUILDID_DIR} >> $MANIFEST |
28 | echo ${filename#$DEBUGDIR} >> $MANIFEST | 38 | echo ${filename#$PERF_BUILDID_DIR} >> $MANIFEST |
29 | done | 39 | done |
30 | 40 | ||
31 | tar cfj $PERF_DATA.tar.bz2 -C $DEBUGDIR -T $MANIFEST | 41 | tar cfj $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST |
32 | rm -f $MANIFEST $BUILDIDS | 42 | rm -f $MANIFEST $BUILDIDS |
33 | echo -e "Now please run:\n" | 43 | echo -e "Now please run:\n" |
34 | echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n" | 44 | echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n" |
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 6e4871191138..cdd6c03f1e14 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -458,6 +458,8 @@ int main(int argc, const char **argv) | |||
458 | handle_options(&argv, &argc, NULL); | 458 | handle_options(&argv, &argc, NULL); |
459 | commit_pager_choice(); | 459 | commit_pager_choice(); |
460 | set_debugfs_path(); | 460 | set_debugfs_path(); |
461 | set_buildid_dir(); | ||
462 | |||
461 | if (argc > 0) { | 463 | if (argc > 0) { |
462 | if (!prefixcmp(argv[0], "--")) | 464 | if (!prefixcmp(argv[0], "--")) |
463 | argv[0] += 2; | 465 | argv[0] += 2; |
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 70c5cf87d020..5c26e2d314af 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c | |||
@@ -43,19 +43,17 @@ struct perf_event_ops build_id__mark_dso_hit_ops = { | |||
43 | char *dso__build_id_filename(struct dso *self, char *bf, size_t size) | 43 | char *dso__build_id_filename(struct dso *self, char *bf, size_t size) |
44 | { | 44 | { |
45 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | 45 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; |
46 | const char *home; | ||
47 | 46 | ||
48 | if (!self->has_build_id) | 47 | if (!self->has_build_id) |
49 | return NULL; | 48 | return NULL; |
50 | 49 | ||
51 | build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex); | 50 | build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex); |
52 | home = getenv("HOME"); | ||
53 | if (bf == NULL) { | 51 | if (bf == NULL) { |
54 | if (asprintf(&bf, "%s/%s/.build-id/%.2s/%s", home, | 52 | if (asprintf(&bf, "%s/.build-id/%.2s/%s", buildid_dir, |
55 | DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2) < 0) | 53 | build_id_hex, build_id_hex + 2) < 0) |
56 | return NULL; | 54 | return NULL; |
57 | } else | 55 | } else |
58 | snprintf(bf, size, "%s/%s/.build-id/%.2s/%s", home, | 56 | snprintf(bf, size, "%s/.build-id/%.2s/%s", buildid_dir, |
59 | DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2); | 57 | build_id_hex, build_id_hex + 2); |
60 | return bf; | 58 | return bf; |
61 | } | 59 | } |
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 65fe664fddf6..27e9ebe4076e 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h | |||
@@ -23,6 +23,7 @@ extern int perf_config(config_fn_t fn, void *); | |||
23 | extern int perf_config_int(const char *, const char *); | 23 | extern int perf_config_int(const char *, const char *); |
24 | extern int perf_config_bool(const char *, const char *); | 24 | extern int perf_config_bool(const char *, const char *); |
25 | extern int config_error_nonbool(const char *); | 25 | extern int config_error_nonbool(const char *); |
26 | extern const char *perf_config_dirname(const char *, const char *); | ||
26 | 27 | ||
27 | /* pager.c */ | 28 | /* pager.c */ |
28 | extern void setup_pager(void); | 29 | extern void setup_pager(void); |
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 62b69ad4aa73..e63c997d6c1b 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -18,7 +18,7 @@ | |||
18 | #include "util.h" | 18 | #include "util.h" |
19 | #include "callchain.h" | 19 | #include "callchain.h" |
20 | 20 | ||
21 | bool ip_callchain__valid(struct ip_callchain *chain, event_t *event) | 21 | bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event) |
22 | { | 22 | { |
23 | unsigned int chain_size = event->header.size; | 23 | unsigned int chain_size = event->header.size; |
24 | chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event; | 24 | chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event; |
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 1ca73e4a2723..809850fb75fb 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -60,5 +60,5 @@ int register_callchain_param(struct callchain_param *param); | |||
60 | int append_chain(struct callchain_node *root, struct ip_callchain *chain, | 60 | int append_chain(struct callchain_node *root, struct ip_callchain *chain, |
61 | struct map_symbol *syms); | 61 | struct map_symbol *syms); |
62 | 62 | ||
63 | bool ip_callchain__valid(struct ip_callchain *chain, event_t *event); | 63 | bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event); |
64 | #endif /* __PERF_CALLCHAIN_H */ | 64 | #endif /* __PERF_CALLCHAIN_H */ |
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index dabe892d0e53..e02d78cae70f 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c | |||
@@ -11,6 +11,11 @@ | |||
11 | 11 | ||
12 | #define MAXNAME (256) | 12 | #define MAXNAME (256) |
13 | 13 | ||
14 | #define DEBUG_CACHE_DIR ".debug" | ||
15 | |||
16 | |||
17 | char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */ | ||
18 | |||
14 | static FILE *config_file; | 19 | static FILE *config_file; |
15 | static const char *config_file_name; | 20 | static const char *config_file_name; |
16 | static int config_linenr; | 21 | static int config_linenr; |
@@ -127,7 +132,7 @@ static int get_value(config_fn_t fn, void *data, char *name, unsigned int len) | |||
127 | break; | 132 | break; |
128 | if (!iskeychar(c)) | 133 | if (!iskeychar(c)) |
129 | break; | 134 | break; |
130 | name[len++] = tolower(c); | 135 | name[len++] = c; |
131 | if (len >= MAXNAME) | 136 | if (len >= MAXNAME) |
132 | return -1; | 137 | return -1; |
133 | } | 138 | } |
@@ -327,6 +332,13 @@ int perf_config_bool(const char *name, const char *value) | |||
327 | return !!perf_config_bool_or_int(name, value, &discard); | 332 | return !!perf_config_bool_or_int(name, value, &discard); |
328 | } | 333 | } |
329 | 334 | ||
335 | const char *perf_config_dirname(const char *name, const char *value) | ||
336 | { | ||
337 | if (!name) | ||
338 | return NULL; | ||
339 | return value; | ||
340 | } | ||
341 | |||
330 | static int perf_default_core_config(const char *var __used, const char *value __used) | 342 | static int perf_default_core_config(const char *var __used, const char *value __used) |
331 | { | 343 | { |
332 | /* Add other config variables here and to Documentation/config.txt. */ | 344 | /* Add other config variables here and to Documentation/config.txt. */ |
@@ -428,3 +440,53 @@ int config_error_nonbool(const char *var) | |||
428 | { | 440 | { |
429 | return error("Missing value for '%s'", var); | 441 | return error("Missing value for '%s'", var); |
430 | } | 442 | } |
443 | |||
444 | struct buildid_dir_config { | ||
445 | char *dir; | ||
446 | }; | ||
447 | |||
448 | static int buildid_dir_command_config(const char *var, const char *value, | ||
449 | void *data) | ||
450 | { | ||
451 | struct buildid_dir_config *c = data; | ||
452 | const char *v; | ||
453 | |||
454 | /* same dir for all commands */ | ||
455 | if (!prefixcmp(var, "buildid.") && !strcmp(var + 8, "dir")) { | ||
456 | v = perf_config_dirname(var, value); | ||
457 | if (!v) | ||
458 | return -1; | ||
459 | strncpy(c->dir, v, MAXPATHLEN-1); | ||
460 | c->dir[MAXPATHLEN-1] = '\0'; | ||
461 | } | ||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static void check_buildid_dir_config(void) | ||
466 | { | ||
467 | struct buildid_dir_config c; | ||
468 | c.dir = buildid_dir; | ||
469 | perf_config(buildid_dir_command_config, &c); | ||
470 | } | ||
471 | |||
472 | void set_buildid_dir(void) | ||
473 | { | ||
474 | buildid_dir[0] = '\0'; | ||
475 | |||
476 | /* try config file */ | ||
477 | check_buildid_dir_config(); | ||
478 | |||
479 | /* default to $HOME/.debug */ | ||
480 | if (buildid_dir[0] == '\0') { | ||
481 | char *v = getenv("HOME"); | ||
482 | if (v) { | ||
483 | snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s", | ||
484 | v, DEBUG_CACHE_DIR); | ||
485 | } else { | ||
486 | strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1); | ||
487 | } | ||
488 | buildid_dir[MAXPATHLEN-1] = '\0'; | ||
489 | } | ||
490 | /* for communicating with external commands */ | ||
491 | setenv("PERF_BUILDID_DIR", buildid_dir, 1); | ||
492 | } | ||
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 4e01490e51e5..0f9b8d7a7d7e 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c | |||
@@ -20,7 +20,7 @@ static int default_cpu_map(void) | |||
20 | return nr_cpus; | 20 | return nr_cpus; |
21 | } | 21 | } |
22 | 22 | ||
23 | int read_cpu_map(void) | 23 | static int read_all_cpu_map(void) |
24 | { | 24 | { |
25 | FILE *onlnf; | 25 | FILE *onlnf; |
26 | int nr_cpus = 0; | 26 | int nr_cpus = 0; |
@@ -57,3 +57,58 @@ int read_cpu_map(void) | |||
57 | 57 | ||
58 | return default_cpu_map(); | 58 | return default_cpu_map(); |
59 | } | 59 | } |
60 | |||
61 | int read_cpu_map(const char *cpu_list) | ||
62 | { | ||
63 | unsigned long start_cpu, end_cpu = 0; | ||
64 | char *p = NULL; | ||
65 | int i, nr_cpus = 0; | ||
66 | |||
67 | if (!cpu_list) | ||
68 | return read_all_cpu_map(); | ||
69 | |||
70 | if (!isdigit(*cpu_list)) | ||
71 | goto invalid; | ||
72 | |||
73 | while (isdigit(*cpu_list)) { | ||
74 | p = NULL; | ||
75 | start_cpu = strtoul(cpu_list, &p, 0); | ||
76 | if (start_cpu >= INT_MAX | ||
77 | || (*p != '\0' && *p != ',' && *p != '-')) | ||
78 | goto invalid; | ||
79 | |||
80 | if (*p == '-') { | ||
81 | cpu_list = ++p; | ||
82 | p = NULL; | ||
83 | end_cpu = strtoul(cpu_list, &p, 0); | ||
84 | |||
85 | if (end_cpu >= INT_MAX || (*p != '\0' && *p != ',')) | ||
86 | goto invalid; | ||
87 | |||
88 | if (end_cpu < start_cpu) | ||
89 | goto invalid; | ||
90 | } else { | ||
91 | end_cpu = start_cpu; | ||
92 | } | ||
93 | |||
94 | for (; start_cpu <= end_cpu; start_cpu++) { | ||
95 | /* check for duplicates */ | ||
96 | for (i = 0; i < nr_cpus; i++) | ||
97 | if (cpumap[i] == (int)start_cpu) | ||
98 | goto invalid; | ||
99 | |||
100 | assert(nr_cpus < MAX_NR_CPUS); | ||
101 | cpumap[nr_cpus++] = (int)start_cpu; | ||
102 | } | ||
103 | if (*p) | ||
104 | ++p; | ||
105 | |||
106 | cpu_list = p; | ||
107 | } | ||
108 | if (nr_cpus > 0) | ||
109 | return nr_cpus; | ||
110 | |||
111 | return default_cpu_map(); | ||
112 | invalid: | ||
113 | return -1; | ||
114 | } | ||
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 86c78bb33098..3e60f56e490e 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #ifndef __PERF_CPUMAP_H | 1 | #ifndef __PERF_CPUMAP_H |
2 | #define __PERF_CPUMAP_H | 2 | #define __PERF_CPUMAP_H |
3 | 3 | ||
4 | extern int read_cpu_map(void); | 4 | extern int read_cpu_map(const char *cpu_list); |
5 | extern int cpumap[]; | 5 | extern int cpumap[]; |
6 | 6 | ||
7 | #endif /* __PERF_CPUMAP_H */ | 7 | #endif /* __PERF_CPUMAP_H */ |
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 6cddff2bc970..318dab15d177 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
@@ -86,12 +86,10 @@ void trace_event(event_t *event) | |||
86 | dump_printf_color(" ", color); | 86 | dump_printf_color(" ", color); |
87 | for (j = 0; j < 15-(i & 15); j++) | 87 | for (j = 0; j < 15-(i & 15); j++) |
88 | dump_printf_color(" ", color); | 88 | dump_printf_color(" ", color); |
89 | for (j = 0; j < (i & 15); j++) { | 89 | for (j = i & ~15; j <= i; j++) { |
90 | if (isprint(raw_event[i-15+j])) | 90 | dump_printf_color("%c", color, |
91 | dump_printf_color("%c", color, | 91 | isprint(raw_event[j]) ? |
92 | raw_event[i-15+j]); | 92 | raw_event[j] : '.'); |
93 | else | ||
94 | dump_printf_color(".", color); | ||
95 | } | 93 | } |
96 | dump_printf_color("\n", color); | 94 | dump_printf_color("\n", color); |
97 | } | 95 | } |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 2fbf6a463c81..d7f21d71eb69 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -657,11 +657,36 @@ static void dso__calc_col_width(struct dso *self) | |||
657 | } | 657 | } |
658 | 658 | ||
659 | int event__preprocess_sample(const event_t *self, struct perf_session *session, | 659 | int event__preprocess_sample(const event_t *self, struct perf_session *session, |
660 | struct addr_location *al, symbol_filter_t filter) | 660 | struct addr_location *al, struct sample_data *data, |
661 | symbol_filter_t filter) | ||
661 | { | 662 | { |
662 | u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 663 | u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
663 | struct thread *thread = perf_session__findnew(session, self->ip.pid); | 664 | struct thread *thread; |
665 | |||
666 | event__parse_sample(self, session->sample_type, data); | ||
667 | |||
668 | dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld cpu:%d\n", | ||
669 | self->header.misc, data->pid, data->tid, data->ip, | ||
670 | data->period, data->cpu); | ||
671 | |||
672 | if (session->sample_type & PERF_SAMPLE_CALLCHAIN) { | ||
673 | unsigned int i; | ||
674 | |||
675 | dump_printf("... chain: nr:%Lu\n", data->callchain->nr); | ||
676 | |||
677 | if (!ip_callchain__valid(data->callchain, self)) { | ||
678 | pr_debug("call-chain problem with event, " | ||
679 | "skipping it.\n"); | ||
680 | goto out_filtered; | ||
681 | } | ||
664 | 682 | ||
683 | if (dump_trace) { | ||
684 | for (i = 0; i < data->callchain->nr; i++) | ||
685 | dump_printf("..... %2d: %016Lx\n", | ||
686 | i, data->callchain->ips[i]); | ||
687 | } | ||
688 | } | ||
689 | thread = perf_session__findnew(session, self->ip.pid); | ||
665 | if (thread == NULL) | 690 | if (thread == NULL) |
666 | return -1; | 691 | return -1; |
667 | 692 | ||
@@ -687,6 +712,7 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session, | |||
687 | al->map ? al->map->dso->long_name : | 712 | al->map ? al->map->dso->long_name : |
688 | al->level == 'H' ? "[hypervisor]" : "<not found>"); | 713 | al->level == 'H' ? "[hypervisor]" : "<not found>"); |
689 | al->sym = NULL; | 714 | al->sym = NULL; |
715 | al->cpu = data->cpu; | ||
690 | 716 | ||
691 | if (al->map) { | 717 | if (al->map) { |
692 | if (symbol_conf.dso_list && | 718 | if (symbol_conf.dso_list && |
@@ -726,9 +752,9 @@ out_filtered: | |||
726 | return 0; | 752 | return 0; |
727 | } | 753 | } |
728 | 754 | ||
729 | int event__parse_sample(event_t *event, u64 type, struct sample_data *data) | 755 | int event__parse_sample(const event_t *event, u64 type, struct sample_data *data) |
730 | { | 756 | { |
731 | u64 *array = event->sample.array; | 757 | const u64 *array = event->sample.array; |
732 | 758 | ||
733 | if (type & PERF_SAMPLE_IP) { | 759 | if (type & PERF_SAMPLE_IP) { |
734 | data->ip = event->ip.ip; | 760 | data->ip = event->ip.ip; |
@@ -767,7 +793,8 @@ int event__parse_sample(event_t *event, u64 type, struct sample_data *data) | |||
767 | u32 *p = (u32 *)array; | 793 | u32 *p = (u32 *)array; |
768 | data->cpu = *p; | 794 | data->cpu = *p; |
769 | array++; | 795 | array++; |
770 | } | 796 | } else |
797 | data->cpu = -1; | ||
771 | 798 | ||
772 | if (type & PERF_SAMPLE_PERIOD) { | 799 | if (type & PERF_SAMPLE_PERIOD) { |
773 | data->period = *array; | 800 | data->period = *array; |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 8577085db067..887ee63bbb62 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -157,8 +157,9 @@ int event__process_task(event_t *self, struct perf_session *session); | |||
157 | 157 | ||
158 | struct addr_location; | 158 | struct addr_location; |
159 | int event__preprocess_sample(const event_t *self, struct perf_session *session, | 159 | int event__preprocess_sample(const event_t *self, struct perf_session *session, |
160 | struct addr_location *al, symbol_filter_t filter); | 160 | struct addr_location *al, struct sample_data *data, |
161 | int event__parse_sample(event_t *event, u64 type, struct sample_data *data); | 161 | symbol_filter_t filter); |
162 | int event__parse_sample(const event_t *event, u64 type, struct sample_data *data); | ||
162 | 163 | ||
163 | extern const char *event__name[]; | 164 | extern const char *event__name[]; |
164 | 165 | ||
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 1f62435f96c2..d7e67b167ea3 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include "symbol.h" | 16 | #include "symbol.h" |
17 | #include "debug.h" | 17 | #include "debug.h" |
18 | 18 | ||
19 | static bool no_buildid_cache = false; | ||
20 | |||
19 | /* | 21 | /* |
20 | * Create new perf.data header attribute: | 22 | * Create new perf.data header attribute: |
21 | */ | 23 | */ |
@@ -385,8 +387,7 @@ static int perf_session__cache_build_ids(struct perf_session *self) | |||
385 | int ret; | 387 | int ret; |
386 | char debugdir[PATH_MAX]; | 388 | char debugdir[PATH_MAX]; |
387 | 389 | ||
388 | snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"), | 390 | snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir); |
389 | DEBUG_CACHE_DIR); | ||
390 | 391 | ||
391 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) | 392 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) |
392 | return -1; | 393 | return -1; |
@@ -471,7 +472,8 @@ static int perf_header__adds_write(struct perf_header *self, int fd) | |||
471 | } | 472 | } |
472 | buildid_sec->size = lseek(fd, 0, SEEK_CUR) - | 473 | buildid_sec->size = lseek(fd, 0, SEEK_CUR) - |
473 | buildid_sec->offset; | 474 | buildid_sec->offset; |
474 | perf_session__cache_build_ids(session); | 475 | if (!no_buildid_cache) |
476 | perf_session__cache_build_ids(session); | ||
475 | } | 477 | } |
476 | 478 | ||
477 | lseek(fd, sec_start, SEEK_SET); | 479 | lseek(fd, sec_start, SEEK_SET); |
@@ -1190,3 +1192,8 @@ int event__process_build_id(event_t *self, | |||
1190 | session); | 1192 | session); |
1191 | return 0; | 1193 | return 0; |
1192 | } | 1194 | } |
1195 | |||
1196 | void disable_buildid_cache(void) | ||
1197 | { | ||
1198 | no_buildid_cache = true; | ||
1199 | } | ||
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 07f89b66b318..68d288c975de 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -70,6 +70,7 @@ struct hist_entry *__hists__add_entry(struct hists *self, | |||
70 | .map = al->map, | 70 | .map = al->map, |
71 | .sym = al->sym, | 71 | .sym = al->sym, |
72 | }, | 72 | }, |
73 | .cpu = al->cpu, | ||
73 | .ip = al->addr, | 74 | .ip = al->addr, |
74 | .level = al->level, | 75 | .level = al->level, |
75 | .period = period, | 76 | .period = period, |
@@ -1037,7 +1038,7 @@ fallback: | |||
1037 | dso, dso->long_name, sym, sym->name); | 1038 | dso, dso->long_name, sym, sym->name); |
1038 | 1039 | ||
1039 | snprintf(command, sizeof(command), | 1040 | snprintf(command, sizeof(command), |
1040 | "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s|expand", | 1041 | "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand", |
1041 | map__rip_2objdump(map, sym->start), | 1042 | map__rip_2objdump(map, sym->start), |
1042 | map__rip_2objdump(map, sym->end), | 1043 | map__rip_2objdump(map, sym->end), |
1043 | filename, filename); | 1044 | filename, filename); |
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index 7537ca15900b..89c52fc9b22e 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c | |||
@@ -278,9 +278,48 @@ struct ui_browser { | |||
278 | void *first_visible_entry, *entries; | 278 | void *first_visible_entry, *entries; |
279 | u16 top, left, width, height; | 279 | u16 top, left, width, height; |
280 | void *priv; | 280 | void *priv; |
281 | unsigned int (*refresh_entries)(struct ui_browser *self); | ||
282 | void (*seek)(struct ui_browser *self, | ||
283 | off_t offset, int whence); | ||
281 | u32 nr_entries; | 284 | u32 nr_entries; |
282 | }; | 285 | }; |
283 | 286 | ||
287 | static void ui_browser__list_head_seek(struct ui_browser *self, | ||
288 | off_t offset, int whence) | ||
289 | { | ||
290 | struct list_head *head = self->entries; | ||
291 | struct list_head *pos; | ||
292 | |||
293 | switch (whence) { | ||
294 | case SEEK_SET: | ||
295 | pos = head->next; | ||
296 | break; | ||
297 | case SEEK_CUR: | ||
298 | pos = self->first_visible_entry; | ||
299 | break; | ||
300 | case SEEK_END: | ||
301 | pos = head->prev; | ||
302 | break; | ||
303 | default: | ||
304 | return; | ||
305 | } | ||
306 | |||
307 | if (offset > 0) { | ||
308 | while (offset-- != 0) | ||
309 | pos = pos->next; | ||
310 | } else { | ||
311 | while (offset++ != 0) | ||
312 | pos = pos->prev; | ||
313 | } | ||
314 | |||
315 | self->first_visible_entry = pos; | ||
316 | } | ||
317 | |||
318 | static bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row) | ||
319 | { | ||
320 | return (self->first_visible_entry_idx + row) == self->index; | ||
321 | } | ||
322 | |||
284 | static void ui_browser__refresh_dimensions(struct ui_browser *self) | 323 | static void ui_browser__refresh_dimensions(struct ui_browser *self) |
285 | { | 324 | { |
286 | int cols, rows; | 325 | int cols, rows; |
@@ -297,8 +336,34 @@ static void ui_browser__refresh_dimensions(struct ui_browser *self) | |||
297 | 336 | ||
298 | static void ui_browser__reset_index(struct ui_browser *self) | 337 | static void ui_browser__reset_index(struct ui_browser *self) |
299 | { | 338 | { |
300 | self->index = self->first_visible_entry_idx = 0; | 339 | self->index = self->first_visible_entry_idx = 0; |
301 | self->first_visible_entry = NULL; | 340 | self->seek(self, 0, SEEK_SET); |
341 | } | ||
342 | |||
343 | static int ui_browser__show(struct ui_browser *self, const char *title) | ||
344 | { | ||
345 | if (self->form != NULL) | ||
346 | return 0; | ||
347 | ui_browser__refresh_dimensions(self); | ||
348 | newtCenteredWindow(self->width + 2, self->height, title); | ||
349 | self->form = newt_form__new(); | ||
350 | if (self->form == NULL) | ||
351 | return -1; | ||
352 | |||
353 | self->sb = newtVerticalScrollbar(self->width + 1, 0, self->height, | ||
354 | HE_COLORSET_NORMAL, | ||
355 | HE_COLORSET_SELECTED); | ||
356 | if (self->sb == NULL) | ||
357 | return -1; | ||
358 | |||
359 | newtFormAddHotKey(self->form, NEWT_KEY_UP); | ||
360 | newtFormAddHotKey(self->form, NEWT_KEY_DOWN); | ||
361 | newtFormAddHotKey(self->form, NEWT_KEY_PGUP); | ||
362 | newtFormAddHotKey(self->form, NEWT_KEY_PGDN); | ||
363 | newtFormAddHotKey(self->form, NEWT_KEY_HOME); | ||
364 | newtFormAddHotKey(self->form, NEWT_KEY_END); | ||
365 | newtFormAddComponent(self->form, self->sb); | ||
366 | return 0; | ||
302 | } | 367 | } |
303 | 368 | ||
304 | static int objdump_line__show(struct objdump_line *self, struct list_head *head, | 369 | static int objdump_line__show(struct objdump_line *self, struct list_head *head, |
@@ -352,26 +417,10 @@ static int objdump_line__show(struct objdump_line *self, struct list_head *head, | |||
352 | 417 | ||
353 | static int ui_browser__refresh_entries(struct ui_browser *self) | 418 | static int ui_browser__refresh_entries(struct ui_browser *self) |
354 | { | 419 | { |
355 | struct objdump_line *pos; | 420 | int row; |
356 | struct list_head *head = self->entries; | ||
357 | struct hist_entry *he = self->priv; | ||
358 | int row = 0; | ||
359 | int len = he->ms.sym->end - he->ms.sym->start; | ||
360 | |||
361 | if (self->first_visible_entry == NULL || self->first_visible_entry == self->entries) | ||
362 | self->first_visible_entry = head->next; | ||
363 | |||
364 | pos = list_entry(self->first_visible_entry, struct objdump_line, node); | ||
365 | |||
366 | list_for_each_entry_from(pos, head, node) { | ||
367 | bool current_entry = (self->first_visible_entry_idx + row) == self->index; | ||
368 | SLsmg_gotorc(self->top + row, self->left); | ||
369 | objdump_line__show(pos, head, self->width, | ||
370 | he, len, current_entry); | ||
371 | if (++row == self->height) | ||
372 | break; | ||
373 | } | ||
374 | 421 | ||
422 | newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); | ||
423 | row = self->refresh_entries(self); | ||
375 | SLsmg_set_color(HE_COLORSET_NORMAL); | 424 | SLsmg_set_color(HE_COLORSET_NORMAL); |
376 | SLsmg_fill_region(self->top + row, self->left, | 425 | SLsmg_fill_region(self->top + row, self->left, |
377 | self->height - row, self->width, ' '); | 426 | self->height - row, self->width, ' '); |
@@ -379,42 +428,13 @@ static int ui_browser__refresh_entries(struct ui_browser *self) | |||
379 | return 0; | 428 | return 0; |
380 | } | 429 | } |
381 | 430 | ||
382 | static int ui_browser__run(struct ui_browser *self, const char *title, | 431 | static int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es) |
383 | struct newtExitStruct *es) | ||
384 | { | 432 | { |
385 | if (self->form) { | ||
386 | newtFormDestroy(self->form); | ||
387 | newtPopWindow(); | ||
388 | } | ||
389 | |||
390 | ui_browser__refresh_dimensions(self); | ||
391 | newtCenteredWindow(self->width + 2, self->height, title); | ||
392 | self->form = newt_form__new(); | ||
393 | if (self->form == NULL) | ||
394 | return -1; | ||
395 | |||
396 | self->sb = newtVerticalScrollbar(self->width + 1, 0, self->height, | ||
397 | HE_COLORSET_NORMAL, | ||
398 | HE_COLORSET_SELECTED); | ||
399 | if (self->sb == NULL) | ||
400 | return -1; | ||
401 | |||
402 | newtFormAddHotKey(self->form, NEWT_KEY_UP); | ||
403 | newtFormAddHotKey(self->form, NEWT_KEY_DOWN); | ||
404 | newtFormAddHotKey(self->form, NEWT_KEY_PGUP); | ||
405 | newtFormAddHotKey(self->form, NEWT_KEY_PGDN); | ||
406 | newtFormAddHotKey(self->form, ' '); | ||
407 | newtFormAddHotKey(self->form, NEWT_KEY_HOME); | ||
408 | newtFormAddHotKey(self->form, NEWT_KEY_END); | ||
409 | newtFormAddHotKey(self->form, NEWT_KEY_TAB); | ||
410 | newtFormAddHotKey(self->form, NEWT_KEY_RIGHT); | ||
411 | |||
412 | if (ui_browser__refresh_entries(self) < 0) | 433 | if (ui_browser__refresh_entries(self) < 0) |
413 | return -1; | 434 | return -1; |
414 | newtFormAddComponent(self->form, self->sb); | ||
415 | 435 | ||
416 | while (1) { | 436 | while (1) { |
417 | unsigned int offset; | 437 | off_t offset; |
418 | 438 | ||
419 | newtFormRun(self->form, es); | 439 | newtFormRun(self->form, es); |
420 | 440 | ||
@@ -428,9 +448,8 @@ static int ui_browser__run(struct ui_browser *self, const char *title, | |||
428 | break; | 448 | break; |
429 | ++self->index; | 449 | ++self->index; |
430 | if (self->index == self->first_visible_entry_idx + self->height) { | 450 | if (self->index == self->first_visible_entry_idx + self->height) { |
431 | struct list_head *pos = self->first_visible_entry; | ||
432 | ++self->first_visible_entry_idx; | 451 | ++self->first_visible_entry_idx; |
433 | self->first_visible_entry = pos->next; | 452 | self->seek(self, +1, SEEK_CUR); |
434 | } | 453 | } |
435 | break; | 454 | break; |
436 | case NEWT_KEY_UP: | 455 | case NEWT_KEY_UP: |
@@ -438,9 +457,8 @@ static int ui_browser__run(struct ui_browser *self, const char *title, | |||
438 | break; | 457 | break; |
439 | --self->index; | 458 | --self->index; |
440 | if (self->index < self->first_visible_entry_idx) { | 459 | if (self->index < self->first_visible_entry_idx) { |
441 | struct list_head *pos = self->first_visible_entry; | ||
442 | --self->first_visible_entry_idx; | 460 | --self->first_visible_entry_idx; |
443 | self->first_visible_entry = pos->prev; | 461 | self->seek(self, -1, SEEK_CUR); |
444 | } | 462 | } |
445 | break; | 463 | break; |
446 | case NEWT_KEY_PGDN: | 464 | case NEWT_KEY_PGDN: |
@@ -453,12 +471,7 @@ static int ui_browser__run(struct ui_browser *self, const char *title, | |||
453 | offset = self->nr_entries - 1 - self->index; | 471 | offset = self->nr_entries - 1 - self->index; |
454 | self->index += offset; | 472 | self->index += offset; |
455 | self->first_visible_entry_idx += offset; | 473 | self->first_visible_entry_idx += offset; |
456 | 474 | self->seek(self, +offset, SEEK_CUR); | |
457 | while (offset--) { | ||
458 | struct list_head *pos = self->first_visible_entry; | ||
459 | self->first_visible_entry = pos->next; | ||
460 | } | ||
461 | |||
462 | break; | 475 | break; |
463 | case NEWT_KEY_PGUP: | 476 | case NEWT_KEY_PGUP: |
464 | if (self->first_visible_entry_idx == 0) | 477 | if (self->first_visible_entry_idx == 0) |
@@ -471,29 +484,19 @@ static int ui_browser__run(struct ui_browser *self, const char *title, | |||
471 | 484 | ||
472 | self->index -= offset; | 485 | self->index -= offset; |
473 | self->first_visible_entry_idx -= offset; | 486 | self->first_visible_entry_idx -= offset; |
474 | 487 | self->seek(self, -offset, SEEK_CUR); | |
475 | while (offset--) { | ||
476 | struct list_head *pos = self->first_visible_entry; | ||
477 | self->first_visible_entry = pos->prev; | ||
478 | } | ||
479 | break; | 488 | break; |
480 | case NEWT_KEY_HOME: | 489 | case NEWT_KEY_HOME: |
481 | ui_browser__reset_index(self); | 490 | ui_browser__reset_index(self); |
482 | break; | 491 | break; |
483 | case NEWT_KEY_END: { | 492 | case NEWT_KEY_END: |
484 | struct list_head *head = self->entries; | ||
485 | offset = self->height - 1; | 493 | offset = self->height - 1; |
486 | 494 | ||
487 | if (offset > self->nr_entries) | 495 | if (offset > self->nr_entries) |
488 | offset = self->nr_entries; | 496 | offset = self->nr_entries; |
489 | 497 | ||
490 | self->index = self->first_visible_entry_idx = self->nr_entries - 1 - offset; | 498 | self->index = self->first_visible_entry_idx = self->nr_entries - 1 - offset; |
491 | self->first_visible_entry = head->prev; | 499 | self->seek(self, -offset, SEEK_END); |
492 | while (offset-- != 0) { | ||
493 | struct list_head *pos = self->first_visible_entry; | ||
494 | self->first_visible_entry = pos->prev; | ||
495 | } | ||
496 | } | ||
497 | break; | 500 | break; |
498 | case NEWT_KEY_RIGHT: | 501 | case NEWT_KEY_RIGHT: |
499 | case NEWT_KEY_LEFT: | 502 | case NEWT_KEY_LEFT: |
@@ -550,6 +553,31 @@ static char *callchain_list__sym_name(struct callchain_list *self, | |||
550 | return bf; | 553 | return bf; |
551 | } | 554 | } |
552 | 555 | ||
556 | static unsigned int hist_entry__annotate_browser_refresh(struct ui_browser *self) | ||
557 | { | ||
558 | struct objdump_line *pos; | ||
559 | struct list_head *head = self->entries; | ||
560 | struct hist_entry *he = self->priv; | ||
561 | int row = 0; | ||
562 | int len = he->ms.sym->end - he->ms.sym->start; | ||
563 | |||
564 | if (self->first_visible_entry == NULL || self->first_visible_entry == self->entries) | ||
565 | self->first_visible_entry = head->next; | ||
566 | |||
567 | pos = list_entry(self->first_visible_entry, struct objdump_line, node); | ||
568 | |||
569 | list_for_each_entry_from(pos, head, node) { | ||
570 | bool current_entry = ui_browser__is_current_entry(self, row); | ||
571 | SLsmg_gotorc(self->top + row, self->left); | ||
572 | objdump_line__show(pos, head, self->width, | ||
573 | he, len, current_entry); | ||
574 | if (++row == self->height) | ||
575 | break; | ||
576 | } | ||
577 | |||
578 | return row; | ||
579 | } | ||
580 | |||
553 | static void __callchain__append_graph_browser(struct callchain_node *self, | 581 | static void __callchain__append_graph_browser(struct callchain_node *self, |
554 | newtComponent tree, u64 total, | 582 | newtComponent tree, u64 total, |
555 | int *indexes, int depth) | 583 | int *indexes, int depth) |
@@ -712,7 +740,9 @@ int hist_entry__tui_annotate(struct hist_entry *self) | |||
712 | ui_helpline__push("Press <- or ESC to exit"); | 740 | ui_helpline__push("Press <- or ESC to exit"); |
713 | 741 | ||
714 | memset(&browser, 0, sizeof(browser)); | 742 | memset(&browser, 0, sizeof(browser)); |
715 | browser.entries = &head; | 743 | browser.entries = &head; |
744 | browser.refresh_entries = hist_entry__annotate_browser_refresh; | ||
745 | browser.seek = ui_browser__list_head_seek; | ||
716 | browser.priv = self; | 746 | browser.priv = self; |
717 | list_for_each_entry(pos, &head, node) { | 747 | list_for_each_entry(pos, &head, node) { |
718 | size_t line_len = strlen(pos->line); | 748 | size_t line_len = strlen(pos->line); |
@@ -722,7 +752,8 @@ int hist_entry__tui_annotate(struct hist_entry *self) | |||
722 | } | 752 | } |
723 | 753 | ||
724 | browser.width += 18; /* Percentage */ | 754 | browser.width += 18; /* Percentage */ |
725 | ret = ui_browser__run(&browser, self->ms.sym->name, &es); | 755 | ui_browser__show(&browser, self->ms.sym->name); |
756 | ui_browser__run(&browser, &es); | ||
726 | newtFormDestroy(browser.form); | 757 | newtFormDestroy(browser.form); |
727 | newtPopWindow(); | 758 | newtPopWindow(); |
728 | list_for_each_entry_safe(pos, n, &head, node) { | 759 | list_for_each_entry_safe(pos, n, &head, node) { |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 9bf0f402ca73..4af5bd59cfd1 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -602,8 +602,15 @@ parse_breakpoint_event(const char **strp, struct perf_event_attr *attr) | |||
602 | return EVT_FAILED; | 602 | return EVT_FAILED; |
603 | } | 603 | } |
604 | 604 | ||
605 | /* We should find a nice way to override the access type */ | 605 | /* |
606 | attr->bp_len = HW_BREAKPOINT_LEN_4; | 606 | * We should find a nice way to override the access length |
607 | * Provide some defaults for now | ||
608 | */ | ||
609 | if (attr->bp_type == HW_BREAKPOINT_X) | ||
610 | attr->bp_len = sizeof(long); | ||
611 | else | ||
612 | attr->bp_len = HW_BREAKPOINT_LEN_4; | ||
613 | |||
607 | attr->type = PERF_TYPE_BREAKPOINT; | 614 | attr->type = PERF_TYPE_BREAKPOINT; |
608 | 615 | ||
609 | return EVT_HANDLED; | 616 | return EVT_HANDLED; |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index d964cb199c67..baf665383498 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include "event.h" | 37 | #include "event.h" |
38 | #include "debug.h" | 38 | #include "debug.h" |
39 | #include "util.h" | 39 | #include "util.h" |
40 | #include "symbol.h" | ||
40 | #include "probe-finder.h" | 41 | #include "probe-finder.h" |
41 | 42 | ||
42 | /* Kprobe tracer basic type is up to u64 */ | 43 | /* Kprobe tracer basic type is up to u64 */ |
@@ -57,6 +58,55 @@ static int strtailcmp(const char *s1, const char *s2) | |||
57 | return 0; | 58 | return 0; |
58 | } | 59 | } |
59 | 60 | ||
61 | /* | ||
62 | * Find a src file from a DWARF tag path. Prepend optional source path prefix | ||
63 | * and chop off leading directories that do not exist. Result is passed back as | ||
64 | * a newly allocated path on success. | ||
65 | * Return 0 if file was found and readable, -errno otherwise. | ||
66 | */ | ||
67 | static int get_real_path(const char *raw_path, char **new_path) | ||
68 | { | ||
69 | if (!symbol_conf.source_prefix) { | ||
70 | if (access(raw_path, R_OK) == 0) { | ||
71 | *new_path = strdup(raw_path); | ||
72 | return 0; | ||
73 | } else | ||
74 | return -errno; | ||
75 | } | ||
76 | |||
77 | *new_path = malloc((strlen(symbol_conf.source_prefix) + | ||
78 | strlen(raw_path) + 2)); | ||
79 | if (!*new_path) | ||
80 | return -ENOMEM; | ||
81 | |||
82 | for (;;) { | ||
83 | sprintf(*new_path, "%s/%s", symbol_conf.source_prefix, | ||
84 | raw_path); | ||
85 | |||
86 | if (access(*new_path, R_OK) == 0) | ||
87 | return 0; | ||
88 | |||
89 | switch (errno) { | ||
90 | case ENAMETOOLONG: | ||
91 | case ENOENT: | ||
92 | case EROFS: | ||
93 | case EFAULT: | ||
94 | raw_path = strchr(++raw_path, '/'); | ||
95 | if (!raw_path) { | ||
96 | free(*new_path); | ||
97 | *new_path = NULL; | ||
98 | return -ENOENT; | ||
99 | } | ||
100 | continue; | ||
101 | |||
102 | default: | ||
103 | free(*new_path); | ||
104 | *new_path = NULL; | ||
105 | return -errno; | ||
106 | } | ||
107 | } | ||
108 | } | ||
109 | |||
60 | /* Line number list operations */ | 110 | /* Line number list operations */ |
61 | 111 | ||
62 | /* Add a line to line number list */ | 112 | /* Add a line to line number list */ |
@@ -1096,11 +1146,13 @@ end: | |||
1096 | static int line_range_add_line(const char *src, unsigned int lineno, | 1146 | static int line_range_add_line(const char *src, unsigned int lineno, |
1097 | struct line_range *lr) | 1147 | struct line_range *lr) |
1098 | { | 1148 | { |
1149 | int ret; | ||
1150 | |||
1099 | /* Copy real path */ | 1151 | /* Copy real path */ |
1100 | if (!lr->path) { | 1152 | if (!lr->path) { |
1101 | lr->path = strdup(src); | 1153 | ret = get_real_path(src, &lr->path); |
1102 | if (lr->path == NULL) | 1154 | if (ret != 0) |
1103 | return -ENOMEM; | 1155 | return ret; |
1104 | } | 1156 | } |
1105 | return line_list__add_line(&lr->line_list, lineno); | 1157 | return line_list__add_line(&lr->line_list, lineno); |
1106 | } | 1158 | } |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index c422cd676313..030791870e33 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -27,8 +27,10 @@ static int perf_session__open(struct perf_session *self, bool force) | |||
27 | 27 | ||
28 | self->fd = open(self->filename, O_RDONLY); | 28 | self->fd = open(self->filename, O_RDONLY); |
29 | if (self->fd < 0) { | 29 | if (self->fd < 0) { |
30 | pr_err("failed to open file: %s", self->filename); | 30 | int err = errno; |
31 | if (!strcmp(self->filename, "perf.data")) | 31 | |
32 | pr_err("failed to open %s: %s", self->filename, strerror(err)); | ||
33 | if (err == ENOENT && !strcmp(self->filename, "perf.data")) | ||
32 | pr_err(" (try 'perf record' first)"); | 34 | pr_err(" (try 'perf record' first)"); |
33 | pr_err("\n"); | 35 | pr_err("\n"); |
34 | return -errno; | 36 | return -errno; |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 2316cb5a4116..c27b4b03fbc1 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -13,6 +13,7 @@ enum sort_type sort__first_dimension; | |||
13 | unsigned int dsos__col_width; | 13 | unsigned int dsos__col_width; |
14 | unsigned int comms__col_width; | 14 | unsigned int comms__col_width; |
15 | unsigned int threads__col_width; | 15 | unsigned int threads__col_width; |
16 | unsigned int cpus__col_width; | ||
16 | static unsigned int parent_symbol__col_width; | 17 | static unsigned int parent_symbol__col_width; |
17 | char * field_sep; | 18 | char * field_sep; |
18 | 19 | ||
@@ -28,6 +29,8 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, | |||
28 | size_t size, unsigned int width); | 29 | size_t size, unsigned int width); |
29 | static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf, | 30 | static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf, |
30 | size_t size, unsigned int width); | 31 | size_t size, unsigned int width); |
32 | static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf, | ||
33 | size_t size, unsigned int width); | ||
31 | 34 | ||
32 | struct sort_entry sort_thread = { | 35 | struct sort_entry sort_thread = { |
33 | .se_header = "Command: Pid", | 36 | .se_header = "Command: Pid", |
@@ -63,6 +66,13 @@ struct sort_entry sort_parent = { | |||
63 | .se_snprintf = hist_entry__parent_snprintf, | 66 | .se_snprintf = hist_entry__parent_snprintf, |
64 | .se_width = &parent_symbol__col_width, | 67 | .se_width = &parent_symbol__col_width, |
65 | }; | 68 | }; |
69 | |||
70 | struct sort_entry sort_cpu = { | ||
71 | .se_header = "CPU", | ||
72 | .se_cmp = sort__cpu_cmp, | ||
73 | .se_snprintf = hist_entry__cpu_snprintf, | ||
74 | .se_width = &cpus__col_width, | ||
75 | }; | ||
66 | 76 | ||
67 | struct sort_dimension { | 77 | struct sort_dimension { |
68 | const char *name; | 78 | const char *name; |
@@ -76,6 +86,7 @@ static struct sort_dimension sort_dimensions[] = { | |||
76 | { .name = "dso", .entry = &sort_dso, }, | 86 | { .name = "dso", .entry = &sort_dso, }, |
77 | { .name = "symbol", .entry = &sort_sym, }, | 87 | { .name = "symbol", .entry = &sort_sym, }, |
78 | { .name = "parent", .entry = &sort_parent, }, | 88 | { .name = "parent", .entry = &sort_parent, }, |
89 | { .name = "cpu", .entry = &sort_cpu, }, | ||
79 | }; | 90 | }; |
80 | 91 | ||
81 | int64_t cmp_null(void *l, void *r) | 92 | int64_t cmp_null(void *l, void *r) |
@@ -242,6 +253,20 @@ static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf, | |||
242 | self->parent ? self->parent->name : "[other]"); | 253 | self->parent ? self->parent->name : "[other]"); |
243 | } | 254 | } |
244 | 255 | ||
256 | /* --sort cpu */ | ||
257 | |||
258 | int64_t | ||
259 | sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right) | ||
260 | { | ||
261 | return right->cpu - left->cpu; | ||
262 | } | ||
263 | |||
264 | static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf, | ||
265 | size_t size, unsigned int width) | ||
266 | { | ||
267 | return repsep_snprintf(bf, size, "%-*d", width, self->cpu); | ||
268 | } | ||
269 | |||
245 | int sort_dimension__add(const char *tok) | 270 | int sort_dimension__add(const char *tok) |
246 | { | 271 | { |
247 | unsigned int i; | 272 | unsigned int i; |
@@ -281,6 +306,8 @@ int sort_dimension__add(const char *tok) | |||
281 | sort__first_dimension = SORT_SYM; | 306 | sort__first_dimension = SORT_SYM; |
282 | else if (!strcmp(sd->name, "parent")) | 307 | else if (!strcmp(sd->name, "parent")) |
283 | sort__first_dimension = SORT_PARENT; | 308 | sort__first_dimension = SORT_PARENT; |
309 | else if (!strcmp(sd->name, "cpu")) | ||
310 | sort__first_dimension = SORT_CPU; | ||
284 | } | 311 | } |
285 | 312 | ||
286 | list_add_tail(&sd->entry->list, &hist_entry__sort_list); | 313 | list_add_tail(&sd->entry->list, &hist_entry__sort_list); |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 0d61c4082f43..560c855417e4 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -39,6 +39,7 @@ extern struct sort_entry sort_parent; | |||
39 | extern unsigned int dsos__col_width; | 39 | extern unsigned int dsos__col_width; |
40 | extern unsigned int comms__col_width; | 40 | extern unsigned int comms__col_width; |
41 | extern unsigned int threads__col_width; | 41 | extern unsigned int threads__col_width; |
42 | extern unsigned int cpus__col_width; | ||
42 | extern enum sort_type sort__first_dimension; | 43 | extern enum sort_type sort__first_dimension; |
43 | 44 | ||
44 | struct hist_entry { | 45 | struct hist_entry { |
@@ -51,6 +52,7 @@ struct hist_entry { | |||
51 | struct map_symbol ms; | 52 | struct map_symbol ms; |
52 | struct thread *thread; | 53 | struct thread *thread; |
53 | u64 ip; | 54 | u64 ip; |
55 | s32 cpu; | ||
54 | u32 nr_events; | 56 | u32 nr_events; |
55 | char level; | 57 | char level; |
56 | u8 filtered; | 58 | u8 filtered; |
@@ -68,7 +70,8 @@ enum sort_type { | |||
68 | SORT_COMM, | 70 | SORT_COMM, |
69 | SORT_DSO, | 71 | SORT_DSO, |
70 | SORT_SYM, | 72 | SORT_SYM, |
71 | SORT_PARENT | 73 | SORT_PARENT, |
74 | SORT_CPU, | ||
72 | }; | 75 | }; |
73 | 76 | ||
74 | /* | 77 | /* |
@@ -104,6 +107,7 @@ extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *); | |||
104 | extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *); | 107 | extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *); |
105 | extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *); | 108 | extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *); |
106 | extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *); | 109 | extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *); |
110 | int64_t sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right); | ||
107 | extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int); | 111 | extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int); |
108 | extern int sort_dimension__add(const char *); | 112 | extern int sort_dimension__add(const char *); |
109 | void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, | 113 | void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b63e5713849f..971d0a05d6b4 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -933,6 +933,25 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type | |||
933 | } | 933 | } |
934 | } | 934 | } |
935 | 935 | ||
936 | static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) | ||
937 | { | ||
938 | Elf_Scn *sec = NULL; | ||
939 | GElf_Shdr shdr; | ||
940 | size_t cnt = 1; | ||
941 | |||
942 | while ((sec = elf_nextscn(elf, sec)) != NULL) { | ||
943 | gelf_getshdr(sec, &shdr); | ||
944 | |||
945 | if ((addr >= shdr.sh_addr) && | ||
946 | (addr < (shdr.sh_addr + shdr.sh_size))) | ||
947 | return cnt; | ||
948 | |||
949 | ++cnt; | ||
950 | } | ||
951 | |||
952 | return -1; | ||
953 | } | ||
954 | |||
936 | static int dso__load_sym(struct dso *self, struct map *map, const char *name, | 955 | static int dso__load_sym(struct dso *self, struct map *map, const char *name, |
937 | int fd, symbol_filter_t filter, int kmodule) | 956 | int fd, symbol_filter_t filter, int kmodule) |
938 | { | 957 | { |
@@ -944,12 +963,13 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
944 | int err = -1; | 963 | int err = -1; |
945 | uint32_t idx; | 964 | uint32_t idx; |
946 | GElf_Ehdr ehdr; | 965 | GElf_Ehdr ehdr; |
947 | GElf_Shdr shdr; | 966 | GElf_Shdr shdr, opdshdr; |
948 | Elf_Data *syms; | 967 | Elf_Data *syms, *opddata = NULL; |
949 | GElf_Sym sym; | 968 | GElf_Sym sym; |
950 | Elf_Scn *sec, *sec_strndx; | 969 | Elf_Scn *sec, *sec_strndx, *opdsec; |
951 | Elf *elf; | 970 | Elf *elf; |
952 | int nr = 0; | 971 | int nr = 0; |
972 | size_t opdidx = 0; | ||
953 | 973 | ||
954 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | 974 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); |
955 | if (elf == NULL) { | 975 | if (elf == NULL) { |
@@ -969,6 +989,10 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
969 | goto out_elf_end; | 989 | goto out_elf_end; |
970 | } | 990 | } |
971 | 991 | ||
992 | opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); | ||
993 | if (opdsec) | ||
994 | opddata = elf_rawdata(opdsec, NULL); | ||
995 | |||
972 | syms = elf_getdata(sec, NULL); | 996 | syms = elf_getdata(sec, NULL); |
973 | if (syms == NULL) | 997 | if (syms == NULL) |
974 | goto out_elf_end; | 998 | goto out_elf_end; |
@@ -1013,6 +1037,13 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
1013 | if (!is_label && !elf_sym__is_a(&sym, map->type)) | 1037 | if (!is_label && !elf_sym__is_a(&sym, map->type)) |
1014 | continue; | 1038 | continue; |
1015 | 1039 | ||
1040 | if (opdsec && sym.st_shndx == opdidx) { | ||
1041 | u32 offset = sym.st_value - opdshdr.sh_addr; | ||
1042 | u64 *opd = opddata->d_buf + offset; | ||
1043 | sym.st_value = *opd; | ||
1044 | sym.st_shndx = elf_addr_to_index(elf, sym.st_value); | ||
1045 | } | ||
1046 | |||
1016 | sec = elf_getscn(elf, sym.st_shndx); | 1047 | sec = elf_getscn(elf, sym.st_shndx); |
1017 | if (!sec) | 1048 | if (!sec) |
1018 | goto out_elf_end; | 1049 | goto out_elf_end; |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 5e02d2c17154..80e569bbdecc 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -9,8 +9,6 @@ | |||
9 | #include <linux/rbtree.h> | 9 | #include <linux/rbtree.h> |
10 | #include <stdio.h> | 10 | #include <stdio.h> |
11 | 11 | ||
12 | #define DEBUG_CACHE_DIR ".debug" | ||
13 | |||
14 | #ifdef HAVE_CPLUS_DEMANGLE | 12 | #ifdef HAVE_CPLUS_DEMANGLE |
15 | extern char *cplus_demangle(const char *, int); | 13 | extern char *cplus_demangle(const char *, int); |
16 | 14 | ||
@@ -73,6 +71,7 @@ struct symbol_conf { | |||
73 | full_paths, | 71 | full_paths, |
74 | show_cpu_utilization; | 72 | show_cpu_utilization; |
75 | const char *vmlinux_name, | 73 | const char *vmlinux_name, |
74 | *source_prefix, | ||
76 | *field_sep; | 75 | *field_sep; |
77 | const char *default_guest_vmlinux_name, | 76 | const char *default_guest_vmlinux_name, |
78 | *default_guest_kallsyms, | 77 | *default_guest_kallsyms, |
@@ -112,7 +111,8 @@ struct addr_location { | |||
112 | u64 addr; | 111 | u64 addr; |
113 | char level; | 112 | char level; |
114 | bool filtered; | 113 | bool filtered; |
115 | unsigned int cpumode; | 114 | u8 cpumode; |
115 | s32 cpu; | ||
116 | }; | 116 | }; |
117 | 117 | ||
118 | enum dso_kernel_type { | 118 | enum dso_kernel_type { |
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 4e8b6b0c551c..f380fed74359 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -89,6 +89,7 @@ | |||
89 | 89 | ||
90 | extern const char *graph_line; | 90 | extern const char *graph_line; |
91 | extern const char *graph_dotted_line; | 91 | extern const char *graph_dotted_line; |
92 | extern char buildid_dir[]; | ||
92 | 93 | ||
93 | /* On most systems <limits.h> would have given us this, but | 94 | /* On most systems <limits.h> would have given us this, but |
94 | * not on some systems (e.g. GNU/Hurd). | 95 | * not on some systems (e.g. GNU/Hurd). |
@@ -152,6 +153,8 @@ extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2))) | |||
152 | extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN); | 153 | extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN); |
153 | 154 | ||
154 | extern int prefixcmp(const char *str, const char *prefix); | 155 | extern int prefixcmp(const char *str, const char *prefix); |
156 | extern void set_buildid_dir(void); | ||
157 | extern void disable_buildid_cache(void); | ||
155 | 158 | ||
156 | static inline const char *skip_prefix(const char *str, const char *prefix) | 159 | static inline const char *skip_prefix(const char *str, const char *prefix) |
157 | { | 160 | { |