diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/Documentation/perf-record.txt | 60 | ||||
-rw-r--r-- | tools/perf/Makefile | 29 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 4 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 85 |
4 files changed, 167 insertions, 11 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 1dbc1eeb4c01..6be696b0a2bb 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -29,13 +29,67 @@ OPTIONS | |||
29 | Select the PMU event. Selection can be a symbolic event name | 29 | Select the PMU event. Selection can be a symbolic event name |
30 | (use 'perf list' to list all events) or a raw PMU | 30 | (use 'perf list' to list all events) or a raw PMU |
31 | event (eventsel+umask) in the form of rNNN where NNN is a | 31 | event (eventsel+umask) in the form of rNNN where NNN is a |
32 | hexadecimal event descriptor. | 32 | hexadecimal event descriptor. |
33 | 33 | ||
34 | -a:: | 34 | -a:: |
35 | system-wide collection | 35 | System-wide collection. |
36 | 36 | ||
37 | -l:: | 37 | -l:: |
38 | scale counter values | 38 | Scale counter values. |
39 | |||
40 | -p:: | ||
41 | --pid=:: | ||
42 | Record events on existing pid. | ||
43 | |||
44 | -r:: | ||
45 | --realtime=:: | ||
46 | Collect data with this RT SCHED_FIFO priority. | ||
47 | -A:: | ||
48 | --append:: | ||
49 | Append to the output file to do incremental profiling. | ||
50 | |||
51 | -f:: | ||
52 | --force:: | ||
53 | Overwrite existing data file. | ||
54 | |||
55 | -c:: | ||
56 | --count=:: | ||
57 | Event period to sample. | ||
58 | |||
59 | -o:: | ||
60 | --output=:: | ||
61 | Output file name. | ||
62 | |||
63 | -i:: | ||
64 | --inherit:: | ||
65 | Child tasks inherit counters. | ||
66 | -F:: | ||
67 | --freq=:: | ||
68 | Profile at this frequency. | ||
69 | |||
70 | -m:: | ||
71 | --mmap-pages=:: | ||
72 | Number of mmap data pages. | ||
73 | |||
74 | -g:: | ||
75 | --call-graph:: | ||
76 | Do call-graph (stack chain/backtrace) recording. | ||
77 | |||
78 | -v:: | ||
79 | --verbose:: | ||
80 | Be more verbose (show counter open errors, etc). | ||
81 | |||
82 | -s:: | ||
83 | --stat:: | ||
84 | Per thread counts. | ||
85 | |||
86 | -d:: | ||
87 | --data:: | ||
88 | Sample addresses. | ||
89 | |||
90 | -n:: | ||
91 | --no-samples:: | ||
92 | Don't sample. | ||
39 | 93 | ||
40 | SEE ALSO | 94 | SEE ALSO |
41 | -------- | 95 | -------- |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 4b20fa47c3ab..1916e44b9bb0 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -158,8 +158,10 @@ uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not') | |||
158 | uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not') | 158 | uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not') |
159 | 159 | ||
160 | # If we're on a 64-bit kernel, use -m64 | 160 | # If we're on a 64-bit kernel, use -m64 |
161 | ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M)) | 161 | ifndef NO_64BIT |
162 | M64 := -m64 | 162 | ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M)) |
163 | M64 := -m64 | ||
164 | endif | ||
163 | endif | 165 | endif |
164 | 166 | ||
165 | # CFLAGS and LDFLAGS are for the users to override from the command line. | 167 | # CFLAGS and LDFLAGS are for the users to override from the command line. |
@@ -345,7 +347,6 @@ BUILTIN_OBJS += builtin-stat.o | |||
345 | BUILTIN_OBJS += builtin-top.o | 347 | BUILTIN_OBJS += builtin-top.o |
346 | 348 | ||
347 | PERFLIBS = $(LIB_FILE) | 349 | PERFLIBS = $(LIB_FILE) |
348 | EXTLIBS = -lbfd -liberty | ||
349 | 350 | ||
350 | # | 351 | # |
351 | # Platform specific tweaks | 352 | # Platform specific tweaks |
@@ -374,6 +375,28 @@ ifeq ($(uname_S),Darwin) | |||
374 | PTHREAD_LIBS = | 375 | PTHREAD_LIBS = |
375 | endif | 376 | endif |
376 | 377 | ||
378 | 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) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y) | ||
379 | msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel); | ||
380 | endif | ||
381 | |||
382 | ifdef NO_DEMANGLE | ||
383 | BASIC_CFLAGS += -DNO_DEMANGLE | ||
384 | else | ||
385 | |||
386 | 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 /dev/null $(ALL_LDFLAGS) -lbfd > /dev/null 2>&1 && echo y") | ||
387 | |||
388 | 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 /dev/null $(ALL_LDFLAGS) -lbfd -liberty > /dev/null 2>&1 && echo y") | ||
389 | |||
390 | ifeq ($(has_bfd),y) | ||
391 | EXTLIBS += -lbfd | ||
392 | else ifeq ($(has_bfd_iberty),y) | ||
393 | EXTLIBS += -lbfd -liberty | ||
394 | else | ||
395 | msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling) | ||
396 | BASIC_CFLAGS += -DNO_DEMANGLE | ||
397 | endif | ||
398 | endif | ||
399 | |||
377 | ifndef CC_LD_DYNPATH | 400 | ifndef CC_LD_DYNPATH |
378 | ifdef NO_R_TO_GCC_LINKER | 401 | ifdef NO_R_TO_GCC_LINKER |
379 | # Some gcc does not accept and pass -R to the linker to specify | 402 | # Some gcc does not accept and pass -R to the linker to specify |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index ce4f28645e64..8cb58d68a006 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -31,7 +31,7 @@ | |||
31 | static char const *input_name = "perf.data"; | 31 | static char const *input_name = "perf.data"; |
32 | static char *vmlinux = NULL; | 32 | static char *vmlinux = NULL; |
33 | 33 | ||
34 | static char default_sort_order[] = "comm,dso"; | 34 | static char default_sort_order[] = "comm,dso,symbol"; |
35 | static char *sort_order = default_sort_order; | 35 | static char *sort_order = default_sort_order; |
36 | static char *dso_list_str, *comm_list_str, *sym_list_str, | 36 | static char *dso_list_str, *comm_list_str, *sym_list_str, |
37 | *col_width_list_str; | 37 | *col_width_list_str; |
@@ -1424,7 +1424,7 @@ print_entries: | |||
1424 | if (sort_order == default_sort_order && | 1424 | if (sort_order == default_sort_order && |
1425 | parent_pattern == default_parent_pattern) { | 1425 | parent_pattern == default_parent_pattern) { |
1426 | fprintf(fp, "#\n"); | 1426 | fprintf(fp, "#\n"); |
1427 | fprintf(fp, "# (For more details, try: perf report --sort comm,dso,symbol)\n"); | 1427 | fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n"); |
1428 | fprintf(fp, "#\n"); | 1428 | fprintf(fp, "#\n"); |
1429 | } | 1429 | } |
1430 | fprintf(fp, "\n"); | 1430 | fprintf(fp, "\n"); |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b4fe0579bd6b..16ddca202948 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -6,7 +6,16 @@ | |||
6 | #include <libelf.h> | 6 | #include <libelf.h> |
7 | #include <gelf.h> | 7 | #include <gelf.h> |
8 | #include <elf.h> | 8 | #include <elf.h> |
9 | |||
10 | #ifndef NO_DEMANGLE | ||
9 | #include <bfd.h> | 11 | #include <bfd.h> |
12 | #else | ||
13 | static inline | ||
14 | char *bfd_demangle(void __used *v, const char __used *c, int __used i) | ||
15 | { | ||
16 | return NULL; | ||
17 | } | ||
18 | #endif | ||
10 | 19 | ||
11 | const char *sym_hist_filter; | 20 | const char *sym_hist_filter; |
12 | 21 | ||
@@ -652,10 +661,69 @@ out_close: | |||
652 | return err; | 661 | return err; |
653 | } | 662 | } |
654 | 663 | ||
664 | #define BUILD_ID_SIZE 128 | ||
665 | |||
666 | static char *dso__read_build_id(struct dso *self, int verbose) | ||
667 | { | ||
668 | int i; | ||
669 | GElf_Ehdr ehdr; | ||
670 | GElf_Shdr shdr; | ||
671 | Elf_Data *build_id_data; | ||
672 | Elf_Scn *sec; | ||
673 | char *build_id = NULL, *bid; | ||
674 | unsigned char *raw; | ||
675 | Elf *elf; | ||
676 | int fd = open(self->name, O_RDONLY); | ||
677 | |||
678 | if (fd < 0) | ||
679 | goto out; | ||
680 | |||
681 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); | ||
682 | if (elf == NULL) { | ||
683 | if (verbose) | ||
684 | fprintf(stderr, "%s: cannot read %s ELF file.\n", | ||
685 | __func__, self->name); | ||
686 | goto out_close; | ||
687 | } | ||
688 | |||
689 | if (gelf_getehdr(elf, &ehdr) == NULL) { | ||
690 | if (verbose) | ||
691 | fprintf(stderr, "%s: cannot get elf header.\n", __func__); | ||
692 | goto out_elf_end; | ||
693 | } | ||
694 | |||
695 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL); | ||
696 | if (sec == NULL) | ||
697 | goto out_elf_end; | ||
698 | |||
699 | build_id_data = elf_getdata(sec, NULL); | ||
700 | if (build_id_data == NULL) | ||
701 | goto out_elf_end; | ||
702 | build_id = malloc(BUILD_ID_SIZE); | ||
703 | if (build_id == NULL) | ||
704 | goto out_elf_end; | ||
705 | raw = build_id_data->d_buf + 16; | ||
706 | bid = build_id; | ||
707 | |||
708 | for (i = 0; i < 20; ++i) { | ||
709 | sprintf(bid, "%02x", *raw); | ||
710 | ++raw; | ||
711 | bid += 2; | ||
712 | } | ||
713 | if (verbose) | ||
714 | printf("%s(%s): %s\n", __func__, self->name, build_id); | ||
715 | out_elf_end: | ||
716 | elf_end(elf); | ||
717 | out_close: | ||
718 | close(fd); | ||
719 | out: | ||
720 | return build_id; | ||
721 | } | ||
722 | |||
655 | int dso__load(struct dso *self, symbol_filter_t filter, int verbose) | 723 | int dso__load(struct dso *self, symbol_filter_t filter, int verbose) |
656 | { | 724 | { |
657 | int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug"); | 725 | int size = PATH_MAX; |
658 | char *name = malloc(size); | 726 | char *name = malloc(size), *build_id = NULL; |
659 | int variant = 0; | 727 | int variant = 0; |
660 | int ret = -1; | 728 | int ret = -1; |
661 | int fd; | 729 | int fd; |
@@ -677,7 +745,18 @@ more: | |||
677 | case 1: /* Ubuntu */ | 745 | case 1: /* Ubuntu */ |
678 | snprintf(name, size, "/usr/lib/debug%s", self->name); | 746 | snprintf(name, size, "/usr/lib/debug%s", self->name); |
679 | break; | 747 | break; |
680 | case 2: /* Sane people */ | 748 | case 2: |
749 | build_id = dso__read_build_id(self, verbose); | ||
750 | if (build_id != NULL) { | ||
751 | snprintf(name, size, | ||
752 | "/usr/lib/debug/.build-id/%.2s/%s.debug", | ||
753 | build_id, build_id + 2); | ||
754 | free(build_id); | ||
755 | break; | ||
756 | } | ||
757 | variant++; | ||
758 | /* Fall thru */ | ||
759 | case 3: /* Sane people */ | ||
681 | snprintf(name, size, "%s", self->name); | 760 | snprintf(name, size, "%s", self->name); |
682 | break; | 761 | break; |
683 | 762 | ||