diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-26 18:09:33 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-26 18:09:33 -0400 |
| commit | 6fa41366c1c5e8b9640baba22d2b90ec9035a889 (patch) | |
| tree | ad3b2214e0c5d4774f200ab7bb08b832babb9468 | |
| parent | 309d1dcb5b73ab1f8212aff3037a7bcb46afe819 (diff) | |
| parent | 9eff26ea48bfbe2885b158742a7512a097ec911b (diff) | |
Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
powerpc/perf_events: Fix call-graph recording, add perf_arch_fetch_caller_regs
perf top: Add missing initialization to zero
perf probe: Use original address instead of CU-based address
perf probe: Fix offset to allow signed value
perf top: Improve the autosizing of column lenghts
perf probe: Fix need_dwarf flag if lazy matching is used
perf probe: Fix probe_point buffer overrun
| -rw-r--r-- | arch/powerpc/include/asm/asm-compat.h | 2 | ||||
| -rw-r--r-- | arch/powerpc/kernel/misc.S | 28 | ||||
| -rw-r--r-- | tools/perf/builtin-probe.c | 1 | ||||
| -rw-r--r-- | tools/perf/builtin-top.c | 13 | ||||
| -rw-r--r-- | tools/perf/util/probe-event.c | 2 | ||||
| -rw-r--r-- | tools/perf/util/probe-finder.c | 18 | ||||
| -rw-r--r-- | tools/perf/util/probe-finder.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/symbol.c | 18 | ||||
| -rw-r--r-- | tools/perf/util/symbol.h | 3 |
9 files changed, 62 insertions, 24 deletions
diff --git a/arch/powerpc/include/asm/asm-compat.h b/arch/powerpc/include/asm/asm-compat.h index c1b475a941eb..a9b91ed3d4b9 100644 --- a/arch/powerpc/include/asm/asm-compat.h +++ b/arch/powerpc/include/asm/asm-compat.h | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #define PPC_LLARX(t, a, b, eh) PPC_LDARX(t, a, b, eh) | 28 | #define PPC_LLARX(t, a, b, eh) PPC_LDARX(t, a, b, eh) |
| 29 | #define PPC_STLCX stringify_in_c(stdcx.) | 29 | #define PPC_STLCX stringify_in_c(stdcx.) |
| 30 | #define PPC_CNTLZL stringify_in_c(cntlzd) | 30 | #define PPC_CNTLZL stringify_in_c(cntlzd) |
| 31 | #define PPC_LR_STKOFF 16 | ||
| 31 | 32 | ||
| 32 | /* Move to CR, single-entry optimized version. Only available | 33 | /* Move to CR, single-entry optimized version. Only available |
| 33 | * on POWER4 and later. | 34 | * on POWER4 and later. |
| @@ -51,6 +52,7 @@ | |||
| 51 | #define PPC_STLCX stringify_in_c(stwcx.) | 52 | #define PPC_STLCX stringify_in_c(stwcx.) |
| 52 | #define PPC_CNTLZL stringify_in_c(cntlzw) | 53 | #define PPC_CNTLZL stringify_in_c(cntlzw) |
| 53 | #define PPC_MTOCRF stringify_in_c(mtcrf) | 54 | #define PPC_MTOCRF stringify_in_c(mtcrf) |
| 55 | #define PPC_LR_STKOFF 4 | ||
| 54 | 56 | ||
| 55 | #endif | 57 | #endif |
| 56 | 58 | ||
diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S index 2d29752cbe16..b485a87c94e1 100644 --- a/arch/powerpc/kernel/misc.S +++ b/arch/powerpc/kernel/misc.S | |||
| @@ -127,3 +127,31 @@ _GLOBAL(__setup_cpu_power7) | |||
| 127 | _GLOBAL(__restore_cpu_power7) | 127 | _GLOBAL(__restore_cpu_power7) |
| 128 | /* place holder */ | 128 | /* place holder */ |
| 129 | blr | 129 | blr |
| 130 | |||
| 131 | #ifdef CONFIG_EVENT_TRACING | ||
| 132 | /* | ||
| 133 | * Get a minimal set of registers for our caller's nth caller. | ||
| 134 | * r3 = regs pointer, r5 = n. | ||
| 135 | * | ||
| 136 | * We only get R1 (stack pointer), NIP (next instruction pointer) | ||
| 137 | * and LR (link register). These are all we can get in the | ||
| 138 | * general case without doing complicated stack unwinding, but | ||
| 139 | * fortunately they are enough to do a stack backtrace, which | ||
| 140 | * is all we need them for. | ||
| 141 | */ | ||
| 142 | _GLOBAL(perf_arch_fetch_caller_regs) | ||
| 143 | mr r6,r1 | ||
| 144 | cmpwi r5,0 | ||
| 145 | mflr r4 | ||
| 146 | ble 2f | ||
| 147 | mtctr r5 | ||
| 148 | 1: PPC_LL r6,0(r6) | ||
| 149 | bdnz 1b | ||
| 150 | PPC_LL r4,PPC_LR_STKOFF(r6) | ||
| 151 | 2: PPC_LL r7,0(r6) | ||
| 152 | PPC_LL r7,PPC_LR_STKOFF(r7) | ||
| 153 | PPC_STL r6,GPR1-STACK_FRAME_OVERHEAD(r3) | ||
| 154 | PPC_STL r4,_NIP-STACK_FRAME_OVERHEAD(r3) | ||
| 155 | PPC_STL r7,_LINK-STACK_FRAME_OVERHEAD(r3) | ||
| 156 | blr | ||
| 157 | #endif /* CONFIG_EVENT_TRACING */ | ||
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index c30a33592340..152d6c9b1fa4 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
| @@ -47,7 +47,6 @@ | |||
| 47 | #include "util/probe-event.h" | 47 | #include "util/probe-event.h" |
| 48 | 48 | ||
| 49 | #define MAX_PATH_LEN 256 | 49 | #define MAX_PATH_LEN 256 |
| 50 | #define MAX_PROBES 128 | ||
| 51 | 50 | ||
| 52 | /* Session management structure */ | 51 | /* Session management structure */ |
| 53 | static struct { | 52 | static struct { |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 0b719e3dde05..1f529321607e 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -455,7 +455,7 @@ static void print_sym_table(void) | |||
| 455 | struct sym_entry *syme, *n; | 455 | struct sym_entry *syme, *n; |
| 456 | struct rb_root tmp = RB_ROOT; | 456 | struct rb_root tmp = RB_ROOT; |
| 457 | struct rb_node *nd; | 457 | struct rb_node *nd; |
| 458 | int sym_width = 0, dso_width = 0, max_dso_width; | 458 | int sym_width = 0, dso_width = 0, dso_short_width = 0; |
| 459 | const int win_width = winsize.ws_col - 1; | 459 | const int win_width = winsize.ws_col - 1; |
| 460 | 460 | ||
| 461 | samples = userspace_samples = 0; | 461 | samples = userspace_samples = 0; |
| @@ -545,15 +545,20 @@ static void print_sym_table(void) | |||
| 545 | if (syme->map->dso->long_name_len > dso_width) | 545 | if (syme->map->dso->long_name_len > dso_width) |
| 546 | dso_width = syme->map->dso->long_name_len; | 546 | dso_width = syme->map->dso->long_name_len; |
| 547 | 547 | ||
| 548 | if (syme->map->dso->short_name_len > dso_short_width) | ||
| 549 | dso_short_width = syme->map->dso->short_name_len; | ||
| 550 | |||
| 548 | if (syme->name_len > sym_width) | 551 | if (syme->name_len > sym_width) |
| 549 | sym_width = syme->name_len; | 552 | sym_width = syme->name_len; |
| 550 | } | 553 | } |
| 551 | 554 | ||
| 552 | printed = 0; | 555 | printed = 0; |
| 553 | 556 | ||
| 554 | max_dso_width = winsize.ws_col - sym_width - 29; | 557 | if (sym_width + dso_width > winsize.ws_col - 29) { |
| 555 | if (dso_width > max_dso_width) | 558 | dso_width = dso_short_width; |
| 556 | dso_width = max_dso_width; | 559 | if (sym_width + dso_width > winsize.ws_col - 29) |
| 560 | sym_width = winsize.ws_col - dso_width - 29; | ||
| 561 | } | ||
| 557 | putchar('\n'); | 562 | putchar('\n'); |
| 558 | if (nr_counters == 1) | 563 | if (nr_counters == 1) |
| 559 | printf(" samples pcnt"); | 564 | printf(" samples pcnt"); |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 53181dbfe4a8..7c004b6ef24f 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
| @@ -242,7 +242,7 @@ void parse_perf_probe_event(const char *str, struct probe_point *pp, | |||
| 242 | 242 | ||
| 243 | /* Parse probe point */ | 243 | /* Parse probe point */ |
| 244 | parse_perf_probe_probepoint(argv[0], pp); | 244 | parse_perf_probe_probepoint(argv[0], pp); |
| 245 | if (pp->file || pp->line) | 245 | if (pp->file || pp->line || pp->lazy_line) |
| 246 | *need_dwarf = true; | 246 | *need_dwarf = true; |
| 247 | 247 | ||
| 248 | /* Copy arguments and ensure return probe has no C argument */ | 248 | /* Copy arguments and ensure return probe has no C argument */ |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 1e6c65ebbd80..c171a243d05b 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
| @@ -333,8 +333,8 @@ static void show_location(Dwarf_Op *op, struct probe_finder *pf) | |||
| 333 | die("%u exceeds max register number.", regn); | 333 | die("%u exceeds max register number.", regn); |
| 334 | 334 | ||
| 335 | if (deref) | 335 | if (deref) |
| 336 | ret = snprintf(pf->buf, pf->len, " %s=+%ju(%s)", | 336 | ret = snprintf(pf->buf, pf->len, " %s=%+jd(%s)", |
| 337 | pf->var, (uintmax_t)offs, regs); | 337 | pf->var, (intmax_t)offs, regs); |
| 338 | else | 338 | else |
| 339 | ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); | 339 | ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); |
| 340 | DIE_IF(ret < 0); | 340 | DIE_IF(ret < 0); |
| @@ -352,8 +352,7 @@ static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | |||
| 352 | if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) | 352 | if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) |
| 353 | goto error; | 353 | goto error; |
| 354 | /* TODO: handle more than 1 exprs */ | 354 | /* TODO: handle more than 1 exprs */ |
| 355 | ret = dwarf_getlocation_addr(&attr, (pf->addr - pf->cu_base), | 355 | ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1); |
| 356 | &expr, &nexpr, 1); | ||
| 357 | if (ret <= 0 || nexpr == 0) | 356 | if (ret <= 0 || nexpr == 0) |
| 358 | goto error; | 357 | goto error; |
| 359 | 358 | ||
| @@ -437,8 +436,7 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
| 437 | 436 | ||
| 438 | /* Get the frame base attribute/ops */ | 437 | /* Get the frame base attribute/ops */ |
| 439 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); | 438 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); |
| 440 | ret = dwarf_getlocation_addr(&fb_attr, (pf->addr - pf->cu_base), | 439 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); |
| 441 | &pf->fb_ops, &nops, 1); | ||
| 442 | if (ret <= 0 || nops == 0) | 440 | if (ret <= 0 || nops == 0) |
| 443 | pf->fb_ops = NULL; | 441 | pf->fb_ops = NULL; |
| 444 | 442 | ||
| @@ -455,6 +453,9 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
| 455 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ | 453 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ |
| 456 | pf->fb_ops = NULL; | 454 | pf->fb_ops = NULL; |
| 457 | 455 | ||
| 456 | if (pp->found == MAX_PROBES) | ||
| 457 | die("Too many( > %d) probe point found.\n", MAX_PROBES); | ||
| 458 | |||
| 458 | pp->probes[pp->found] = strdup(tmp); | 459 | pp->probes[pp->found] = strdup(tmp); |
| 459 | pp->found++; | 460 | pp->found++; |
| 460 | } | 461 | } |
| @@ -641,7 +642,6 @@ static void find_probe_point_by_func(struct probe_finder *pf) | |||
| 641 | int find_probe_point(int fd, struct probe_point *pp) | 642 | int find_probe_point(int fd, struct probe_point *pp) |
| 642 | { | 643 | { |
| 643 | struct probe_finder pf = {.pp = pp}; | 644 | struct probe_finder pf = {.pp = pp}; |
| 644 | int ret; | ||
| 645 | Dwarf_Off off, noff; | 645 | Dwarf_Off off, noff; |
| 646 | size_t cuhl; | 646 | size_t cuhl; |
| 647 | Dwarf_Die *diep; | 647 | Dwarf_Die *diep; |
| @@ -668,10 +668,6 @@ int find_probe_point(int fd, struct probe_point *pp) | |||
| 668 | pf.fname = NULL; | 668 | pf.fname = NULL; |
| 669 | 669 | ||
| 670 | if (!pp->file || pf.fname) { | 670 | if (!pp->file || pf.fname) { |
| 671 | /* Save CU base address (for frame_base) */ | ||
| 672 | ret = dwarf_lowpc(&pf.cu_die, &pf.cu_base); | ||
| 673 | if (ret != 0) | ||
| 674 | pf.cu_base = 0; | ||
| 675 | if (pp->function) | 671 | if (pp->function) |
| 676 | find_probe_point_by_func(&pf); | 672 | find_probe_point_by_func(&pf); |
| 677 | else if (pp->lazy_line) | 673 | else if (pp->lazy_line) |
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index d1a651793ba6..21f7354397b4 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
| @@ -71,7 +71,6 @@ struct probe_finder { | |||
| 71 | 71 | ||
| 72 | /* For variable searching */ | 72 | /* For variable searching */ |
| 73 | Dwarf_Op *fb_ops; /* Frame base attribute */ | 73 | Dwarf_Op *fb_ops; /* Frame base attribute */ |
| 74 | Dwarf_Addr cu_base; /* Current CU base address */ | ||
| 75 | const char *var; /* Current variable name */ | 74 | const char *var; /* Current variable name */ |
| 76 | char *buf; /* Current output buffer */ | 75 | char *buf; /* Current output buffer */ |
| 77 | int len; /* Length of output buffer */ | 76 | int len; /* Length of output buffer */ |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 323c0aea0a91..c458c4a371d1 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -163,9 +163,17 @@ void dso__set_long_name(struct dso *self, char *name) | |||
| 163 | self->long_name_len = strlen(name); | 163 | self->long_name_len = strlen(name); |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | static void dso__set_short_name(struct dso *self, const char *name) | ||
| 167 | { | ||
| 168 | if (name == NULL) | ||
| 169 | return; | ||
| 170 | self->short_name = name; | ||
| 171 | self->short_name_len = strlen(name); | ||
| 172 | } | ||
| 173 | |||
| 166 | static void dso__set_basename(struct dso *self) | 174 | static void dso__set_basename(struct dso *self) |
| 167 | { | 175 | { |
| 168 | self->short_name = basename(self->long_name); | 176 | dso__set_short_name(self, basename(self->long_name)); |
| 169 | } | 177 | } |
| 170 | 178 | ||
| 171 | struct dso *dso__new(const char *name) | 179 | struct dso *dso__new(const char *name) |
| @@ -176,7 +184,7 @@ struct dso *dso__new(const char *name) | |||
| 176 | int i; | 184 | int i; |
| 177 | strcpy(self->name, name); | 185 | strcpy(self->name, name); |
| 178 | dso__set_long_name(self, self->name); | 186 | dso__set_long_name(self, self->name); |
| 179 | self->short_name = self->name; | 187 | dso__set_short_name(self, self->name); |
| 180 | for (i = 0; i < MAP__NR_TYPES; ++i) | 188 | for (i = 0; i < MAP__NR_TYPES; ++i) |
| 181 | self->symbols[i] = self->symbol_names[i] = RB_ROOT; | 189 | self->symbols[i] = self->symbol_names[i] = RB_ROOT; |
| 182 | self->slen_calculated = 0; | 190 | self->slen_calculated = 0; |
| @@ -897,7 +905,6 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
| 897 | struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; | 905 | struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; |
| 898 | struct map *curr_map = map; | 906 | struct map *curr_map = map; |
| 899 | struct dso *curr_dso = self; | 907 | struct dso *curr_dso = self; |
| 900 | size_t dso_name_len = strlen(self->short_name); | ||
| 901 | Elf_Data *symstrs, *secstrs; | 908 | Elf_Data *symstrs, *secstrs; |
| 902 | uint32_t nr_syms; | 909 | uint32_t nr_syms; |
| 903 | int err = -1; | 910 | int err = -1; |
| @@ -987,7 +994,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
| 987 | char dso_name[PATH_MAX]; | 994 | char dso_name[PATH_MAX]; |
| 988 | 995 | ||
| 989 | if (strcmp(section_name, | 996 | if (strcmp(section_name, |
| 990 | curr_dso->short_name + dso_name_len) == 0) | 997 | (curr_dso->short_name + |
| 998 | self->short_name_len)) == 0) | ||
| 991 | goto new_symbol; | 999 | goto new_symbol; |
| 992 | 1000 | ||
| 993 | if (strcmp(section_name, ".text") == 0) { | 1001 | if (strcmp(section_name, ".text") == 0) { |
| @@ -1782,7 +1790,7 @@ struct dso *dso__new_kernel(const char *name) | |||
| 1782 | struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); | 1790 | struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); |
| 1783 | 1791 | ||
| 1784 | if (self != NULL) { | 1792 | if (self != NULL) { |
| 1785 | self->short_name = "[kernel]"; | 1793 | dso__set_short_name(self, "[kernel]"); |
| 1786 | self->kernel = 1; | 1794 | self->kernel = 1; |
| 1787 | } | 1795 | } |
| 1788 | 1796 | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 280dadd32a08..f30a37428919 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
| @@ -110,9 +110,10 @@ struct dso { | |||
| 110 | u8 sorted_by_name; | 110 | u8 sorted_by_name; |
| 111 | u8 loaded; | 111 | u8 loaded; |
| 112 | u8 build_id[BUILD_ID_SIZE]; | 112 | u8 build_id[BUILD_ID_SIZE]; |
| 113 | u16 long_name_len; | ||
| 114 | const char *short_name; | 113 | const char *short_name; |
| 115 | char *long_name; | 114 | char *long_name; |
| 115 | u16 long_name_len; | ||
| 116 | u16 short_name_len; | ||
| 116 | char name[0]; | 117 | char name[0]; |
| 117 | }; | 118 | }; |
| 118 | 119 | ||
