diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-08-09 06:46:45 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-08-09 06:46:49 -0400 |
commit | e3560336be655c6791316482fe288b119f34c427 (patch) | |
tree | 43ca9a6b489aaa3918b773f78a7eda37458ef0a8 /tools/perf | |
parent | 26528e773ecc74fb1b61b7275f86f761cbb340ec (diff) | |
parent | 7b2aa037e878c939676675969983284a02958ae3 (diff) |
Merge branch 'linus' into tracing/urgent
Merge reason: Merge up to almost-rc6 to pick up latest perfcounters
(on which we'll queue up a dependent fix)
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf')
-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 | 28 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 1 | ||||
-rw-r--r-- | tools/perf/util/quote.c | 2 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 87 |
6 files changed, 189 insertions, 18 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 a5e9b876ca09..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 | ||
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 b20a4b6e31b7..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; |
@@ -99,6 +99,7 @@ struct comm_event { | |||
99 | struct fork_event { | 99 | struct fork_event { |
100 | struct perf_event_header header; | 100 | struct perf_event_header header; |
101 | u32 pid, ppid; | 101 | u32 pid, ppid; |
102 | u32 tid, ptid; | ||
102 | }; | 103 | }; |
103 | 104 | ||
104 | struct lost_event { | 105 | struct lost_event { |
@@ -252,7 +253,7 @@ static int strcommon(const char *pathname) | |||
252 | { | 253 | { |
253 | int n = 0; | 254 | int n = 0; |
254 | 255 | ||
255 | while (pathname[n] == cwd[n] && n < cwdlen) | 256 | while (n < cwdlen && pathname[n] == cwd[n]) |
256 | ++n; | 257 | ++n; |
257 | 258 | ||
258 | return n; | 259 | return n; |
@@ -1423,7 +1424,7 @@ print_entries: | |||
1423 | if (sort_order == default_sort_order && | 1424 | if (sort_order == default_sort_order && |
1424 | parent_pattern == default_parent_pattern) { | 1425 | parent_pattern == default_parent_pattern) { |
1425 | fprintf(fp, "#\n"); | 1426 | fprintf(fp, "#\n"); |
1426 | 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"); |
1427 | fprintf(fp, "#\n"); | 1428 | fprintf(fp, "#\n"); |
1428 | } | 1429 | } |
1429 | fprintf(fp, "\n"); | 1430 | fprintf(fp, "\n"); |
@@ -1608,15 +1609,27 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) | |||
1608 | } | 1609 | } |
1609 | 1610 | ||
1610 | static int | 1611 | static int |
1611 | process_fork_event(event_t *event, unsigned long offset, unsigned long head) | 1612 | process_task_event(event_t *event, unsigned long offset, unsigned long head) |
1612 | { | 1613 | { |
1613 | struct thread *thread = threads__findnew(event->fork.pid); | 1614 | struct thread *thread = threads__findnew(event->fork.pid); |
1614 | struct thread *parent = threads__findnew(event->fork.ppid); | 1615 | struct thread *parent = threads__findnew(event->fork.ppid); |
1615 | 1616 | ||
1616 | dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", | 1617 | dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n", |
1617 | (void *)(offset + head), | 1618 | (void *)(offset + head), |
1618 | (void *)(long)(event->header.size), | 1619 | (void *)(long)(event->header.size), |
1619 | event->fork.pid, event->fork.ppid); | 1620 | event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT", |
1621 | event->fork.pid, event->fork.tid, | ||
1622 | event->fork.ppid, event->fork.ptid); | ||
1623 | |||
1624 | /* | ||
1625 | * A thread clone will have the same PID for both | ||
1626 | * parent and child. | ||
1627 | */ | ||
1628 | if (thread == parent) | ||
1629 | return 0; | ||
1630 | |||
1631 | if (event->header.type == PERF_EVENT_EXIT) | ||
1632 | return 0; | ||
1620 | 1633 | ||
1621 | if (!thread || !parent || thread__fork(thread, parent)) { | 1634 | if (!thread || !parent || thread__fork(thread, parent)) { |
1622 | dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); | 1635 | dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); |
@@ -1706,7 +1719,8 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
1706 | return process_comm_event(event, offset, head); | 1719 | return process_comm_event(event, offset, head); |
1707 | 1720 | ||
1708 | case PERF_EVENT_FORK: | 1721 | case PERF_EVENT_FORK: |
1709 | return process_fork_event(event, offset, head); | 1722 | case PERF_EVENT_EXIT: |
1723 | return process_task_event(event, offset, head); | ||
1710 | 1724 | ||
1711 | case PERF_EVENT_LOST: | 1725 | case PERF_EVENT_LOST: |
1712 | return process_lost_event(event, offset, head); | 1726 | return process_lost_event(event, offset, head); |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c0a423004e15..f139f1ab9333 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -285,6 +285,7 @@ static const char *skip_symbols[] = { | |||
285 | "enter_idle", | 285 | "enter_idle", |
286 | "exit_idle", | 286 | "exit_idle", |
287 | "mwait_idle", | 287 | "mwait_idle", |
288 | "mwait_idle_with_hints", | ||
288 | "ppc64_runlatch_off", | 289 | "ppc64_runlatch_off", |
289 | "pseries_dedicated_idle_sleep", | 290 | "pseries_dedicated_idle_sleep", |
290 | NULL | 291 | NULL |
diff --git a/tools/perf/util/quote.c b/tools/perf/util/quote.c index c6e5dc0dc82f..2726fe40eb5d 100644 --- a/tools/perf/util/quote.c +++ b/tools/perf/util/quote.c | |||
@@ -318,7 +318,7 @@ char *quote_path_relative(const char *in, int len, | |||
318 | strbuf_addch(out, '"'); | 318 | strbuf_addch(out, '"'); |
319 | if (prefix) { | 319 | if (prefix) { |
320 | int off = 0; | 320 | int off = 0; |
321 | while (prefix[off] && off < len && prefix[off] == in[off]) | 321 | while (off < len && prefix[off] && prefix[off] == in[off]) |
322 | if (prefix[off] == '/') { | 322 | if (prefix[off] == '/') { |
323 | prefix += off + 1; | 323 | prefix += off + 1; |
324 | in += off + 1; | 324 | in += off + 1; |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 28106059bf12..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 | ||
@@ -565,7 +574,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
565 | goto out_elf_end; | 574 | goto out_elf_end; |
566 | 575 | ||
567 | secstrs = elf_getdata(sec_strndx, NULL); | 576 | secstrs = elf_getdata(sec_strndx, NULL); |
568 | if (symstrs == NULL) | 577 | if (secstrs == NULL) |
569 | goto out_elf_end; | 578 | goto out_elf_end; |
570 | 579 | ||
571 | nr_syms = shdr.sh_size / shdr.sh_entsize; | 580 | nr_syms = shdr.sh_size / shdr.sh_entsize; |
@@ -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 | ||