diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-20 14:29:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-20 14:29:32 -0400 |
commit | 12e24f34cb0d55efd08c18b2112507d4bf498008 (patch) | |
tree | 83b07be17b8ef45f42360a3b9159b3aaae3fbad4 /tools/perf | |
parent | 1eb51c33b21ffa3fceb634d1d6bcd6488c79bc26 (diff) | |
parent | eadc84cc01e04f9f74ec2de0c9355be035c7b396 (diff) |
Merge branch 'perfcounters-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perfcounters-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (49 commits)
perfcounter: Handle some IO return values
perf_counter: Push perf_sample_data through the swcounter code
perf_counter tools: Define and use our own u64, s64 etc. definitions
perf_counter: Close race in perf_lock_task_context()
perf_counter, x86: Improve interactions with fast-gup
perf_counter: Simplify and fix task migration counting
perf_counter tools: Add a data file header
perf_counter: Update userspace callchain sampling uses
perf_counter: Make callchain samples extensible
perf report: Filter to parent set by default
perf_counter tools: Handle lost events
perf_counter: Add event overlow handling
fs: Provide empty .set_page_dirty() aop for anon inodes
perf_counter: tools: Makefile tweaks for 64-bit powerpc
perf_counter: powerpc: Add processor back-end for MPC7450 family
perf_counter: powerpc: Make powerpc perf_counter code safe for 32-bit kernels
perf_counter: powerpc: Change how processor-specific back-ends get selected
perf_counter: powerpc: Use unsigned long for register and constraint values
perf_counter: powerpc: Enable use of software counters on 32-bit powerpc
perf_counter tools: Add and use isprint()
...
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Makefile | 10 | ||||
-rw-r--r-- | tools/perf/builtin-annotate.c | 262 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 163 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 439 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 308 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 24 | ||||
-rw-r--r-- | tools/perf/perf.h | 7 | ||||
-rw-r--r-- | tools/perf/types.h | 17 | ||||
-rw-r--r-- | tools/perf/util/ctype.c | 17 | ||||
-rw-r--r-- | tools/perf/util/parse-events.c | 14 | ||||
-rw-r--r-- | tools/perf/util/string.c | 2 | ||||
-rw-r--r-- | tools/perf/util/string.h | 4 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 20 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 16 | ||||
-rw-r--r-- | tools/perf/util/util.h | 18 |
15 files changed, 992 insertions, 329 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 0cbd5d6874ec..36d7eef49913 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -157,10 +157,15 @@ uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not') | |||
157 | uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not') | 157 | 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 | ||
161 | ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M)) | ||
162 | M64 := -m64 | ||
163 | endif | ||
164 | |||
160 | # CFLAGS and LDFLAGS are for the users to override from the command line. | 165 | # CFLAGS and LDFLAGS are for the users to override from the command line. |
161 | 166 | ||
162 | CFLAGS = -ggdb3 -Wall -Werror -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -std=gnu99 -Wdeclaration-after-statement -O6 | 167 | CFLAGS = $(M64) -ggdb3 -Wall -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -std=gnu99 -Wdeclaration-after-statement -Werror -O6 |
163 | LDFLAGS = -lpthread -lrt -lelf | 168 | LDFLAGS = -lpthread -lrt -lelf -lm |
164 | ALL_CFLAGS = $(CFLAGS) | 169 | ALL_CFLAGS = $(CFLAGS) |
165 | ALL_LDFLAGS = $(LDFLAGS) | 170 | ALL_LDFLAGS = $(LDFLAGS) |
166 | STRIP ?= strip | 171 | STRIP ?= strip |
@@ -285,6 +290,7 @@ LIB_FILE=libperf.a | |||
285 | 290 | ||
286 | LIB_H += ../../include/linux/perf_counter.h | 291 | LIB_H += ../../include/linux/perf_counter.h |
287 | LIB_H += perf.h | 292 | LIB_H += perf.h |
293 | LIB_H += types.h | ||
288 | LIB_H += util/list.h | 294 | LIB_H += util/list.h |
289 | LIB_H += util/rbtree.h | 295 | LIB_H += util/rbtree.h |
290 | LIB_H += util/levenshtein.h | 296 | LIB_H += util/levenshtein.h |
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index b1ed5f766cb3..7e58e3ad1508 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -25,6 +25,10 @@ | |||
25 | #define SHOW_USER 2 | 25 | #define SHOW_USER 2 |
26 | #define SHOW_HV 4 | 26 | #define SHOW_HV 4 |
27 | 27 | ||
28 | #define MIN_GREEN 0.5 | ||
29 | #define MIN_RED 5.0 | ||
30 | |||
31 | |||
28 | static char const *input_name = "perf.data"; | 32 | static char const *input_name = "perf.data"; |
29 | static char *vmlinux = "vmlinux"; | 33 | static char *vmlinux = "vmlinux"; |
30 | 34 | ||
@@ -39,40 +43,42 @@ static int dump_trace = 0; | |||
39 | 43 | ||
40 | static int verbose; | 44 | static int verbose; |
41 | 45 | ||
46 | static int print_line; | ||
47 | |||
42 | static unsigned long page_size; | 48 | static unsigned long page_size; |
43 | static unsigned long mmap_window = 32; | 49 | static unsigned long mmap_window = 32; |
44 | 50 | ||
45 | struct ip_event { | 51 | struct ip_event { |
46 | struct perf_event_header header; | 52 | struct perf_event_header header; |
47 | __u64 ip; | 53 | u64 ip; |
48 | __u32 pid, tid; | 54 | u32 pid, tid; |
49 | }; | 55 | }; |
50 | 56 | ||
51 | struct mmap_event { | 57 | struct mmap_event { |
52 | struct perf_event_header header; | 58 | struct perf_event_header header; |
53 | __u32 pid, tid; | 59 | u32 pid, tid; |
54 | __u64 start; | 60 | u64 start; |
55 | __u64 len; | 61 | u64 len; |
56 | __u64 pgoff; | 62 | u64 pgoff; |
57 | char filename[PATH_MAX]; | 63 | char filename[PATH_MAX]; |
58 | }; | 64 | }; |
59 | 65 | ||
60 | struct comm_event { | 66 | struct comm_event { |
61 | struct perf_event_header header; | 67 | struct perf_event_header header; |
62 | __u32 pid, tid; | 68 | u32 pid, tid; |
63 | char comm[16]; | 69 | char comm[16]; |
64 | }; | 70 | }; |
65 | 71 | ||
66 | struct fork_event { | 72 | struct fork_event { |
67 | struct perf_event_header header; | 73 | struct perf_event_header header; |
68 | __u32 pid, ppid; | 74 | u32 pid, ppid; |
69 | }; | 75 | }; |
70 | 76 | ||
71 | struct period_event { | 77 | struct period_event { |
72 | struct perf_event_header header; | 78 | struct perf_event_header header; |
73 | __u64 time; | 79 | u64 time; |
74 | __u64 id; | 80 | u64 id; |
75 | __u64 sample_period; | 81 | u64 sample_period; |
76 | }; | 82 | }; |
77 | 83 | ||
78 | typedef union event_union { | 84 | typedef union event_union { |
@@ -84,6 +90,13 @@ typedef union event_union { | |||
84 | struct period_event period; | 90 | struct period_event period; |
85 | } event_t; | 91 | } event_t; |
86 | 92 | ||
93 | |||
94 | struct sym_ext { | ||
95 | struct rb_node node; | ||
96 | double percent; | ||
97 | char *path; | ||
98 | }; | ||
99 | |||
87 | static LIST_HEAD(dsos); | 100 | static LIST_HEAD(dsos); |
88 | static struct dso *kernel_dso; | 101 | static struct dso *kernel_dso; |
89 | static struct dso *vdso; | 102 | static struct dso *vdso; |
@@ -145,7 +158,7 @@ static void dsos__fprintf(FILE *fp) | |||
145 | dso__fprintf(pos, fp); | 158 | dso__fprintf(pos, fp); |
146 | } | 159 | } |
147 | 160 | ||
148 | static struct symbol *vdso__find_symbol(struct dso *dso, __u64 ip) | 161 | static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) |
149 | { | 162 | { |
150 | return dso__find_symbol(kernel_dso, ip); | 163 | return dso__find_symbol(kernel_dso, ip); |
151 | } | 164 | } |
@@ -178,19 +191,19 @@ static int load_kernel(void) | |||
178 | 191 | ||
179 | struct map { | 192 | struct map { |
180 | struct list_head node; | 193 | struct list_head node; |
181 | __u64 start; | 194 | u64 start; |
182 | __u64 end; | 195 | u64 end; |
183 | __u64 pgoff; | 196 | u64 pgoff; |
184 | __u64 (*map_ip)(struct map *, __u64); | 197 | u64 (*map_ip)(struct map *, u64); |
185 | struct dso *dso; | 198 | struct dso *dso; |
186 | }; | 199 | }; |
187 | 200 | ||
188 | static __u64 map__map_ip(struct map *map, __u64 ip) | 201 | static u64 map__map_ip(struct map *map, u64 ip) |
189 | { | 202 | { |
190 | return ip - map->start + map->pgoff; | 203 | return ip - map->start + map->pgoff; |
191 | } | 204 | } |
192 | 205 | ||
193 | static __u64 vdso__map_ip(struct map *map, __u64 ip) | 206 | static u64 vdso__map_ip(struct map *map, u64 ip) |
194 | { | 207 | { |
195 | return ip; | 208 | return ip; |
196 | } | 209 | } |
@@ -373,7 +386,7 @@ static int thread__fork(struct thread *self, struct thread *parent) | |||
373 | return 0; | 386 | return 0; |
374 | } | 387 | } |
375 | 388 | ||
376 | static struct map *thread__find_map(struct thread *self, __u64 ip) | 389 | static struct map *thread__find_map(struct thread *self, u64 ip) |
377 | { | 390 | { |
378 | struct map *pos; | 391 | struct map *pos; |
379 | 392 | ||
@@ -414,7 +427,7 @@ struct hist_entry { | |||
414 | struct map *map; | 427 | struct map *map; |
415 | struct dso *dso; | 428 | struct dso *dso; |
416 | struct symbol *sym; | 429 | struct symbol *sym; |
417 | __u64 ip; | 430 | u64 ip; |
418 | char level; | 431 | char level; |
419 | 432 | ||
420 | uint32_t count; | 433 | uint32_t count; |
@@ -519,7 +532,7 @@ sort__dso_print(FILE *fp, struct hist_entry *self) | |||
519 | if (self->dso) | 532 | if (self->dso) |
520 | return fprintf(fp, "%-25s", self->dso->name); | 533 | return fprintf(fp, "%-25s", self->dso->name); |
521 | 534 | ||
522 | return fprintf(fp, "%016llx ", (__u64)self->ip); | 535 | return fprintf(fp, "%016llx ", (u64)self->ip); |
523 | } | 536 | } |
524 | 537 | ||
525 | static struct sort_entry sort_dso = { | 538 | static struct sort_entry sort_dso = { |
@@ -533,7 +546,7 @@ static struct sort_entry sort_dso = { | |||
533 | static int64_t | 546 | static int64_t |
534 | sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) | 547 | sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) |
535 | { | 548 | { |
536 | __u64 ip_l, ip_r; | 549 | u64 ip_l, ip_r; |
537 | 550 | ||
538 | if (left->sym == right->sym) | 551 | if (left->sym == right->sym) |
539 | return 0; | 552 | return 0; |
@@ -550,13 +563,13 @@ sort__sym_print(FILE *fp, struct hist_entry *self) | |||
550 | size_t ret = 0; | 563 | size_t ret = 0; |
551 | 564 | ||
552 | if (verbose) | 565 | if (verbose) |
553 | ret += fprintf(fp, "%#018llx ", (__u64)self->ip); | 566 | ret += fprintf(fp, "%#018llx ", (u64)self->ip); |
554 | 567 | ||
555 | if (self->sym) { | 568 | if (self->sym) { |
556 | ret += fprintf(fp, "[%c] %s", | 569 | ret += fprintf(fp, "[%c] %s", |
557 | self->dso == kernel_dso ? 'k' : '.', self->sym->name); | 570 | self->dso == kernel_dso ? 'k' : '.', self->sym->name); |
558 | } else { | 571 | } else { |
559 | ret += fprintf(fp, "%#016llx", (__u64)self->ip); | 572 | ret += fprintf(fp, "%#016llx", (u64)self->ip); |
560 | } | 573 | } |
561 | 574 | ||
562 | return ret; | 575 | return ret; |
@@ -647,7 +660,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) | |||
647 | /* | 660 | /* |
648 | * collect histogram counts | 661 | * collect histogram counts |
649 | */ | 662 | */ |
650 | static void hist_hit(struct hist_entry *he, __u64 ip) | 663 | static void hist_hit(struct hist_entry *he, u64 ip) |
651 | { | 664 | { |
652 | unsigned int sym_size, offset; | 665 | unsigned int sym_size, offset; |
653 | struct symbol *sym = he->sym; | 666 | struct symbol *sym = he->sym; |
@@ -676,7 +689,7 @@ static void hist_hit(struct hist_entry *he, __u64 ip) | |||
676 | 689 | ||
677 | static int | 690 | static int |
678 | hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, | 691 | hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, |
679 | struct symbol *sym, __u64 ip, char level) | 692 | struct symbol *sym, u64 ip, char level) |
680 | { | 693 | { |
681 | struct rb_node **p = &hist.rb_node; | 694 | struct rb_node **p = &hist.rb_node; |
682 | struct rb_node *parent = NULL; | 695 | struct rb_node *parent = NULL; |
@@ -848,7 +861,7 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head) | |||
848 | int show = 0; | 861 | int show = 0; |
849 | struct dso *dso = NULL; | 862 | struct dso *dso = NULL; |
850 | struct thread *thread = threads__findnew(event->ip.pid); | 863 | struct thread *thread = threads__findnew(event->ip.pid); |
851 | __u64 ip = event->ip.ip; | 864 | u64 ip = event->ip.ip; |
852 | struct map *map = NULL; | 865 | struct map *map = NULL; |
853 | 866 | ||
854 | dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", | 867 | dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", |
@@ -1030,13 +1043,33 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
1030 | return 0; | 1043 | return 0; |
1031 | } | 1044 | } |
1032 | 1045 | ||
1046 | static char *get_color(double percent) | ||
1047 | { | ||
1048 | char *color = PERF_COLOR_NORMAL; | ||
1049 | |||
1050 | /* | ||
1051 | * We color high-overhead entries in red, mid-overhead | ||
1052 | * entries in green - and keep the low overhead places | ||
1053 | * normal: | ||
1054 | */ | ||
1055 | if (percent >= MIN_RED) | ||
1056 | color = PERF_COLOR_RED; | ||
1057 | else { | ||
1058 | if (percent > MIN_GREEN) | ||
1059 | color = PERF_COLOR_GREEN; | ||
1060 | } | ||
1061 | return color; | ||
1062 | } | ||
1063 | |||
1033 | static int | 1064 | static int |
1034 | parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) | 1065 | parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) |
1035 | { | 1066 | { |
1036 | char *line = NULL, *tmp, *tmp2; | 1067 | char *line = NULL, *tmp, *tmp2; |
1068 | static const char *prev_line; | ||
1069 | static const char *prev_color; | ||
1037 | unsigned int offset; | 1070 | unsigned int offset; |
1038 | size_t line_len; | 1071 | size_t line_len; |
1039 | __u64 line_ip; | 1072 | u64 line_ip; |
1040 | int ret; | 1073 | int ret; |
1041 | char *c; | 1074 | char *c; |
1042 | 1075 | ||
@@ -1073,27 +1106,36 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) | |||
1073 | } | 1106 | } |
1074 | 1107 | ||
1075 | if (line_ip != -1) { | 1108 | if (line_ip != -1) { |
1109 | const char *path = NULL; | ||
1076 | unsigned int hits = 0; | 1110 | unsigned int hits = 0; |
1077 | double percent = 0.0; | 1111 | double percent = 0.0; |
1078 | char *color = PERF_COLOR_NORMAL; | 1112 | char *color; |
1113 | struct sym_ext *sym_ext = sym->priv; | ||
1079 | 1114 | ||
1080 | offset = line_ip - start; | 1115 | offset = line_ip - start; |
1081 | if (offset < len) | 1116 | if (offset < len) |
1082 | hits = sym->hist[offset]; | 1117 | hits = sym->hist[offset]; |
1083 | 1118 | ||
1084 | if (sym->hist_sum) | 1119 | if (offset < len && sym_ext) { |
1120 | path = sym_ext[offset].path; | ||
1121 | percent = sym_ext[offset].percent; | ||
1122 | } else if (sym->hist_sum) | ||
1085 | percent = 100.0 * hits / sym->hist_sum; | 1123 | percent = 100.0 * hits / sym->hist_sum; |
1086 | 1124 | ||
1125 | color = get_color(percent); | ||
1126 | |||
1087 | /* | 1127 | /* |
1088 | * We color high-overhead entries in red, mid-overhead | 1128 | * Also color the filename and line if needed, with |
1089 | * entries in green - and keep the low overhead places | 1129 | * the same color than the percentage. Don't print it |
1090 | * normal: | 1130 | * twice for close colored ip with the same filename:line |
1091 | */ | 1131 | */ |
1092 | if (percent >= 5.0) | 1132 | if (path) { |
1093 | color = PERF_COLOR_RED; | 1133 | if (!prev_line || strcmp(prev_line, path) |
1094 | else { | 1134 | || color != prev_color) { |
1095 | if (percent > 0.5) | 1135 | color_fprintf(stdout, color, " %s", path); |
1096 | color = PERF_COLOR_GREEN; | 1136 | prev_line = path; |
1137 | prev_color = color; | ||
1138 | } | ||
1097 | } | 1139 | } |
1098 | 1140 | ||
1099 | color_fprintf(stdout, color, " %7.2f", percent); | 1141 | color_fprintf(stdout, color, " %7.2f", percent); |
@@ -1109,10 +1151,125 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len) | |||
1109 | return 0; | 1151 | return 0; |
1110 | } | 1152 | } |
1111 | 1153 | ||
1154 | static struct rb_root root_sym_ext; | ||
1155 | |||
1156 | static void insert_source_line(struct sym_ext *sym_ext) | ||
1157 | { | ||
1158 | struct sym_ext *iter; | ||
1159 | struct rb_node **p = &root_sym_ext.rb_node; | ||
1160 | struct rb_node *parent = NULL; | ||
1161 | |||
1162 | while (*p != NULL) { | ||
1163 | parent = *p; | ||
1164 | iter = rb_entry(parent, struct sym_ext, node); | ||
1165 | |||
1166 | if (sym_ext->percent > iter->percent) | ||
1167 | p = &(*p)->rb_left; | ||
1168 | else | ||
1169 | p = &(*p)->rb_right; | ||
1170 | } | ||
1171 | |||
1172 | rb_link_node(&sym_ext->node, parent, p); | ||
1173 | rb_insert_color(&sym_ext->node, &root_sym_ext); | ||
1174 | } | ||
1175 | |||
1176 | static void free_source_line(struct symbol *sym, int len) | ||
1177 | { | ||
1178 | struct sym_ext *sym_ext = sym->priv; | ||
1179 | int i; | ||
1180 | |||
1181 | if (!sym_ext) | ||
1182 | return; | ||
1183 | |||
1184 | for (i = 0; i < len; i++) | ||
1185 | free(sym_ext[i].path); | ||
1186 | free(sym_ext); | ||
1187 | |||
1188 | sym->priv = NULL; | ||
1189 | root_sym_ext = RB_ROOT; | ||
1190 | } | ||
1191 | |||
1192 | /* Get the filename:line for the colored entries */ | ||
1193 | static void | ||
1194 | get_source_line(struct symbol *sym, u64 start, int len, char *filename) | ||
1195 | { | ||
1196 | int i; | ||
1197 | char cmd[PATH_MAX * 2]; | ||
1198 | struct sym_ext *sym_ext; | ||
1199 | |||
1200 | if (!sym->hist_sum) | ||
1201 | return; | ||
1202 | |||
1203 | sym->priv = calloc(len, sizeof(struct sym_ext)); | ||
1204 | if (!sym->priv) | ||
1205 | return; | ||
1206 | |||
1207 | sym_ext = sym->priv; | ||
1208 | |||
1209 | for (i = 0; i < len; i++) { | ||
1210 | char *path = NULL; | ||
1211 | size_t line_len; | ||
1212 | u64 offset; | ||
1213 | FILE *fp; | ||
1214 | |||
1215 | sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum; | ||
1216 | if (sym_ext[i].percent <= 0.5) | ||
1217 | continue; | ||
1218 | |||
1219 | offset = start + i; | ||
1220 | sprintf(cmd, "addr2line -e %s %016llx", filename, offset); | ||
1221 | fp = popen(cmd, "r"); | ||
1222 | if (!fp) | ||
1223 | continue; | ||
1224 | |||
1225 | if (getline(&path, &line_len, fp) < 0 || !line_len) | ||
1226 | goto next; | ||
1227 | |||
1228 | sym_ext[i].path = malloc(sizeof(char) * line_len + 1); | ||
1229 | if (!sym_ext[i].path) | ||
1230 | goto next; | ||
1231 | |||
1232 | strcpy(sym_ext[i].path, path); | ||
1233 | insert_source_line(&sym_ext[i]); | ||
1234 | |||
1235 | next: | ||
1236 | pclose(fp); | ||
1237 | } | ||
1238 | } | ||
1239 | |||
1240 | static void print_summary(char *filename) | ||
1241 | { | ||
1242 | struct sym_ext *sym_ext; | ||
1243 | struct rb_node *node; | ||
1244 | |||
1245 | printf("\nSorted summary for file %s\n", filename); | ||
1246 | printf("----------------------------------------------\n\n"); | ||
1247 | |||
1248 | if (RB_EMPTY_ROOT(&root_sym_ext)) { | ||
1249 | printf(" Nothing higher than %1.1f%%\n", MIN_GREEN); | ||
1250 | return; | ||
1251 | } | ||
1252 | |||
1253 | node = rb_first(&root_sym_ext); | ||
1254 | while (node) { | ||
1255 | double percent; | ||
1256 | char *color; | ||
1257 | char *path; | ||
1258 | |||
1259 | sym_ext = rb_entry(node, struct sym_ext, node); | ||
1260 | percent = sym_ext->percent; | ||
1261 | color = get_color(percent); | ||
1262 | path = sym_ext->path; | ||
1263 | |||
1264 | color_fprintf(stdout, color, " %7.2f %s", percent, path); | ||
1265 | node = rb_next(node); | ||
1266 | } | ||
1267 | } | ||
1268 | |||
1112 | static void annotate_sym(struct dso *dso, struct symbol *sym) | 1269 | static void annotate_sym(struct dso *dso, struct symbol *sym) |
1113 | { | 1270 | { |
1114 | char *filename = dso->name; | 1271 | char *filename = dso->name; |
1115 | __u64 start, end, len; | 1272 | u64 start, end, len; |
1116 | char command[PATH_MAX*2]; | 1273 | char command[PATH_MAX*2]; |
1117 | FILE *file; | 1274 | FILE *file; |
1118 | 1275 | ||
@@ -1121,13 +1278,6 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) | |||
1121 | if (dso == kernel_dso) | 1278 | if (dso == kernel_dso) |
1122 | filename = vmlinux; | 1279 | filename = vmlinux; |
1123 | 1280 | ||
1124 | printf("\n------------------------------------------------\n"); | ||
1125 | printf(" Percent | Source code & Disassembly of %s\n", filename); | ||
1126 | printf("------------------------------------------------\n"); | ||
1127 | |||
1128 | if (verbose >= 2) | ||
1129 | printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); | ||
1130 | |||
1131 | start = sym->obj_start; | 1281 | start = sym->obj_start; |
1132 | if (!start) | 1282 | if (!start) |
1133 | start = sym->start; | 1283 | start = sym->start; |
@@ -1135,7 +1285,19 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) | |||
1135 | end = start + sym->end - sym->start + 1; | 1285 | end = start + sym->end - sym->start + 1; |
1136 | len = sym->end - sym->start; | 1286 | len = sym->end - sym->start; |
1137 | 1287 | ||
1138 | sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (__u64)start, (__u64)end, filename); | 1288 | if (print_line) { |
1289 | get_source_line(sym, start, len, filename); | ||
1290 | print_summary(filename); | ||
1291 | } | ||
1292 | |||
1293 | printf("\n\n------------------------------------------------\n"); | ||
1294 | printf(" Percent | Source code & Disassembly of %s\n", filename); | ||
1295 | printf("------------------------------------------------\n"); | ||
1296 | |||
1297 | if (verbose >= 2) | ||
1298 | printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); | ||
1299 | |||
1300 | sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (u64)start, (u64)end, filename); | ||
1139 | 1301 | ||
1140 | if (verbose >= 3) | 1302 | if (verbose >= 3) |
1141 | printf("doing: %s\n", command); | 1303 | printf("doing: %s\n", command); |
@@ -1150,6 +1312,8 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) | |||
1150 | } | 1312 | } |
1151 | 1313 | ||
1152 | pclose(file); | 1314 | pclose(file); |
1315 | if (print_line) | ||
1316 | free_source_line(sym, len); | ||
1153 | } | 1317 | } |
1154 | 1318 | ||
1155 | static void find_annotations(void) | 1319 | static void find_annotations(void) |
@@ -1308,6 +1472,8 @@ static const struct option options[] = { | |||
1308 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, | 1472 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, |
1309 | "dump raw trace in ASCII"), | 1473 | "dump raw trace in ASCII"), |
1310 | OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), | 1474 | OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), |
1475 | OPT_BOOLEAN('l', "print-line", &print_line, | ||
1476 | "print matching source lines (may be slow)"), | ||
1311 | OPT_END() | 1477 | OPT_END() |
1312 | }; | 1478 | }; |
1313 | 1479 | ||
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 0f5771f615da..d7ebbd757543 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -37,33 +37,37 @@ static pid_t target_pid = -1; | |||
37 | static int inherit = 1; | 37 | static int inherit = 1; |
38 | static int force = 0; | 38 | static int force = 0; |
39 | static int append_file = 0; | 39 | static int append_file = 0; |
40 | static int call_graph = 0; | ||
40 | static int verbose = 0; | 41 | static int verbose = 0; |
41 | 42 | ||
42 | static long samples; | 43 | static long samples; |
43 | static struct timeval last_read; | 44 | static struct timeval last_read; |
44 | static struct timeval this_read; | 45 | static struct timeval this_read; |
45 | 46 | ||
46 | static __u64 bytes_written; | 47 | static u64 bytes_written; |
47 | 48 | ||
48 | static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; | 49 | static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; |
49 | 50 | ||
50 | static int nr_poll; | 51 | static int nr_poll; |
51 | static int nr_cpu; | 52 | static int nr_cpu; |
52 | 53 | ||
54 | static int file_new = 1; | ||
55 | static struct perf_file_header file_header; | ||
56 | |||
53 | struct mmap_event { | 57 | struct mmap_event { |
54 | struct perf_event_header header; | 58 | struct perf_event_header header; |
55 | __u32 pid; | 59 | u32 pid; |
56 | __u32 tid; | 60 | u32 tid; |
57 | __u64 start; | 61 | u64 start; |
58 | __u64 len; | 62 | u64 len; |
59 | __u64 pgoff; | 63 | u64 pgoff; |
60 | char filename[PATH_MAX]; | 64 | char filename[PATH_MAX]; |
61 | }; | 65 | }; |
62 | 66 | ||
63 | struct comm_event { | 67 | struct comm_event { |
64 | struct perf_event_header header; | 68 | struct perf_event_header header; |
65 | __u32 pid; | 69 | u32 pid; |
66 | __u32 tid; | 70 | u32 tid; |
67 | char comm[16]; | 71 | char comm[16]; |
68 | }; | 72 | }; |
69 | 73 | ||
@@ -77,10 +81,10 @@ struct mmap_data { | |||
77 | 81 | ||
78 | static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; | 82 | static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; |
79 | 83 | ||
80 | static unsigned int mmap_read_head(struct mmap_data *md) | 84 | static unsigned long mmap_read_head(struct mmap_data *md) |
81 | { | 85 | { |
82 | struct perf_counter_mmap_page *pc = md->base; | 86 | struct perf_counter_mmap_page *pc = md->base; |
83 | int head; | 87 | long head; |
84 | 88 | ||
85 | head = pc->data_head; | 89 | head = pc->data_head; |
86 | rmb(); | 90 | rmb(); |
@@ -88,6 +92,32 @@ static unsigned int mmap_read_head(struct mmap_data *md) | |||
88 | return head; | 92 | return head; |
89 | } | 93 | } |
90 | 94 | ||
95 | static void mmap_write_tail(struct mmap_data *md, unsigned long tail) | ||
96 | { | ||
97 | struct perf_counter_mmap_page *pc = md->base; | ||
98 | |||
99 | /* | ||
100 | * ensure all reads are done before we write the tail out. | ||
101 | */ | ||
102 | /* mb(); */ | ||
103 | pc->data_tail = tail; | ||
104 | } | ||
105 | |||
106 | static void write_output(void *buf, size_t size) | ||
107 | { | ||
108 | while (size) { | ||
109 | int ret = write(output, buf, size); | ||
110 | |||
111 | if (ret < 0) | ||
112 | die("failed to write"); | ||
113 | |||
114 | size -= ret; | ||
115 | buf += ret; | ||
116 | |||
117 | bytes_written += ret; | ||
118 | } | ||
119 | } | ||
120 | |||
91 | static void mmap_read(struct mmap_data *md) | 121 | static void mmap_read(struct mmap_data *md) |
92 | { | 122 | { |
93 | unsigned int head = mmap_read_head(md); | 123 | unsigned int head = mmap_read_head(md); |
@@ -108,7 +138,7 @@ static void mmap_read(struct mmap_data *md) | |||
108 | * In either case, truncate and restart at head. | 138 | * In either case, truncate and restart at head. |
109 | */ | 139 | */ |
110 | diff = head - old; | 140 | diff = head - old; |
111 | if (diff > md->mask / 2 || diff < 0) { | 141 | if (diff < 0) { |
112 | struct timeval iv; | 142 | struct timeval iv; |
113 | unsigned long msecs; | 143 | unsigned long msecs; |
114 | 144 | ||
@@ -136,36 +166,17 @@ static void mmap_read(struct mmap_data *md) | |||
136 | size = md->mask + 1 - (old & md->mask); | 166 | size = md->mask + 1 - (old & md->mask); |
137 | old += size; | 167 | old += size; |
138 | 168 | ||
139 | while (size) { | 169 | write_output(buf, size); |
140 | int ret = write(output, buf, size); | ||
141 | |||
142 | if (ret < 0) | ||
143 | die("failed to write"); | ||
144 | |||
145 | size -= ret; | ||
146 | buf += ret; | ||
147 | |||
148 | bytes_written += ret; | ||
149 | } | ||
150 | } | 170 | } |
151 | 171 | ||
152 | buf = &data[old & md->mask]; | 172 | buf = &data[old & md->mask]; |
153 | size = head - old; | 173 | size = head - old; |
154 | old += size; | 174 | old += size; |
155 | 175 | ||
156 | while (size) { | 176 | write_output(buf, size); |
157 | int ret = write(output, buf, size); | ||
158 | |||
159 | if (ret < 0) | ||
160 | die("failed to write"); | ||
161 | |||
162 | size -= ret; | ||
163 | buf += ret; | ||
164 | |||
165 | bytes_written += ret; | ||
166 | } | ||
167 | 177 | ||
168 | md->prev = old; | 178 | md->prev = old; |
179 | mmap_write_tail(md, old); | ||
169 | } | 180 | } |
170 | 181 | ||
171 | static volatile int done = 0; | 182 | static volatile int done = 0; |
@@ -191,7 +202,7 @@ static void pid_synthesize_comm_event(pid_t pid, int full) | |||
191 | struct comm_event comm_ev; | 202 | struct comm_event comm_ev; |
192 | char filename[PATH_MAX]; | 203 | char filename[PATH_MAX]; |
193 | char bf[BUFSIZ]; | 204 | char bf[BUFSIZ]; |
194 | int fd, ret; | 205 | int fd; |
195 | size_t size; | 206 | size_t size; |
196 | char *field, *sep; | 207 | char *field, *sep; |
197 | DIR *tasks; | 208 | DIR *tasks; |
@@ -201,8 +212,12 @@ static void pid_synthesize_comm_event(pid_t pid, int full) | |||
201 | 212 | ||
202 | fd = open(filename, O_RDONLY); | 213 | fd = open(filename, O_RDONLY); |
203 | if (fd < 0) { | 214 | if (fd < 0) { |
204 | fprintf(stderr, "couldn't open %s\n", filename); | 215 | /* |
205 | exit(EXIT_FAILURE); | 216 | * We raced with a task exiting - just return: |
217 | */ | ||
218 | if (verbose) | ||
219 | fprintf(stderr, "couldn't open %s\n", filename); | ||
220 | return; | ||
206 | } | 221 | } |
207 | if (read(fd, bf, sizeof(bf)) < 0) { | 222 | if (read(fd, bf, sizeof(bf)) < 0) { |
208 | fprintf(stderr, "couldn't read %s\n", filename); | 223 | fprintf(stderr, "couldn't read %s\n", filename); |
@@ -223,17 +238,13 @@ static void pid_synthesize_comm_event(pid_t pid, int full) | |||
223 | 238 | ||
224 | comm_ev.pid = pid; | 239 | comm_ev.pid = pid; |
225 | comm_ev.header.type = PERF_EVENT_COMM; | 240 | comm_ev.header.type = PERF_EVENT_COMM; |
226 | size = ALIGN(size, sizeof(__u64)); | 241 | size = ALIGN(size, sizeof(u64)); |
227 | comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); | 242 | comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); |
228 | 243 | ||
229 | if (!full) { | 244 | if (!full) { |
230 | comm_ev.tid = pid; | 245 | comm_ev.tid = pid; |
231 | 246 | ||
232 | ret = write(output, &comm_ev, comm_ev.header.size); | 247 | write_output(&comm_ev, comm_ev.header.size); |
233 | if (ret < 0) { | ||
234 | perror("failed to write"); | ||
235 | exit(-1); | ||
236 | } | ||
237 | return; | 248 | return; |
238 | } | 249 | } |
239 | 250 | ||
@@ -248,11 +259,7 @@ static void pid_synthesize_comm_event(pid_t pid, int full) | |||
248 | 259 | ||
249 | comm_ev.tid = pid; | 260 | comm_ev.tid = pid; |
250 | 261 | ||
251 | ret = write(output, &comm_ev, comm_ev.header.size); | 262 | write_output(&comm_ev, comm_ev.header.size); |
252 | if (ret < 0) { | ||
253 | perror("failed to write"); | ||
254 | exit(-1); | ||
255 | } | ||
256 | } | 263 | } |
257 | closedir(tasks); | 264 | closedir(tasks); |
258 | return; | 265 | return; |
@@ -272,8 +279,12 @@ static void pid_synthesize_mmap_samples(pid_t pid) | |||
272 | 279 | ||
273 | fp = fopen(filename, "r"); | 280 | fp = fopen(filename, "r"); |
274 | if (fp == NULL) { | 281 | if (fp == NULL) { |
275 | fprintf(stderr, "couldn't open %s\n", filename); | 282 | /* |
276 | exit(EXIT_FAILURE); | 283 | * We raced with a task exiting - just return: |
284 | */ | ||
285 | if (verbose) | ||
286 | fprintf(stderr, "couldn't open %s\n", filename); | ||
287 | return; | ||
277 | } | 288 | } |
278 | while (1) { | 289 | while (1) { |
279 | char bf[BUFSIZ], *pbf = bf; | 290 | char bf[BUFSIZ], *pbf = bf; |
@@ -304,17 +315,14 @@ static void pid_synthesize_mmap_samples(pid_t pid) | |||
304 | size = strlen(execname); | 315 | size = strlen(execname); |
305 | execname[size - 1] = '\0'; /* Remove \n */ | 316 | execname[size - 1] = '\0'; /* Remove \n */ |
306 | memcpy(mmap_ev.filename, execname, size); | 317 | memcpy(mmap_ev.filename, execname, size); |
307 | size = ALIGN(size, sizeof(__u64)); | 318 | size = ALIGN(size, sizeof(u64)); |
308 | mmap_ev.len -= mmap_ev.start; | 319 | mmap_ev.len -= mmap_ev.start; |
309 | mmap_ev.header.size = (sizeof(mmap_ev) - | 320 | mmap_ev.header.size = (sizeof(mmap_ev) - |
310 | (sizeof(mmap_ev.filename) - size)); | 321 | (sizeof(mmap_ev.filename) - size)); |
311 | mmap_ev.pid = pid; | 322 | mmap_ev.pid = pid; |
312 | mmap_ev.tid = pid; | 323 | mmap_ev.tid = pid; |
313 | 324 | ||
314 | if (write(output, &mmap_ev, mmap_ev.header.size) < 0) { | 325 | write_output(&mmap_ev, mmap_ev.header.size); |
315 | perror("failed to write"); | ||
316 | exit(-1); | ||
317 | } | ||
318 | } | 326 | } |
319 | } | 327 | } |
320 | 328 | ||
@@ -351,11 +359,25 @@ static void create_counter(int counter, int cpu, pid_t pid) | |||
351 | int track = 1; | 359 | int track = 1; |
352 | 360 | ||
353 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 361 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
362 | |||
354 | if (freq) { | 363 | if (freq) { |
355 | attr->sample_type |= PERF_SAMPLE_PERIOD; | 364 | attr->sample_type |= PERF_SAMPLE_PERIOD; |
356 | attr->freq = 1; | 365 | attr->freq = 1; |
357 | attr->sample_freq = freq; | 366 | attr->sample_freq = freq; |
358 | } | 367 | } |
368 | |||
369 | if (call_graph) | ||
370 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; | ||
371 | |||
372 | if (file_new) { | ||
373 | file_header.sample_type = attr->sample_type; | ||
374 | } else { | ||
375 | if (file_header.sample_type != attr->sample_type) { | ||
376 | fprintf(stderr, "incompatible append\n"); | ||
377 | exit(-1); | ||
378 | } | ||
379 | } | ||
380 | |||
359 | attr->mmap = track; | 381 | attr->mmap = track; |
360 | attr->comm = track; | 382 | attr->comm = track; |
361 | attr->inherit = (cpu < 0) && inherit; | 383 | attr->inherit = (cpu < 0) && inherit; |
@@ -410,7 +432,7 @@ try_again: | |||
410 | mmap_array[nr_cpu][counter].prev = 0; | 432 | mmap_array[nr_cpu][counter].prev = 0; |
411 | mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1; | 433 | mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1; |
412 | mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size, | 434 | mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size, |
413 | PROT_READ, MAP_SHARED, fd[nr_cpu][counter], 0); | 435 | PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter], 0); |
414 | if (mmap_array[nr_cpu][counter].base == MAP_FAILED) { | 436 | if (mmap_array[nr_cpu][counter].base == MAP_FAILED) { |
415 | error("failed to mmap with %d (%s)\n", errno, strerror(errno)); | 437 | error("failed to mmap with %d (%s)\n", errno, strerror(errno)); |
416 | exit(-1); | 438 | exit(-1); |
@@ -435,6 +457,14 @@ static void open_counters(int cpu, pid_t pid) | |||
435 | nr_cpu++; | 457 | nr_cpu++; |
436 | } | 458 | } |
437 | 459 | ||
460 | static void atexit_header(void) | ||
461 | { | ||
462 | file_header.data_size += bytes_written; | ||
463 | |||
464 | if (pwrite(output, &file_header, sizeof(file_header), 0) == -1) | ||
465 | perror("failed to write on file headers"); | ||
466 | } | ||
467 | |||
438 | static int __cmd_record(int argc, const char **argv) | 468 | static int __cmd_record(int argc, const char **argv) |
439 | { | 469 | { |
440 | int i, counter; | 470 | int i, counter; |
@@ -448,6 +478,10 @@ static int __cmd_record(int argc, const char **argv) | |||
448 | assert(nr_cpus <= MAX_NR_CPUS); | 478 | assert(nr_cpus <= MAX_NR_CPUS); |
449 | assert(nr_cpus >= 0); | 479 | assert(nr_cpus >= 0); |
450 | 480 | ||
481 | atexit(sig_atexit); | ||
482 | signal(SIGCHLD, sig_handler); | ||
483 | signal(SIGINT, sig_handler); | ||
484 | |||
451 | if (!stat(output_name, &st) && !force && !append_file) { | 485 | if (!stat(output_name, &st) && !force && !append_file) { |
452 | fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", | 486 | fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", |
453 | output_name); | 487 | output_name); |
@@ -456,7 +490,7 @@ static int __cmd_record(int argc, const char **argv) | |||
456 | 490 | ||
457 | flags = O_CREAT|O_RDWR; | 491 | flags = O_CREAT|O_RDWR; |
458 | if (append_file) | 492 | if (append_file) |
459 | flags |= O_APPEND; | 493 | file_new = 0; |
460 | else | 494 | else |
461 | flags |= O_TRUNC; | 495 | flags |= O_TRUNC; |
462 | 496 | ||
@@ -466,15 +500,22 @@ static int __cmd_record(int argc, const char **argv) | |||
466 | exit(-1); | 500 | exit(-1); |
467 | } | 501 | } |
468 | 502 | ||
503 | if (!file_new) { | ||
504 | if (read(output, &file_header, sizeof(file_header)) == -1) { | ||
505 | perror("failed to read file headers"); | ||
506 | exit(-1); | ||
507 | } | ||
508 | |||
509 | lseek(output, file_header.data_size, SEEK_CUR); | ||
510 | } | ||
511 | |||
512 | atexit(atexit_header); | ||
513 | |||
469 | if (!system_wide) { | 514 | if (!system_wide) { |
470 | open_counters(-1, target_pid != -1 ? target_pid : getpid()); | 515 | open_counters(-1, target_pid != -1 ? target_pid : getpid()); |
471 | } else for (i = 0; i < nr_cpus; i++) | 516 | } else for (i = 0; i < nr_cpus; i++) |
472 | open_counters(i, target_pid); | 517 | open_counters(i, target_pid); |
473 | 518 | ||
474 | atexit(sig_atexit); | ||
475 | signal(SIGCHLD, sig_handler); | ||
476 | signal(SIGINT, sig_handler); | ||
477 | |||
478 | if (target_pid == -1 && argc) { | 519 | if (target_pid == -1 && argc) { |
479 | pid = fork(); | 520 | pid = fork(); |
480 | if (pid < 0) | 521 | if (pid < 0) |
@@ -555,6 +596,8 @@ static const struct option options[] = { | |||
555 | "profile at this frequency"), | 596 | "profile at this frequency"), |
556 | OPT_INTEGER('m', "mmap-pages", &mmap_pages, | 597 | OPT_INTEGER('m', "mmap-pages", &mmap_pages, |
557 | "number of mmap data pages"), | 598 | "number of mmap data pages"), |
599 | OPT_BOOLEAN('g', "call-graph", &call_graph, | ||
600 | "do call-graph (stack chain/backtrace) recording"), | ||
558 | OPT_BOOLEAN('v', "verbose", &verbose, | 601 | OPT_BOOLEAN('v', "verbose", &verbose, |
559 | "be more verbose (show counter open errors, etc)"), | 602 | "be more verbose (show counter open errors, etc)"), |
560 | OPT_END() | 603 | OPT_END() |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 82fa93b4db99..5eb5566f0c95 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -36,45 +36,65 @@ static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; | |||
36 | 36 | ||
37 | static int dump_trace = 0; | 37 | static int dump_trace = 0; |
38 | #define dprintf(x...) do { if (dump_trace) printf(x); } while (0) | 38 | #define dprintf(x...) do { if (dump_trace) printf(x); } while (0) |
39 | #define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0) | ||
39 | 40 | ||
40 | static int verbose; | 41 | static int verbose; |
42 | #define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0) | ||
43 | |||
41 | static int full_paths; | 44 | static int full_paths; |
42 | 45 | ||
43 | static unsigned long page_size; | 46 | static unsigned long page_size; |
44 | static unsigned long mmap_window = 32; | 47 | static unsigned long mmap_window = 32; |
45 | 48 | ||
49 | static char default_parent_pattern[] = "^sys_|^do_page_fault"; | ||
50 | static char *parent_pattern = default_parent_pattern; | ||
51 | static regex_t parent_regex; | ||
52 | |||
53 | static int exclude_other = 1; | ||
54 | |||
46 | struct ip_event { | 55 | struct ip_event { |
47 | struct perf_event_header header; | 56 | struct perf_event_header header; |
48 | __u64 ip; | 57 | u64 ip; |
49 | __u32 pid, tid; | 58 | u32 pid, tid; |
50 | __u64 period; | 59 | unsigned char __more_data[]; |
60 | }; | ||
61 | |||
62 | struct ip_callchain { | ||
63 | u64 nr; | ||
64 | u64 ips[0]; | ||
51 | }; | 65 | }; |
52 | 66 | ||
53 | struct mmap_event { | 67 | struct mmap_event { |
54 | struct perf_event_header header; | 68 | struct perf_event_header header; |
55 | __u32 pid, tid; | 69 | u32 pid, tid; |
56 | __u64 start; | 70 | u64 start; |
57 | __u64 len; | 71 | u64 len; |
58 | __u64 pgoff; | 72 | u64 pgoff; |
59 | char filename[PATH_MAX]; | 73 | char filename[PATH_MAX]; |
60 | }; | 74 | }; |
61 | 75 | ||
62 | struct comm_event { | 76 | struct comm_event { |
63 | struct perf_event_header header; | 77 | struct perf_event_header header; |
64 | __u32 pid, tid; | 78 | u32 pid, tid; |
65 | char comm[16]; | 79 | char comm[16]; |
66 | }; | 80 | }; |
67 | 81 | ||
68 | struct fork_event { | 82 | struct fork_event { |
69 | struct perf_event_header header; | 83 | struct perf_event_header header; |
70 | __u32 pid, ppid; | 84 | u32 pid, ppid; |
71 | }; | 85 | }; |
72 | 86 | ||
73 | struct period_event { | 87 | struct period_event { |
74 | struct perf_event_header header; | 88 | struct perf_event_header header; |
75 | __u64 time; | 89 | u64 time; |
76 | __u64 id; | 90 | u64 id; |
77 | __u64 sample_period; | 91 | u64 sample_period; |
92 | }; | ||
93 | |||
94 | struct lost_event { | ||
95 | struct perf_event_header header; | ||
96 | u64 id; | ||
97 | u64 lost; | ||
78 | }; | 98 | }; |
79 | 99 | ||
80 | typedef union event_union { | 100 | typedef union event_union { |
@@ -84,6 +104,7 @@ typedef union event_union { | |||
84 | struct comm_event comm; | 104 | struct comm_event comm; |
85 | struct fork_event fork; | 105 | struct fork_event fork; |
86 | struct period_event period; | 106 | struct period_event period; |
107 | struct lost_event lost; | ||
87 | } event_t; | 108 | } event_t; |
88 | 109 | ||
89 | static LIST_HEAD(dsos); | 110 | static LIST_HEAD(dsos); |
@@ -119,15 +140,11 @@ static struct dso *dsos__findnew(const char *name) | |||
119 | 140 | ||
120 | nr = dso__load(dso, NULL, verbose); | 141 | nr = dso__load(dso, NULL, verbose); |
121 | if (nr < 0) { | 142 | if (nr < 0) { |
122 | if (verbose) | 143 | eprintf("Failed to open: %s\n", name); |
123 | fprintf(stderr, "Failed to open: %s\n", name); | ||
124 | goto out_delete_dso; | 144 | goto out_delete_dso; |
125 | } | 145 | } |
126 | if (!nr && verbose) { | 146 | if (!nr) |
127 | fprintf(stderr, | 147 | eprintf("No symbols found in: %s, maybe install a debug package?\n", name); |
128 | "No symbols found in: %s, maybe install a debug package?\n", | ||
129 | name); | ||
130 | } | ||
131 | 148 | ||
132 | dsos__add(dso); | 149 | dsos__add(dso); |
133 | 150 | ||
@@ -146,7 +163,7 @@ static void dsos__fprintf(FILE *fp) | |||
146 | dso__fprintf(pos, fp); | 163 | dso__fprintf(pos, fp); |
147 | } | 164 | } |
148 | 165 | ||
149 | static struct symbol *vdso__find_symbol(struct dso *dso, __u64 ip) | 166 | static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) |
150 | { | 167 | { |
151 | return dso__find_symbol(kernel_dso, ip); | 168 | return dso__find_symbol(kernel_dso, ip); |
152 | } | 169 | } |
@@ -193,19 +210,19 @@ static int strcommon(const char *pathname) | |||
193 | 210 | ||
194 | struct map { | 211 | struct map { |
195 | struct list_head node; | 212 | struct list_head node; |
196 | __u64 start; | 213 | u64 start; |
197 | __u64 end; | 214 | u64 end; |
198 | __u64 pgoff; | 215 | u64 pgoff; |
199 | __u64 (*map_ip)(struct map *, __u64); | 216 | u64 (*map_ip)(struct map *, u64); |
200 | struct dso *dso; | 217 | struct dso *dso; |
201 | }; | 218 | }; |
202 | 219 | ||
203 | static __u64 map__map_ip(struct map *map, __u64 ip) | 220 | static u64 map__map_ip(struct map *map, u64 ip) |
204 | { | 221 | { |
205 | return ip - map->start + map->pgoff; | 222 | return ip - map->start + map->pgoff; |
206 | } | 223 | } |
207 | 224 | ||
208 | static __u64 vdso__map_ip(struct map *map, __u64 ip) | 225 | static u64 vdso__map_ip(struct map *map, u64 ip) |
209 | { | 226 | { |
210 | return ip; | 227 | return ip; |
211 | } | 228 | } |
@@ -412,7 +429,7 @@ static int thread__fork(struct thread *self, struct thread *parent) | |||
412 | return 0; | 429 | return 0; |
413 | } | 430 | } |
414 | 431 | ||
415 | static struct map *thread__find_map(struct thread *self, __u64 ip) | 432 | static struct map *thread__find_map(struct thread *self, u64 ip) |
416 | { | 433 | { |
417 | struct map *pos; | 434 | struct map *pos; |
418 | 435 | ||
@@ -453,10 +470,11 @@ struct hist_entry { | |||
453 | struct map *map; | 470 | struct map *map; |
454 | struct dso *dso; | 471 | struct dso *dso; |
455 | struct symbol *sym; | 472 | struct symbol *sym; |
456 | __u64 ip; | 473 | struct symbol *parent; |
474 | u64 ip; | ||
457 | char level; | 475 | char level; |
458 | 476 | ||
459 | __u64 count; | 477 | u64 count; |
460 | }; | 478 | }; |
461 | 479 | ||
462 | /* | 480 | /* |
@@ -473,6 +491,16 @@ struct sort_entry { | |||
473 | size_t (*print)(FILE *fp, struct hist_entry *); | 491 | size_t (*print)(FILE *fp, struct hist_entry *); |
474 | }; | 492 | }; |
475 | 493 | ||
494 | static int64_t cmp_null(void *l, void *r) | ||
495 | { | ||
496 | if (!l && !r) | ||
497 | return 0; | ||
498 | else if (!l) | ||
499 | return -1; | ||
500 | else | ||
501 | return 1; | ||
502 | } | ||
503 | |||
476 | /* --sort pid */ | 504 | /* --sort pid */ |
477 | 505 | ||
478 | static int64_t | 506 | static int64_t |
@@ -507,14 +535,8 @@ sort__comm_collapse(struct hist_entry *left, struct hist_entry *right) | |||
507 | char *comm_l = left->thread->comm; | 535 | char *comm_l = left->thread->comm; |
508 | char *comm_r = right->thread->comm; | 536 | char *comm_r = right->thread->comm; |
509 | 537 | ||
510 | if (!comm_l || !comm_r) { | 538 | if (!comm_l || !comm_r) |
511 | if (!comm_l && !comm_r) | 539 | return cmp_null(comm_l, comm_r); |
512 | return 0; | ||
513 | else if (!comm_l) | ||
514 | return -1; | ||
515 | else | ||
516 | return 1; | ||
517 | } | ||
518 | 540 | ||
519 | return strcmp(comm_l, comm_r); | 541 | return strcmp(comm_l, comm_r); |
520 | } | 542 | } |
@@ -540,14 +562,8 @@ sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) | |||
540 | struct dso *dso_l = left->dso; | 562 | struct dso *dso_l = left->dso; |
541 | struct dso *dso_r = right->dso; | 563 | struct dso *dso_r = right->dso; |
542 | 564 | ||
543 | if (!dso_l || !dso_r) { | 565 | if (!dso_l || !dso_r) |
544 | if (!dso_l && !dso_r) | 566 | return cmp_null(dso_l, dso_r); |
545 | return 0; | ||
546 | else if (!dso_l) | ||
547 | return -1; | ||
548 | else | ||
549 | return 1; | ||
550 | } | ||
551 | 567 | ||
552 | return strcmp(dso_l->name, dso_r->name); | 568 | return strcmp(dso_l->name, dso_r->name); |
553 | } | 569 | } |
@@ -558,7 +574,7 @@ sort__dso_print(FILE *fp, struct hist_entry *self) | |||
558 | if (self->dso) | 574 | if (self->dso) |
559 | return fprintf(fp, "%-25s", self->dso->name); | 575 | return fprintf(fp, "%-25s", self->dso->name); |
560 | 576 | ||
561 | return fprintf(fp, "%016llx ", (__u64)self->ip); | 577 | return fprintf(fp, "%016llx ", (u64)self->ip); |
562 | } | 578 | } |
563 | 579 | ||
564 | static struct sort_entry sort_dso = { | 580 | static struct sort_entry sort_dso = { |
@@ -572,7 +588,7 @@ static struct sort_entry sort_dso = { | |||
572 | static int64_t | 588 | static int64_t |
573 | sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) | 589 | sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) |
574 | { | 590 | { |
575 | __u64 ip_l, ip_r; | 591 | u64 ip_l, ip_r; |
576 | 592 | ||
577 | if (left->sym == right->sym) | 593 | if (left->sym == right->sym) |
578 | return 0; | 594 | return 0; |
@@ -589,13 +605,13 @@ sort__sym_print(FILE *fp, struct hist_entry *self) | |||
589 | size_t ret = 0; | 605 | size_t ret = 0; |
590 | 606 | ||
591 | if (verbose) | 607 | if (verbose) |
592 | ret += fprintf(fp, "%#018llx ", (__u64)self->ip); | 608 | ret += fprintf(fp, "%#018llx ", (u64)self->ip); |
593 | 609 | ||
594 | if (self->sym) { | 610 | if (self->sym) { |
595 | ret += fprintf(fp, "[%c] %s", | 611 | ret += fprintf(fp, "[%c] %s", |
596 | self->dso == kernel_dso ? 'k' : '.', self->sym->name); | 612 | self->dso == kernel_dso ? 'k' : '.', self->sym->name); |
597 | } else { | 613 | } else { |
598 | ret += fprintf(fp, "%#016llx", (__u64)self->ip); | 614 | ret += fprintf(fp, "%#016llx", (u64)self->ip); |
599 | } | 615 | } |
600 | 616 | ||
601 | return ret; | 617 | return ret; |
@@ -607,7 +623,38 @@ static struct sort_entry sort_sym = { | |||
607 | .print = sort__sym_print, | 623 | .print = sort__sym_print, |
608 | }; | 624 | }; |
609 | 625 | ||
626 | /* --sort parent */ | ||
627 | |||
628 | static int64_t | ||
629 | sort__parent_cmp(struct hist_entry *left, struct hist_entry *right) | ||
630 | { | ||
631 | struct symbol *sym_l = left->parent; | ||
632 | struct symbol *sym_r = right->parent; | ||
633 | |||
634 | if (!sym_l || !sym_r) | ||
635 | return cmp_null(sym_l, sym_r); | ||
636 | |||
637 | return strcmp(sym_l->name, sym_r->name); | ||
638 | } | ||
639 | |||
640 | static size_t | ||
641 | sort__parent_print(FILE *fp, struct hist_entry *self) | ||
642 | { | ||
643 | size_t ret = 0; | ||
644 | |||
645 | ret += fprintf(fp, "%-20s", self->parent ? self->parent->name : "[other]"); | ||
646 | |||
647 | return ret; | ||
648 | } | ||
649 | |||
650 | static struct sort_entry sort_parent = { | ||
651 | .header = "Parent symbol ", | ||
652 | .cmp = sort__parent_cmp, | ||
653 | .print = sort__parent_print, | ||
654 | }; | ||
655 | |||
610 | static int sort__need_collapse = 0; | 656 | static int sort__need_collapse = 0; |
657 | static int sort__has_parent = 0; | ||
611 | 658 | ||
612 | struct sort_dimension { | 659 | struct sort_dimension { |
613 | char *name; | 660 | char *name; |
@@ -620,6 +667,7 @@ static struct sort_dimension sort_dimensions[] = { | |||
620 | { .name = "comm", .entry = &sort_comm, }, | 667 | { .name = "comm", .entry = &sort_comm, }, |
621 | { .name = "dso", .entry = &sort_dso, }, | 668 | { .name = "dso", .entry = &sort_dso, }, |
622 | { .name = "symbol", .entry = &sort_sym, }, | 669 | { .name = "symbol", .entry = &sort_sym, }, |
670 | { .name = "parent", .entry = &sort_parent, }, | ||
623 | }; | 671 | }; |
624 | 672 | ||
625 | static LIST_HEAD(hist_entry__sort_list); | 673 | static LIST_HEAD(hist_entry__sort_list); |
@@ -640,6 +688,19 @@ static int sort_dimension__add(char *tok) | |||
640 | if (sd->entry->collapse) | 688 | if (sd->entry->collapse) |
641 | sort__need_collapse = 1; | 689 | sort__need_collapse = 1; |
642 | 690 | ||
691 | if (sd->entry == &sort_parent) { | ||
692 | int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); | ||
693 | if (ret) { | ||
694 | char err[BUFSIZ]; | ||
695 | |||
696 | regerror(ret, &parent_regex, err, sizeof(err)); | ||
697 | fprintf(stderr, "Invalid regex: %s\n%s", | ||
698 | parent_pattern, err); | ||
699 | exit(-1); | ||
700 | } | ||
701 | sort__has_parent = 1; | ||
702 | } | ||
703 | |||
643 | list_add_tail(&sd->entry->list, &hist_entry__sort_list); | 704 | list_add_tail(&sd->entry->list, &hist_entry__sort_list); |
644 | sd->taken = 1; | 705 | sd->taken = 1; |
645 | 706 | ||
@@ -684,11 +745,14 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) | |||
684 | } | 745 | } |
685 | 746 | ||
686 | static size_t | 747 | static size_t |
687 | hist_entry__fprintf(FILE *fp, struct hist_entry *self, __u64 total_samples) | 748 | hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples) |
688 | { | 749 | { |
689 | struct sort_entry *se; | 750 | struct sort_entry *se; |
690 | size_t ret; | 751 | size_t ret; |
691 | 752 | ||
753 | if (exclude_other && !self->parent) | ||
754 | return 0; | ||
755 | |||
692 | if (total_samples) { | 756 | if (total_samples) { |
693 | double percent = self->count * 100.0 / total_samples; | 757 | double percent = self->count * 100.0 / total_samples; |
694 | char *color = PERF_COLOR_NORMAL; | 758 | char *color = PERF_COLOR_NORMAL; |
@@ -711,6 +775,9 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, __u64 total_samples) | |||
711 | ret = fprintf(fp, "%12Ld ", self->count); | 775 | ret = fprintf(fp, "%12Ld ", self->count); |
712 | 776 | ||
713 | list_for_each_entry(se, &hist_entry__sort_list, list) { | 777 | list_for_each_entry(se, &hist_entry__sort_list, list) { |
778 | if (exclude_other && (se == &sort_parent)) | ||
779 | continue; | ||
780 | |||
714 | fprintf(fp, " "); | 781 | fprintf(fp, " "); |
715 | ret += se->print(fp, self); | 782 | ret += se->print(fp, self); |
716 | } | 783 | } |
@@ -721,12 +788,72 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, __u64 total_samples) | |||
721 | } | 788 | } |
722 | 789 | ||
723 | /* | 790 | /* |
791 | * | ||
792 | */ | ||
793 | |||
794 | static struct symbol * | ||
795 | resolve_symbol(struct thread *thread, struct map **mapp, | ||
796 | struct dso **dsop, u64 *ipp) | ||
797 | { | ||
798 | struct dso *dso = dsop ? *dsop : NULL; | ||
799 | struct map *map = mapp ? *mapp : NULL; | ||
800 | uint64_t ip = *ipp; | ||
801 | |||
802 | if (!thread) | ||
803 | return NULL; | ||
804 | |||
805 | if (dso) | ||
806 | goto got_dso; | ||
807 | |||
808 | if (map) | ||
809 | goto got_map; | ||
810 | |||
811 | map = thread__find_map(thread, ip); | ||
812 | if (map != NULL) { | ||
813 | if (mapp) | ||
814 | *mapp = map; | ||
815 | got_map: | ||
816 | ip = map->map_ip(map, ip); | ||
817 | *ipp = ip; | ||
818 | |||
819 | dso = map->dso; | ||
820 | } else { | ||
821 | /* | ||
822 | * If this is outside of all known maps, | ||
823 | * and is a negative address, try to look it | ||
824 | * up in the kernel dso, as it might be a | ||
825 | * vsyscall (which executes in user-mode): | ||
826 | */ | ||
827 | if ((long long)ip < 0) | ||
828 | dso = kernel_dso; | ||
829 | } | ||
830 | dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); | ||
831 | |||
832 | if (dsop) | ||
833 | *dsop = dso; | ||
834 | |||
835 | if (!dso) | ||
836 | return NULL; | ||
837 | got_dso: | ||
838 | return dso->find_symbol(dso, ip); | ||
839 | } | ||
840 | |||
841 | static int call__match(struct symbol *sym) | ||
842 | { | ||
843 | if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) | ||
844 | return 1; | ||
845 | |||
846 | return 0; | ||
847 | } | ||
848 | |||
849 | /* | ||
724 | * collect histogram counts | 850 | * collect histogram counts |
725 | */ | 851 | */ |
726 | 852 | ||
727 | static int | 853 | static int |
728 | hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, | 854 | hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, |
729 | struct symbol *sym, __u64 ip, char level, __u64 count) | 855 | struct symbol *sym, u64 ip, struct ip_callchain *chain, |
856 | char level, u64 count) | ||
730 | { | 857 | { |
731 | struct rb_node **p = &hist.rb_node; | 858 | struct rb_node **p = &hist.rb_node; |
732 | struct rb_node *parent = NULL; | 859 | struct rb_node *parent = NULL; |
@@ -739,9 +866,41 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, | |||
739 | .ip = ip, | 866 | .ip = ip, |
740 | .level = level, | 867 | .level = level, |
741 | .count = count, | 868 | .count = count, |
869 | .parent = NULL, | ||
742 | }; | 870 | }; |
743 | int cmp; | 871 | int cmp; |
744 | 872 | ||
873 | if (sort__has_parent && chain) { | ||
874 | u64 context = PERF_CONTEXT_MAX; | ||
875 | int i; | ||
876 | |||
877 | for (i = 0; i < chain->nr; i++) { | ||
878 | u64 ip = chain->ips[i]; | ||
879 | struct dso *dso = NULL; | ||
880 | struct symbol *sym; | ||
881 | |||
882 | if (ip >= PERF_CONTEXT_MAX) { | ||
883 | context = ip; | ||
884 | continue; | ||
885 | } | ||
886 | |||
887 | switch (context) { | ||
888 | case PERF_CONTEXT_KERNEL: | ||
889 | dso = kernel_dso; | ||
890 | break; | ||
891 | default: | ||
892 | break; | ||
893 | } | ||
894 | |||
895 | sym = resolve_symbol(thread, NULL, &dso, &ip); | ||
896 | |||
897 | if (sym && call__match(sym)) { | ||
898 | entry.parent = sym; | ||
899 | break; | ||
900 | } | ||
901 | } | ||
902 | } | ||
903 | |||
745 | while (*p != NULL) { | 904 | while (*p != NULL) { |
746 | parent = *p; | 905 | parent = *p; |
747 | he = rb_entry(parent, struct hist_entry, rb_node); | 906 | he = rb_entry(parent, struct hist_entry, rb_node); |
@@ -873,7 +1032,7 @@ static void output__resort(void) | |||
873 | } | 1032 | } |
874 | } | 1033 | } |
875 | 1034 | ||
876 | static size_t output__fprintf(FILE *fp, __u64 total_samples) | 1035 | static size_t output__fprintf(FILE *fp, u64 total_samples) |
877 | { | 1036 | { |
878 | struct hist_entry *pos; | 1037 | struct hist_entry *pos; |
879 | struct sort_entry *se; | 1038 | struct sort_entry *se; |
@@ -882,18 +1041,24 @@ static size_t output__fprintf(FILE *fp, __u64 total_samples) | |||
882 | 1041 | ||
883 | fprintf(fp, "\n"); | 1042 | fprintf(fp, "\n"); |
884 | fprintf(fp, "#\n"); | 1043 | fprintf(fp, "#\n"); |
885 | fprintf(fp, "# (%Ld samples)\n", (__u64)total_samples); | 1044 | fprintf(fp, "# (%Ld samples)\n", (u64)total_samples); |
886 | fprintf(fp, "#\n"); | 1045 | fprintf(fp, "#\n"); |
887 | 1046 | ||
888 | fprintf(fp, "# Overhead"); | 1047 | fprintf(fp, "# Overhead"); |
889 | list_for_each_entry(se, &hist_entry__sort_list, list) | 1048 | list_for_each_entry(se, &hist_entry__sort_list, list) { |
1049 | if (exclude_other && (se == &sort_parent)) | ||
1050 | continue; | ||
890 | fprintf(fp, " %s", se->header); | 1051 | fprintf(fp, " %s", se->header); |
1052 | } | ||
891 | fprintf(fp, "\n"); | 1053 | fprintf(fp, "\n"); |
892 | 1054 | ||
893 | fprintf(fp, "# ........"); | 1055 | fprintf(fp, "# ........"); |
894 | list_for_each_entry(se, &hist_entry__sort_list, list) { | 1056 | list_for_each_entry(se, &hist_entry__sort_list, list) { |
895 | int i; | 1057 | int i; |
896 | 1058 | ||
1059 | if (exclude_other && (se == &sort_parent)) | ||
1060 | continue; | ||
1061 | |||
897 | fprintf(fp, " "); | 1062 | fprintf(fp, " "); |
898 | for (i = 0; i < strlen(se->header); i++) | 1063 | for (i = 0; i < strlen(se->header); i++) |
899 | fprintf(fp, "."); | 1064 | fprintf(fp, "."); |
@@ -907,7 +1072,8 @@ static size_t output__fprintf(FILE *fp, __u64 total_samples) | |||
907 | ret += hist_entry__fprintf(fp, pos, total_samples); | 1072 | ret += hist_entry__fprintf(fp, pos, total_samples); |
908 | } | 1073 | } |
909 | 1074 | ||
910 | if (!strcmp(sort_order, default_sort_order)) { | 1075 | if (sort_order == default_sort_order && |
1076 | parent_pattern == default_parent_pattern) { | ||
911 | fprintf(fp, "#\n"); | 1077 | fprintf(fp, "#\n"); |
912 | fprintf(fp, "# (For more details, try: perf report --sort comm,dso,symbol)\n"); | 1078 | fprintf(fp, "# (For more details, try: perf report --sort comm,dso,symbol)\n"); |
913 | fprintf(fp, "#\n"); | 1079 | fprintf(fp, "#\n"); |
@@ -932,7 +1098,21 @@ static unsigned long total = 0, | |||
932 | total_mmap = 0, | 1098 | total_mmap = 0, |
933 | total_comm = 0, | 1099 | total_comm = 0, |
934 | total_fork = 0, | 1100 | total_fork = 0, |
935 | total_unknown = 0; | 1101 | total_unknown = 0, |
1102 | total_lost = 0; | ||
1103 | |||
1104 | static int validate_chain(struct ip_callchain *chain, event_t *event) | ||
1105 | { | ||
1106 | unsigned int chain_size; | ||
1107 | |||
1108 | chain_size = event->header.size; | ||
1109 | chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event; | ||
1110 | |||
1111 | if (chain->nr*sizeof(u64) > chain_size) | ||
1112 | return -1; | ||
1113 | |||
1114 | return 0; | ||
1115 | } | ||
936 | 1116 | ||
937 | static int | 1117 | static int |
938 | process_overflow_event(event_t *event, unsigned long offset, unsigned long head) | 1118 | process_overflow_event(event_t *event, unsigned long offset, unsigned long head) |
@@ -941,12 +1121,16 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head) | |||
941 | int show = 0; | 1121 | int show = 0; |
942 | struct dso *dso = NULL; | 1122 | struct dso *dso = NULL; |
943 | struct thread *thread = threads__findnew(event->ip.pid); | 1123 | struct thread *thread = threads__findnew(event->ip.pid); |
944 | __u64 ip = event->ip.ip; | 1124 | u64 ip = event->ip.ip; |
945 | __u64 period = 1; | 1125 | u64 period = 1; |
946 | struct map *map = NULL; | 1126 | struct map *map = NULL; |
1127 | void *more_data = event->ip.__more_data; | ||
1128 | struct ip_callchain *chain = NULL; | ||
947 | 1129 | ||
948 | if (event->header.type & PERF_SAMPLE_PERIOD) | 1130 | if (event->header.type & PERF_SAMPLE_PERIOD) { |
949 | period = event->ip.period; | 1131 | period = *(u64 *)more_data; |
1132 | more_data += sizeof(u64); | ||
1133 | } | ||
950 | 1134 | ||
951 | dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p period: %Ld\n", | 1135 | dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p period: %Ld\n", |
952 | (void *)(offset + head), | 1136 | (void *)(offset + head), |
@@ -956,10 +1140,28 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head) | |||
956 | (void *)(long)ip, | 1140 | (void *)(long)ip, |
957 | (long long)period); | 1141 | (long long)period); |
958 | 1142 | ||
1143 | if (event->header.type & PERF_SAMPLE_CALLCHAIN) { | ||
1144 | int i; | ||
1145 | |||
1146 | chain = (void *)more_data; | ||
1147 | |||
1148 | dprintf("... chain: nr:%Lu\n", chain->nr); | ||
1149 | |||
1150 | if (validate_chain(chain, event) < 0) { | ||
1151 | eprintf("call-chain problem with event, skipping it.\n"); | ||
1152 | return 0; | ||
1153 | } | ||
1154 | |||
1155 | if (dump_trace) { | ||
1156 | for (i = 0; i < chain->nr; i++) | ||
1157 | dprintf("..... %2d: %016Lx\n", i, chain->ips[i]); | ||
1158 | } | ||
1159 | } | ||
1160 | |||
959 | dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 1161 | dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid); |
960 | 1162 | ||
961 | if (thread == NULL) { | 1163 | if (thread == NULL) { |
962 | fprintf(stderr, "problem processing %d event, skipping it.\n", | 1164 | eprintf("problem processing %d event, skipping it.\n", |
963 | event->header.type); | 1165 | event->header.type); |
964 | return -1; | 1166 | return -1; |
965 | } | 1167 | } |
@@ -977,22 +1179,6 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head) | |||
977 | show = SHOW_USER; | 1179 | show = SHOW_USER; |
978 | level = '.'; | 1180 | level = '.'; |
979 | 1181 | ||
980 | map = thread__find_map(thread, ip); | ||
981 | if (map != NULL) { | ||
982 | ip = map->map_ip(map, ip); | ||
983 | dso = map->dso; | ||
984 | } else { | ||
985 | /* | ||
986 | * If this is outside of all known maps, | ||
987 | * and is a negative address, try to look it | ||
988 | * up in the kernel dso, as it might be a | ||
989 | * vsyscall (which executes in user-mode): | ||
990 | */ | ||
991 | if ((long long)ip < 0) | ||
992 | dso = kernel_dso; | ||
993 | } | ||
994 | dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); | ||
995 | |||
996 | } else { | 1182 | } else { |
997 | show = SHOW_HV; | 1183 | show = SHOW_HV; |
998 | level = 'H'; | 1184 | level = 'H'; |
@@ -1000,14 +1186,10 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head) | |||
1000 | } | 1186 | } |
1001 | 1187 | ||
1002 | if (show & show_mask) { | 1188 | if (show & show_mask) { |
1003 | struct symbol *sym = NULL; | 1189 | struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip); |
1004 | |||
1005 | if (dso) | ||
1006 | sym = dso->find_symbol(dso, ip); | ||
1007 | 1190 | ||
1008 | if (hist_entry__add(thread, map, dso, sym, ip, level, period)) { | 1191 | if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) { |
1009 | fprintf(stderr, | 1192 | eprintf("problem incrementing symbol count, skipping event\n"); |
1010 | "problem incrementing symbol count, skipping event\n"); | ||
1011 | return -1; | 1193 | return -1; |
1012 | } | 1194 | } |
1013 | } | 1195 | } |
@@ -1096,8 +1278,60 @@ process_period_event(event_t *event, unsigned long offset, unsigned long head) | |||
1096 | } | 1278 | } |
1097 | 1279 | ||
1098 | static int | 1280 | static int |
1281 | process_lost_event(event_t *event, unsigned long offset, unsigned long head) | ||
1282 | { | ||
1283 | dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n", | ||
1284 | (void *)(offset + head), | ||
1285 | (void *)(long)(event->header.size), | ||
1286 | event->lost.id, | ||
1287 | event->lost.lost); | ||
1288 | |||
1289 | total_lost += event->lost.lost; | ||
1290 | |||
1291 | return 0; | ||
1292 | } | ||
1293 | |||
1294 | static void trace_event(event_t *event) | ||
1295 | { | ||
1296 | unsigned char *raw_event = (void *)event; | ||
1297 | char *color = PERF_COLOR_BLUE; | ||
1298 | int i, j; | ||
1299 | |||
1300 | if (!dump_trace) | ||
1301 | return; | ||
1302 | |||
1303 | dprintf("."); | ||
1304 | cdprintf("\n. ... raw event: size %d bytes\n", event->header.size); | ||
1305 | |||
1306 | for (i = 0; i < event->header.size; i++) { | ||
1307 | if ((i & 15) == 0) { | ||
1308 | dprintf("."); | ||
1309 | cdprintf(" %04x: ", i); | ||
1310 | } | ||
1311 | |||
1312 | cdprintf(" %02x", raw_event[i]); | ||
1313 | |||
1314 | if (((i & 15) == 15) || i == event->header.size-1) { | ||
1315 | cdprintf(" "); | ||
1316 | for (j = 0; j < 15-(i & 15); j++) | ||
1317 | cdprintf(" "); | ||
1318 | for (j = 0; j < (i & 15); j++) { | ||
1319 | if (isprint(raw_event[i-15+j])) | ||
1320 | cdprintf("%c", raw_event[i-15+j]); | ||
1321 | else | ||
1322 | cdprintf("."); | ||
1323 | } | ||
1324 | cdprintf("\n"); | ||
1325 | } | ||
1326 | } | ||
1327 | dprintf(".\n"); | ||
1328 | } | ||
1329 | |||
1330 | static int | ||
1099 | process_event(event_t *event, unsigned long offset, unsigned long head) | 1331 | process_event(event_t *event, unsigned long offset, unsigned long head) |
1100 | { | 1332 | { |
1333 | trace_event(event); | ||
1334 | |||
1101 | if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) | 1335 | if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) |
1102 | return process_overflow_event(event, offset, head); | 1336 | return process_overflow_event(event, offset, head); |
1103 | 1337 | ||
@@ -1113,6 +1347,10 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
1113 | 1347 | ||
1114 | case PERF_EVENT_PERIOD: | 1348 | case PERF_EVENT_PERIOD: |
1115 | return process_period_event(event, offset, head); | 1349 | return process_period_event(event, offset, head); |
1350 | |||
1351 | case PERF_EVENT_LOST: | ||
1352 | return process_lost_event(event, offset, head); | ||
1353 | |||
1116 | /* | 1354 | /* |
1117 | * We dont process them right now but they are fine: | 1355 | * We dont process them right now but they are fine: |
1118 | */ | 1356 | */ |
@@ -1128,11 +1366,13 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
1128 | return 0; | 1366 | return 0; |
1129 | } | 1367 | } |
1130 | 1368 | ||
1369 | static struct perf_file_header file_header; | ||
1370 | |||
1131 | static int __cmd_report(void) | 1371 | static int __cmd_report(void) |
1132 | { | 1372 | { |
1133 | int ret, rc = EXIT_FAILURE; | 1373 | int ret, rc = EXIT_FAILURE; |
1134 | unsigned long offset = 0; | 1374 | unsigned long offset = 0; |
1135 | unsigned long head = 0; | 1375 | unsigned long head = sizeof(file_header); |
1136 | struct stat stat; | 1376 | struct stat stat; |
1137 | event_t *event; | 1377 | event_t *event; |
1138 | uint32_t size; | 1378 | uint32_t size; |
@@ -1160,6 +1400,17 @@ static int __cmd_report(void) | |||
1160 | exit(0); | 1400 | exit(0); |
1161 | } | 1401 | } |
1162 | 1402 | ||
1403 | if (read(input, &file_header, sizeof(file_header)) == -1) { | ||
1404 | perror("failed to read file headers"); | ||
1405 | exit(-1); | ||
1406 | } | ||
1407 | |||
1408 | if (sort__has_parent && | ||
1409 | !(file_header.sample_type & PERF_SAMPLE_CALLCHAIN)) { | ||
1410 | fprintf(stderr, "selected --sort parent, but no callchain data\n"); | ||
1411 | exit(-1); | ||
1412 | } | ||
1413 | |||
1163 | if (load_kernel() < 0) { | 1414 | if (load_kernel() < 0) { |
1164 | perror("failed to load kernel symbols"); | 1415 | perror("failed to load kernel symbols"); |
1165 | return EXIT_FAILURE; | 1416 | return EXIT_FAILURE; |
@@ -1204,7 +1455,7 @@ more: | |||
1204 | 1455 | ||
1205 | size = event->header.size; | 1456 | size = event->header.size; |
1206 | 1457 | ||
1207 | dprintf("%p [%p]: event: %d\n", | 1458 | dprintf("\n%p [%p]: event: %d\n", |
1208 | (void *)(offset + head), | 1459 | (void *)(offset + head), |
1209 | (void *)(long)event->header.size, | 1460 | (void *)(long)event->header.size, |
1210 | event->header.type); | 1461 | event->header.type); |
@@ -1231,9 +1482,13 @@ more: | |||
1231 | 1482 | ||
1232 | head += size; | 1483 | head += size; |
1233 | 1484 | ||
1485 | if (offset + head >= sizeof(file_header) + file_header.data_size) | ||
1486 | goto done; | ||
1487 | |||
1234 | if (offset + head < stat.st_size) | 1488 | if (offset + head < stat.st_size) |
1235 | goto more; | 1489 | goto more; |
1236 | 1490 | ||
1491 | done: | ||
1237 | rc = EXIT_SUCCESS; | 1492 | rc = EXIT_SUCCESS; |
1238 | close(input); | 1493 | close(input); |
1239 | 1494 | ||
@@ -1241,6 +1496,7 @@ more: | |||
1241 | dprintf(" mmap events: %10ld\n", total_mmap); | 1496 | dprintf(" mmap events: %10ld\n", total_mmap); |
1242 | dprintf(" comm events: %10ld\n", total_comm); | 1497 | dprintf(" comm events: %10ld\n", total_comm); |
1243 | dprintf(" fork events: %10ld\n", total_fork); | 1498 | dprintf(" fork events: %10ld\n", total_fork); |
1499 | dprintf(" lost events: %10ld\n", total_lost); | ||
1244 | dprintf(" unknown events: %10ld\n", total_unknown); | 1500 | dprintf(" unknown events: %10ld\n", total_unknown); |
1245 | 1501 | ||
1246 | if (dump_trace) | 1502 | if (dump_trace) |
@@ -1273,9 +1529,13 @@ static const struct option options[] = { | |||
1273 | "dump raw trace in ASCII"), | 1529 | "dump raw trace in ASCII"), |
1274 | OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), | 1530 | OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), |
1275 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", | 1531 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", |
1276 | "sort by key(s): pid, comm, dso, symbol. Default: pid,symbol"), | 1532 | "sort by key(s): pid, comm, dso, symbol, parent"), |
1277 | OPT_BOOLEAN('P', "full-paths", &full_paths, | 1533 | OPT_BOOLEAN('P', "full-paths", &full_paths, |
1278 | "Don't shorten the pathnames taking into account the cwd"), | 1534 | "Don't shorten the pathnames taking into account the cwd"), |
1535 | OPT_STRING('p', "parent", &parent_pattern, "regex", | ||
1536 | "regex filter to identify parent, see: '--sort parent'"), | ||
1537 | OPT_BOOLEAN('x', "exclude-other", &exclude_other, | ||
1538 | "Only display entries with parent-match"), | ||
1279 | OPT_END() | 1539 | OPT_END() |
1280 | }; | 1540 | }; |
1281 | 1541 | ||
@@ -1304,6 +1564,11 @@ int cmd_report(int argc, const char **argv, const char *prefix) | |||
1304 | 1564 | ||
1305 | setup_sorting(); | 1565 | setup_sorting(); |
1306 | 1566 | ||
1567 | if (parent_pattern != default_parent_pattern) | ||
1568 | sort_dimension__add("parent"); | ||
1569 | else | ||
1570 | exclude_other = 0; | ||
1571 | |||
1307 | /* | 1572 | /* |
1308 | * Any (unrecognized) arguments left? | 1573 | * Any (unrecognized) arguments left? |
1309 | */ | 1574 | */ |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index c43e4a97dc42..6d3eeac1ea25 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include "util/parse-events.h" | 43 | #include "util/parse-events.h" |
44 | 44 | ||
45 | #include <sys/prctl.h> | 45 | #include <sys/prctl.h> |
46 | #include <math.h> | ||
46 | 47 | ||
47 | static struct perf_counter_attr default_attrs[MAX_COUNTERS] = { | 48 | static struct perf_counter_attr default_attrs[MAX_COUNTERS] = { |
48 | 49 | ||
@@ -79,12 +80,34 @@ static const unsigned int default_count[] = { | |||
79 | 10000, | 80 | 10000, |
80 | }; | 81 | }; |
81 | 82 | ||
82 | static __u64 event_res[MAX_COUNTERS][3]; | 83 | #define MAX_RUN 100 |
83 | static __u64 event_scaled[MAX_COUNTERS]; | ||
84 | 84 | ||
85 | static __u64 runtime_nsecs; | 85 | static int run_count = 1; |
86 | static __u64 walltime_nsecs; | 86 | static int run_idx = 0; |
87 | static __u64 runtime_cycles; | 87 | |
88 | static u64 event_res[MAX_RUN][MAX_COUNTERS][3]; | ||
89 | static u64 event_scaled[MAX_RUN][MAX_COUNTERS]; | ||
90 | |||
91 | //static u64 event_hist[MAX_RUN][MAX_COUNTERS][3]; | ||
92 | |||
93 | |||
94 | static u64 runtime_nsecs[MAX_RUN]; | ||
95 | static u64 walltime_nsecs[MAX_RUN]; | ||
96 | static u64 runtime_cycles[MAX_RUN]; | ||
97 | |||
98 | static u64 event_res_avg[MAX_COUNTERS][3]; | ||
99 | static u64 event_res_noise[MAX_COUNTERS][3]; | ||
100 | |||
101 | static u64 event_scaled_avg[MAX_COUNTERS]; | ||
102 | |||
103 | static u64 runtime_nsecs_avg; | ||
104 | static u64 runtime_nsecs_noise; | ||
105 | |||
106 | static u64 walltime_nsecs_avg; | ||
107 | static u64 walltime_nsecs_noise; | ||
108 | |||
109 | static u64 runtime_cycles_avg; | ||
110 | static u64 runtime_cycles_noise; | ||
88 | 111 | ||
89 | static void create_perf_stat_counter(int counter) | 112 | static void create_perf_stat_counter(int counter) |
90 | { | 113 | { |
@@ -135,12 +158,12 @@ static inline int nsec_counter(int counter) | |||
135 | */ | 158 | */ |
136 | static void read_counter(int counter) | 159 | static void read_counter(int counter) |
137 | { | 160 | { |
138 | __u64 *count, single_count[3]; | 161 | u64 *count, single_count[3]; |
139 | ssize_t res; | 162 | ssize_t res; |
140 | int cpu, nv; | 163 | int cpu, nv; |
141 | int scaled; | 164 | int scaled; |
142 | 165 | ||
143 | count = event_res[counter]; | 166 | count = event_res[run_idx][counter]; |
144 | 167 | ||
145 | count[0] = count[1] = count[2] = 0; | 168 | count[0] = count[1] = count[2] = 0; |
146 | 169 | ||
@@ -149,8 +172,10 @@ static void read_counter(int counter) | |||
149 | if (fd[cpu][counter] < 0) | 172 | if (fd[cpu][counter] < 0) |
150 | continue; | 173 | continue; |
151 | 174 | ||
152 | res = read(fd[cpu][counter], single_count, nv * sizeof(__u64)); | 175 | res = read(fd[cpu][counter], single_count, nv * sizeof(u64)); |
153 | assert(res == nv * sizeof(__u64)); | 176 | assert(res == nv * sizeof(u64)); |
177 | close(fd[cpu][counter]); | ||
178 | fd[cpu][counter] = -1; | ||
154 | 179 | ||
155 | count[0] += single_count[0]; | 180 | count[0] += single_count[0]; |
156 | if (scale) { | 181 | if (scale) { |
@@ -162,13 +187,13 @@ static void read_counter(int counter) | |||
162 | scaled = 0; | 187 | scaled = 0; |
163 | if (scale) { | 188 | if (scale) { |
164 | if (count[2] == 0) { | 189 | if (count[2] == 0) { |
165 | event_scaled[counter] = -1; | 190 | event_scaled[run_idx][counter] = -1; |
166 | count[0] = 0; | 191 | count[0] = 0; |
167 | return; | 192 | return; |
168 | } | 193 | } |
169 | 194 | ||
170 | if (count[2] < count[1]) { | 195 | if (count[2] < count[1]) { |
171 | event_scaled[counter] = 1; | 196 | event_scaled[run_idx][counter] = 1; |
172 | count[0] = (unsigned long long) | 197 | count[0] = (unsigned long long) |
173 | ((double)count[0] * count[1] / count[2] + 0.5); | 198 | ((double)count[0] * count[1] / count[2] + 0.5); |
174 | } | 199 | } |
@@ -178,10 +203,94 @@ static void read_counter(int counter) | |||
178 | */ | 203 | */ |
179 | if (attrs[counter].type == PERF_TYPE_SOFTWARE && | 204 | if (attrs[counter].type == PERF_TYPE_SOFTWARE && |
180 | attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK) | 205 | attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK) |
181 | runtime_nsecs = count[0]; | 206 | runtime_nsecs[run_idx] = count[0]; |
182 | if (attrs[counter].type == PERF_TYPE_HARDWARE && | 207 | if (attrs[counter].type == PERF_TYPE_HARDWARE && |
183 | attrs[counter].config == PERF_COUNT_HW_CPU_CYCLES) | 208 | attrs[counter].config == PERF_COUNT_HW_CPU_CYCLES) |
184 | runtime_cycles = count[0]; | 209 | runtime_cycles[run_idx] = count[0]; |
210 | } | ||
211 | |||
212 | static int run_perf_stat(int argc, const char **argv) | ||
213 | { | ||
214 | unsigned long long t0, t1; | ||
215 | int status = 0; | ||
216 | int counter; | ||
217 | int pid; | ||
218 | |||
219 | if (!system_wide) | ||
220 | nr_cpus = 1; | ||
221 | |||
222 | for (counter = 0; counter < nr_counters; counter++) | ||
223 | create_perf_stat_counter(counter); | ||
224 | |||
225 | /* | ||
226 | * Enable counters and exec the command: | ||
227 | */ | ||
228 | t0 = rdclock(); | ||
229 | prctl(PR_TASK_PERF_COUNTERS_ENABLE); | ||
230 | |||
231 | if ((pid = fork()) < 0) | ||
232 | perror("failed to fork"); | ||
233 | |||
234 | if (!pid) { | ||
235 | if (execvp(argv[0], (char **)argv)) { | ||
236 | perror(argv[0]); | ||
237 | exit(-1); | ||
238 | } | ||
239 | } | ||
240 | |||
241 | wait(&status); | ||
242 | |||
243 | prctl(PR_TASK_PERF_COUNTERS_DISABLE); | ||
244 | t1 = rdclock(); | ||
245 | |||
246 | walltime_nsecs[run_idx] = t1 - t0; | ||
247 | |||
248 | for (counter = 0; counter < nr_counters; counter++) | ||
249 | read_counter(counter); | ||
250 | |||
251 | return WEXITSTATUS(status); | ||
252 | } | ||
253 | |||
254 | static void print_noise(u64 *count, u64 *noise) | ||
255 | { | ||
256 | if (run_count > 1) | ||
257 | fprintf(stderr, " ( +- %7.3f%% )", | ||
258 | (double)noise[0]/(count[0]+1)*100.0); | ||
259 | } | ||
260 | |||
261 | static void nsec_printout(int counter, u64 *count, u64 *noise) | ||
262 | { | ||
263 | double msecs = (double)count[0] / 1000000; | ||
264 | |||
265 | fprintf(stderr, " %14.6f %-20s", msecs, event_name(counter)); | ||
266 | |||
267 | if (attrs[counter].type == PERF_TYPE_SOFTWARE && | ||
268 | attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK) { | ||
269 | |||
270 | if (walltime_nsecs_avg) | ||
271 | fprintf(stderr, " # %10.3f CPUs ", | ||
272 | (double)count[0] / (double)walltime_nsecs_avg); | ||
273 | } | ||
274 | print_noise(count, noise); | ||
275 | } | ||
276 | |||
277 | static void abs_printout(int counter, u64 *count, u64 *noise) | ||
278 | { | ||
279 | fprintf(stderr, " %14Ld %-20s", count[0], event_name(counter)); | ||
280 | |||
281 | if (runtime_cycles_avg && | ||
282 | attrs[counter].type == PERF_TYPE_HARDWARE && | ||
283 | attrs[counter].config == PERF_COUNT_HW_INSTRUCTIONS) { | ||
284 | |||
285 | fprintf(stderr, " # %10.3f IPC ", | ||
286 | (double)count[0] / (double)runtime_cycles_avg); | ||
287 | } else { | ||
288 | if (runtime_nsecs_avg) { | ||
289 | fprintf(stderr, " # %10.3f M/sec", | ||
290 | (double)count[0]/runtime_nsecs_avg*1000.0); | ||
291 | } | ||
292 | } | ||
293 | print_noise(count, noise); | ||
185 | } | 294 | } |
186 | 295 | ||
187 | /* | 296 | /* |
@@ -189,11 +298,12 @@ static void read_counter(int counter) | |||
189 | */ | 298 | */ |
190 | static void print_counter(int counter) | 299 | static void print_counter(int counter) |
191 | { | 300 | { |
192 | __u64 *count; | 301 | u64 *count, *noise; |
193 | int scaled; | 302 | int scaled; |
194 | 303 | ||
195 | count = event_res[counter]; | 304 | count = event_res_avg[counter]; |
196 | scaled = event_scaled[counter]; | 305 | noise = event_res_noise[counter]; |
306 | scaled = event_scaled_avg[counter]; | ||
197 | 307 | ||
198 | if (scaled == -1) { | 308 | if (scaled == -1) { |
199 | fprintf(stderr, " %14s %-20s\n", | 309 | fprintf(stderr, " %14s %-20s\n", |
@@ -201,75 +311,107 @@ static void print_counter(int counter) | |||
201 | return; | 311 | return; |
202 | } | 312 | } |
203 | 313 | ||
204 | if (nsec_counter(counter)) { | 314 | if (nsec_counter(counter)) |
205 | double msecs = (double)count[0] / 1000000; | 315 | nsec_printout(counter, count, noise); |
206 | 316 | else | |
207 | fprintf(stderr, " %14.6f %-20s", | 317 | abs_printout(counter, count, noise); |
208 | msecs, event_name(counter)); | ||
209 | if (attrs[counter].type == PERF_TYPE_SOFTWARE && | ||
210 | attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK) { | ||
211 | 318 | ||
212 | if (walltime_nsecs) | ||
213 | fprintf(stderr, " # %11.3f CPU utilization factor", | ||
214 | (double)count[0] / (double)walltime_nsecs); | ||
215 | } | ||
216 | } else { | ||
217 | fprintf(stderr, " %14Ld %-20s", | ||
218 | count[0], event_name(counter)); | ||
219 | if (runtime_nsecs) | ||
220 | fprintf(stderr, " # %11.3f M/sec", | ||
221 | (double)count[0]/runtime_nsecs*1000.0); | ||
222 | if (runtime_cycles && | ||
223 | attrs[counter].type == PERF_TYPE_HARDWARE && | ||
224 | attrs[counter].config == PERF_COUNT_HW_INSTRUCTIONS) { | ||
225 | |||
226 | fprintf(stderr, " # %1.3f per cycle", | ||
227 | (double)count[0] / (double)runtime_cycles); | ||
228 | } | ||
229 | } | ||
230 | if (scaled) | 319 | if (scaled) |
231 | fprintf(stderr, " (scaled from %.2f%%)", | 320 | fprintf(stderr, " (scaled from %.2f%%)", |
232 | (double) count[2] / count[1] * 100); | 321 | (double) count[2] / count[1] * 100); |
322 | |||
233 | fprintf(stderr, "\n"); | 323 | fprintf(stderr, "\n"); |
234 | } | 324 | } |
235 | 325 | ||
236 | static int do_perf_stat(int argc, const char **argv) | 326 | /* |
327 | * normalize_noise noise values down to stddev: | ||
328 | */ | ||
329 | static void normalize_noise(u64 *val) | ||
237 | { | 330 | { |
238 | unsigned long long t0, t1; | 331 | double res; |
239 | int counter; | ||
240 | int status; | ||
241 | int pid; | ||
242 | int i; | ||
243 | 332 | ||
244 | if (!system_wide) | 333 | res = (double)*val / (run_count * sqrt((double)run_count)); |
245 | nr_cpus = 1; | ||
246 | 334 | ||
247 | for (counter = 0; counter < nr_counters; counter++) | 335 | *val = (u64)res; |
248 | create_perf_stat_counter(counter); | 336 | } |
249 | 337 | ||
250 | /* | 338 | static void update_avg(const char *name, int idx, u64 *avg, u64 *val) |
251 | * Enable counters and exec the command: | 339 | { |
252 | */ | 340 | *avg += *val; |
253 | t0 = rdclock(); | ||
254 | prctl(PR_TASK_PERF_COUNTERS_ENABLE); | ||
255 | 341 | ||
256 | if ((pid = fork()) < 0) | 342 | if (verbose > 1) |
257 | perror("failed to fork"); | 343 | fprintf(stderr, "debug: %20s[%d]: %Ld\n", name, idx, *val); |
344 | } | ||
345 | /* | ||
346 | * Calculate the averages and noises: | ||
347 | */ | ||
348 | static void calc_avg(void) | ||
349 | { | ||
350 | int i, j; | ||
351 | |||
352 | if (verbose > 1) | ||
353 | fprintf(stderr, "\n"); | ||
354 | |||
355 | for (i = 0; i < run_count; i++) { | ||
356 | update_avg("runtime", 0, &runtime_nsecs_avg, runtime_nsecs + i); | ||
357 | update_avg("walltime", 0, &walltime_nsecs_avg, walltime_nsecs + i); | ||
358 | update_avg("runtime_cycles", 0, &runtime_cycles_avg, runtime_cycles + i); | ||
359 | |||
360 | for (j = 0; j < nr_counters; j++) { | ||
361 | update_avg("counter/0", j, | ||
362 | event_res_avg[j]+0, event_res[i][j]+0); | ||
363 | update_avg("counter/1", j, | ||
364 | event_res_avg[j]+1, event_res[i][j]+1); | ||
365 | update_avg("counter/2", j, | ||
366 | event_res_avg[j]+2, event_res[i][j]+2); | ||
367 | update_avg("scaled", j, | ||
368 | event_scaled_avg + j, event_scaled[i]+j); | ||
369 | } | ||
370 | } | ||
371 | runtime_nsecs_avg /= run_count; | ||
372 | walltime_nsecs_avg /= run_count; | ||
373 | runtime_cycles_avg /= run_count; | ||
374 | |||
375 | for (j = 0; j < nr_counters; j++) { | ||
376 | event_res_avg[j][0] /= run_count; | ||
377 | event_res_avg[j][1] /= run_count; | ||
378 | event_res_avg[j][2] /= run_count; | ||
379 | } | ||
258 | 380 | ||
259 | if (!pid) { | 381 | for (i = 0; i < run_count; i++) { |
260 | if (execvp(argv[0], (char **)argv)) { | 382 | runtime_nsecs_noise += |
261 | perror(argv[0]); | 383 | abs((s64)(runtime_nsecs[i] - runtime_nsecs_avg)); |
262 | exit(-1); | 384 | walltime_nsecs_noise += |
385 | abs((s64)(walltime_nsecs[i] - walltime_nsecs_avg)); | ||
386 | runtime_cycles_noise += | ||
387 | abs((s64)(runtime_cycles[i] - runtime_cycles_avg)); | ||
388 | |||
389 | for (j = 0; j < nr_counters; j++) { | ||
390 | event_res_noise[j][0] += | ||
391 | abs((s64)(event_res[i][j][0] - event_res_avg[j][0])); | ||
392 | event_res_noise[j][1] += | ||
393 | abs((s64)(event_res[i][j][1] - event_res_avg[j][1])); | ||
394 | event_res_noise[j][2] += | ||
395 | abs((s64)(event_res[i][j][2] - event_res_avg[j][2])); | ||
263 | } | 396 | } |
264 | } | 397 | } |
265 | 398 | ||
266 | while (wait(&status) >= 0) | 399 | normalize_noise(&runtime_nsecs_noise); |
267 | ; | 400 | normalize_noise(&walltime_nsecs_noise); |
401 | normalize_noise(&runtime_cycles_noise); | ||
268 | 402 | ||
269 | prctl(PR_TASK_PERF_COUNTERS_DISABLE); | 403 | for (j = 0; j < nr_counters; j++) { |
270 | t1 = rdclock(); | 404 | normalize_noise(&event_res_noise[j][0]); |
405 | normalize_noise(&event_res_noise[j][1]); | ||
406 | normalize_noise(&event_res_noise[j][2]); | ||
407 | } | ||
408 | } | ||
271 | 409 | ||
272 | walltime_nsecs = t1 - t0; | 410 | static void print_stat(int argc, const char **argv) |
411 | { | ||
412 | int i, counter; | ||
413 | |||
414 | calc_avg(); | ||
273 | 415 | ||
274 | fflush(stdout); | 416 | fflush(stdout); |
275 | 417 | ||
@@ -279,22 +421,19 @@ static int do_perf_stat(int argc, const char **argv) | |||
279 | for (i = 1; i < argc; i++) | 421 | for (i = 1; i < argc; i++) |
280 | fprintf(stderr, " %s", argv[i]); | 422 | fprintf(stderr, " %s", argv[i]); |
281 | 423 | ||
282 | fprintf(stderr, "\':\n"); | 424 | fprintf(stderr, "\'"); |
283 | fprintf(stderr, "\n"); | 425 | if (run_count > 1) |
284 | 426 | fprintf(stderr, " (%d runs)", run_count); | |
285 | for (counter = 0; counter < nr_counters; counter++) | 427 | fprintf(stderr, ":\n\n"); |
286 | read_counter(counter); | ||
287 | 428 | ||
288 | for (counter = 0; counter < nr_counters; counter++) | 429 | for (counter = 0; counter < nr_counters; counter++) |
289 | print_counter(counter); | 430 | print_counter(counter); |
290 | 431 | ||
291 | 432 | ||
292 | fprintf(stderr, "\n"); | 433 | fprintf(stderr, "\n"); |
293 | fprintf(stderr, " Wall-clock time elapsed: %12.6f msecs\n", | 434 | fprintf(stderr, " %14.9f seconds time elapsed.\n", |
294 | (double)(t1-t0)/1e6); | 435 | (double)walltime_nsecs_avg/1e9); |
295 | fprintf(stderr, "\n"); | 436 | fprintf(stderr, "\n"); |
296 | |||
297 | return 0; | ||
298 | } | 437 | } |
299 | 438 | ||
300 | static volatile int signr = -1; | 439 | static volatile int signr = -1; |
@@ -332,11 +471,15 @@ static const struct option options[] = { | |||
332 | "scale/normalize counters"), | 471 | "scale/normalize counters"), |
333 | OPT_BOOLEAN('v', "verbose", &verbose, | 472 | OPT_BOOLEAN('v', "verbose", &verbose, |
334 | "be more verbose (show counter open errors, etc)"), | 473 | "be more verbose (show counter open errors, etc)"), |
474 | OPT_INTEGER('r', "repeat", &run_count, | ||
475 | "repeat command and print average + stddev (max: 100)"), | ||
335 | OPT_END() | 476 | OPT_END() |
336 | }; | 477 | }; |
337 | 478 | ||
338 | int cmd_stat(int argc, const char **argv, const char *prefix) | 479 | int cmd_stat(int argc, const char **argv, const char *prefix) |
339 | { | 480 | { |
481 | int status; | ||
482 | |||
340 | page_size = sysconf(_SC_PAGE_SIZE); | 483 | page_size = sysconf(_SC_PAGE_SIZE); |
341 | 484 | ||
342 | memcpy(attrs, default_attrs, sizeof(attrs)); | 485 | memcpy(attrs, default_attrs, sizeof(attrs)); |
@@ -344,6 +487,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix) | |||
344 | argc = parse_options(argc, argv, options, stat_usage, 0); | 487 | argc = parse_options(argc, argv, options, stat_usage, 0); |
345 | if (!argc) | 488 | if (!argc) |
346 | usage_with_options(stat_usage, options); | 489 | usage_with_options(stat_usage, options); |
490 | if (run_count <= 0 || run_count > MAX_RUN) | ||
491 | usage_with_options(stat_usage, options); | ||
347 | 492 | ||
348 | if (!nr_counters) | 493 | if (!nr_counters) |
349 | nr_counters = 8; | 494 | nr_counters = 8; |
@@ -363,5 +508,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix) | |||
363 | signal(SIGALRM, skip_signal); | 508 | signal(SIGALRM, skip_signal); |
364 | signal(SIGABRT, skip_signal); | 509 | signal(SIGABRT, skip_signal); |
365 | 510 | ||
366 | return do_perf_stat(argc, argv); | 511 | status = 0; |
512 | for (run_idx = 0; run_idx < run_count; run_idx++) { | ||
513 | if (run_count != 1 && verbose) | ||
514 | fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx+1); | ||
515 | status = run_perf_stat(argc, argv); | ||
516 | } | ||
517 | |||
518 | print_stat(argc, argv); | ||
519 | |||
520 | return status; | ||
367 | } | 521 | } |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index fe338d3c5d7e..5352b5e352ed 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -54,7 +54,7 @@ static int system_wide = 0; | |||
54 | 54 | ||
55 | static int default_interval = 100000; | 55 | static int default_interval = 100000; |
56 | 56 | ||
57 | static __u64 count_filter = 5; | 57 | static u64 count_filter = 5; |
58 | static int print_entries = 15; | 58 | static int print_entries = 15; |
59 | 59 | ||
60 | static int target_pid = -1; | 60 | static int target_pid = -1; |
@@ -79,8 +79,8 @@ static int dump_symtab; | |||
79 | * Symbols | 79 | * Symbols |
80 | */ | 80 | */ |
81 | 81 | ||
82 | static __u64 min_ip; | 82 | static u64 min_ip; |
83 | static __u64 max_ip = -1ll; | 83 | static u64 max_ip = -1ll; |
84 | 84 | ||
85 | struct sym_entry { | 85 | struct sym_entry { |
86 | struct rb_node rb_node; | 86 | struct rb_node rb_node; |
@@ -194,7 +194,7 @@ static void print_sym_table(void) | |||
194 | 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); | 194 | 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); |
195 | 195 | ||
196 | if (nr_counters == 1) { | 196 | if (nr_counters == 1) { |
197 | printf("%Ld", attrs[0].sample_period); | 197 | printf("%Ld", (u64)attrs[0].sample_period); |
198 | if (freq) | 198 | if (freq) |
199 | printf("Hz "); | 199 | printf("Hz "); |
200 | else | 200 | else |
@@ -372,7 +372,7 @@ out_delete_dso: | |||
372 | /* | 372 | /* |
373 | * Binary search in the histogram table and record the hit: | 373 | * Binary search in the histogram table and record the hit: |
374 | */ | 374 | */ |
375 | static void record_ip(__u64 ip, int counter) | 375 | static void record_ip(u64 ip, int counter) |
376 | { | 376 | { |
377 | struct symbol *sym = dso__find_symbol(kernel_dso, ip); | 377 | struct symbol *sym = dso__find_symbol(kernel_dso, ip); |
378 | 378 | ||
@@ -392,7 +392,7 @@ static void record_ip(__u64 ip, int counter) | |||
392 | samples--; | 392 | samples--; |
393 | } | 393 | } |
394 | 394 | ||
395 | static void process_event(__u64 ip, int counter) | 395 | static void process_event(u64 ip, int counter) |
396 | { | 396 | { |
397 | samples++; | 397 | samples++; |
398 | 398 | ||
@@ -463,15 +463,15 @@ static void mmap_read_counter(struct mmap_data *md) | |||
463 | for (; old != head;) { | 463 | for (; old != head;) { |
464 | struct ip_event { | 464 | struct ip_event { |
465 | struct perf_event_header header; | 465 | struct perf_event_header header; |
466 | __u64 ip; | 466 | u64 ip; |
467 | __u32 pid, target_pid; | 467 | u32 pid, target_pid; |
468 | }; | 468 | }; |
469 | struct mmap_event { | 469 | struct mmap_event { |
470 | struct perf_event_header header; | 470 | struct perf_event_header header; |
471 | __u32 pid, target_pid; | 471 | u32 pid, target_pid; |
472 | __u64 start; | 472 | u64 start; |
473 | __u64 len; | 473 | u64 len; |
474 | __u64 pgoff; | 474 | u64 pgoff; |
475 | char filename[PATH_MAX]; | 475 | char filename[PATH_MAX]; |
476 | }; | 476 | }; |
477 | 477 | ||
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 87a1aca4a424..bccb529dac08 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <sys/syscall.h> | 19 | #include <sys/syscall.h> |
20 | 20 | ||
21 | #include "../../include/linux/perf_counter.h" | 21 | #include "../../include/linux/perf_counter.h" |
22 | #include "types.h" | ||
22 | 23 | ||
23 | /* | 24 | /* |
24 | * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all | 25 | * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all |
@@ -65,4 +66,10 @@ sys_perf_counter_open(struct perf_counter_attr *attr, | |||
65 | #define MAX_COUNTERS 256 | 66 | #define MAX_COUNTERS 256 |
66 | #define MAX_NR_CPUS 256 | 67 | #define MAX_NR_CPUS 256 |
67 | 68 | ||
69 | struct perf_file_header { | ||
70 | u64 version; | ||
71 | u64 sample_type; | ||
72 | u64 data_size; | ||
73 | }; | ||
74 | |||
68 | #endif | 75 | #endif |
diff --git a/tools/perf/types.h b/tools/perf/types.h new file mode 100644 index 000000000000..5e75f9005940 --- /dev/null +++ b/tools/perf/types.h | |||
@@ -0,0 +1,17 @@ | |||
1 | #ifndef _PERF_TYPES_H | ||
2 | #define _PERF_TYPES_H | ||
3 | |||
4 | /* | ||
5 | * We define u64 as unsigned long long for every architecture | ||
6 | * so that we can print it with %Lx without getting warnings. | ||
7 | */ | ||
8 | typedef unsigned long long u64; | ||
9 | typedef signed long long s64; | ||
10 | typedef unsigned int u32; | ||
11 | typedef signed int s32; | ||
12 | typedef unsigned short u16; | ||
13 | typedef signed short s16; | ||
14 | typedef unsigned char u8; | ||
15 | typedef signed char s8; | ||
16 | |||
17 | #endif /* _PERF_TYPES_H */ | ||
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c index b90ec004f29c..0b791bd346bc 100644 --- a/tools/perf/util/ctype.c +++ b/tools/perf/util/ctype.c | |||
@@ -11,16 +11,21 @@ enum { | |||
11 | D = GIT_DIGIT, | 11 | D = GIT_DIGIT, |
12 | G = GIT_GLOB_SPECIAL, /* *, ?, [, \\ */ | 12 | G = GIT_GLOB_SPECIAL, /* *, ?, [, \\ */ |
13 | R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | * */ | 13 | R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | * */ |
14 | P = GIT_PRINT_EXTRA, /* printable - alpha - digit - glob - regex */ | ||
15 | |||
16 | PS = GIT_SPACE | GIT_PRINT_EXTRA, | ||
14 | }; | 17 | }; |
15 | 18 | ||
16 | unsigned char sane_ctype[256] = { | 19 | unsigned char sane_ctype[256] = { |
20 | /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ | ||
21 | |||
17 | 0, 0, 0, 0, 0, 0, 0, 0, 0, S, S, 0, 0, S, 0, 0, /* 0.. 15 */ | 22 | 0, 0, 0, 0, 0, 0, 0, 0, 0, S, S, 0, 0, S, 0, 0, /* 0.. 15 */ |
18 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16.. 31 */ | 23 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16.. 31 */ |
19 | S, 0, 0, 0, R, 0, 0, 0, R, R, G, R, 0, 0, R, 0, /* 32.. 47 */ | 24 | PS,P, P, P, R, P, P, P, R, R, G, R, P, P, R, P, /* 32.. 47 */ |
20 | D, D, D, D, D, D, D, D, D, D, 0, 0, 0, 0, 0, G, /* 48.. 63 */ | 25 | D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, G, /* 48.. 63 */ |
21 | 0, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 64.. 79 */ | 26 | P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 64.. 79 */ |
22 | A, A, A, A, A, A, A, A, A, A, A, G, G, 0, R, 0, /* 80.. 95 */ | 27 | A, A, A, A, A, A, A, A, A, A, A, G, G, P, R, P, /* 80.. 95 */ |
23 | 0, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 96..111 */ | 28 | P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 96..111 */ |
24 | A, A, A, A, A, A, A, A, A, A, A, R, R, 0, 0, 0, /* 112..127 */ | 29 | A, A, A, A, A, A, A, A, A, A, A, R, R, P, P, 0, /* 112..127 */ |
25 | /* Nothing in the 128.. range */ | 30 | /* Nothing in the 128.. range */ |
26 | }; | 31 | }; |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 5a72586e1df0..35d04da38d6a 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -13,8 +13,8 @@ int nr_counters; | |||
13 | struct perf_counter_attr attrs[MAX_COUNTERS]; | 13 | struct perf_counter_attr attrs[MAX_COUNTERS]; |
14 | 14 | ||
15 | struct event_symbol { | 15 | struct event_symbol { |
16 | __u8 type; | 16 | u8 type; |
17 | __u64 config; | 17 | u64 config; |
18 | char *symbol; | 18 | char *symbol; |
19 | }; | 19 | }; |
20 | 20 | ||
@@ -63,8 +63,8 @@ static char *hw_event_names[] = { | |||
63 | }; | 63 | }; |
64 | 64 | ||
65 | static char *sw_event_names[] = { | 65 | static char *sw_event_names[] = { |
66 | "cpu-clock-ticks", | 66 | "cpu-clock-msecs", |
67 | "task-clock-ticks", | 67 | "task-clock-msecs", |
68 | "page-faults", | 68 | "page-faults", |
69 | "context-switches", | 69 | "context-switches", |
70 | "CPU-migrations", | 70 | "CPU-migrations", |
@@ -96,7 +96,7 @@ static char *hw_cache_result [][MAX_ALIASES] = { | |||
96 | 96 | ||
97 | char *event_name(int counter) | 97 | char *event_name(int counter) |
98 | { | 98 | { |
99 | __u64 config = attrs[counter].config; | 99 | u64 config = attrs[counter].config; |
100 | int type = attrs[counter].type; | 100 | int type = attrs[counter].type; |
101 | static char buf[32]; | 101 | static char buf[32]; |
102 | 102 | ||
@@ -112,7 +112,7 @@ char *event_name(int counter) | |||
112 | return "unknown-hardware"; | 112 | return "unknown-hardware"; |
113 | 113 | ||
114 | case PERF_TYPE_HW_CACHE: { | 114 | case PERF_TYPE_HW_CACHE: { |
115 | __u8 cache_type, cache_op, cache_result; | 115 | u8 cache_type, cache_op, cache_result; |
116 | static char name[100]; | 116 | static char name[100]; |
117 | 117 | ||
118 | cache_type = (config >> 0) & 0xff; | 118 | cache_type = (config >> 0) & 0xff; |
@@ -202,7 +202,7 @@ static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *a | |||
202 | */ | 202 | */ |
203 | static int parse_event_symbols(const char *str, struct perf_counter_attr *attr) | 203 | static int parse_event_symbols(const char *str, struct perf_counter_attr *attr) |
204 | { | 204 | { |
205 | __u64 config, id; | 205 | u64 config, id; |
206 | int type; | 206 | int type; |
207 | unsigned int i; | 207 | unsigned int i; |
208 | const char *sep, *pstr; | 208 | const char *sep, *pstr; |
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c index ec33c0c7f4e2..c93eca9a7be3 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c | |||
@@ -15,7 +15,7 @@ static int hex(char ch) | |||
15 | * While we find nice hex chars, build a long_val. | 15 | * While we find nice hex chars, build a long_val. |
16 | * Return number of chars processed. | 16 | * Return number of chars processed. |
17 | */ | 17 | */ |
18 | int hex2u64(const char *ptr, __u64 *long_val) | 18 | int hex2u64(const char *ptr, u64 *long_val) |
19 | { | 19 | { |
20 | const char *p = ptr; | 20 | const char *p = ptr; |
21 | *long_val = 0; | 21 | *long_val = 0; |
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h index 72812c1c9a7a..37b03255b425 100644 --- a/tools/perf/util/string.h +++ b/tools/perf/util/string.h | |||
@@ -1,8 +1,8 @@ | |||
1 | #ifndef _PERF_STRING_H_ | 1 | #ifndef _PERF_STRING_H_ |
2 | #define _PERF_STRING_H_ | 2 | #define _PERF_STRING_H_ |
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include "../types.h" |
5 | 5 | ||
6 | int hex2u64(const char *ptr, __u64 *val); | 6 | int hex2u64(const char *ptr, u64 *val); |
7 | 7 | ||
8 | #endif | 8 | #endif |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 49a55f813712..86e14375e74e 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -9,9 +9,9 @@ | |||
9 | 9 | ||
10 | const char *sym_hist_filter; | 10 | const char *sym_hist_filter; |
11 | 11 | ||
12 | static struct symbol *symbol__new(__u64 start, __u64 len, | 12 | static struct symbol *symbol__new(u64 start, u64 len, |
13 | const char *name, unsigned int priv_size, | 13 | const char *name, unsigned int priv_size, |
14 | __u64 obj_start, int verbose) | 14 | u64 obj_start, int verbose) |
15 | { | 15 | { |
16 | size_t namelen = strlen(name) + 1; | 16 | size_t namelen = strlen(name) + 1; |
17 | struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); | 17 | struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); |
@@ -21,14 +21,14 @@ static struct symbol *symbol__new(__u64 start, __u64 len, | |||
21 | 21 | ||
22 | if (verbose >= 2) | 22 | if (verbose >= 2) |
23 | printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", | 23 | printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", |
24 | (__u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); | 24 | (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); |
25 | 25 | ||
26 | self->obj_start= obj_start; | 26 | self->obj_start= obj_start; |
27 | self->hist = NULL; | 27 | self->hist = NULL; |
28 | self->hist_sum = 0; | 28 | self->hist_sum = 0; |
29 | 29 | ||
30 | if (sym_hist_filter && !strcmp(name, sym_hist_filter)) | 30 | if (sym_hist_filter && !strcmp(name, sym_hist_filter)) |
31 | self->hist = calloc(sizeof(__u64), len); | 31 | self->hist = calloc(sizeof(u64), len); |
32 | 32 | ||
33 | if (priv_size) { | 33 | if (priv_size) { |
34 | memset(self, 0, priv_size); | 34 | memset(self, 0, priv_size); |
@@ -89,7 +89,7 @@ static void dso__insert_symbol(struct dso *self, struct symbol *sym) | |||
89 | { | 89 | { |
90 | struct rb_node **p = &self->syms.rb_node; | 90 | struct rb_node **p = &self->syms.rb_node; |
91 | struct rb_node *parent = NULL; | 91 | struct rb_node *parent = NULL; |
92 | const __u64 ip = sym->start; | 92 | const u64 ip = sym->start; |
93 | struct symbol *s; | 93 | struct symbol *s; |
94 | 94 | ||
95 | while (*p != NULL) { | 95 | while (*p != NULL) { |
@@ -104,7 +104,7 @@ static void dso__insert_symbol(struct dso *self, struct symbol *sym) | |||
104 | rb_insert_color(&sym->rb_node, &self->syms); | 104 | rb_insert_color(&sym->rb_node, &self->syms); |
105 | } | 105 | } |
106 | 106 | ||
107 | struct symbol *dso__find_symbol(struct dso *self, __u64 ip) | 107 | struct symbol *dso__find_symbol(struct dso *self, u64 ip) |
108 | { | 108 | { |
109 | struct rb_node *n; | 109 | struct rb_node *n; |
110 | 110 | ||
@@ -151,7 +151,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb | |||
151 | goto out_failure; | 151 | goto out_failure; |
152 | 152 | ||
153 | while (!feof(file)) { | 153 | while (!feof(file)) { |
154 | __u64 start; | 154 | u64 start; |
155 | struct symbol *sym; | 155 | struct symbol *sym; |
156 | int line_len, len; | 156 | int line_len, len; |
157 | char symbol_type; | 157 | char symbol_type; |
@@ -232,7 +232,7 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verb | |||
232 | goto out_failure; | 232 | goto out_failure; |
233 | 233 | ||
234 | while (!feof(file)) { | 234 | while (!feof(file)) { |
235 | __u64 start, size; | 235 | u64 start, size; |
236 | struct symbol *sym; | 236 | struct symbol *sym; |
237 | int line_len, len; | 237 | int line_len, len; |
238 | 238 | ||
@@ -353,7 +353,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, | |||
353 | { | 353 | { |
354 | uint32_t nr_rel_entries, idx; | 354 | uint32_t nr_rel_entries, idx; |
355 | GElf_Sym sym; | 355 | GElf_Sym sym; |
356 | __u64 plt_offset; | 356 | u64 plt_offset; |
357 | GElf_Shdr shdr_plt; | 357 | GElf_Shdr shdr_plt; |
358 | struct symbol *f; | 358 | struct symbol *f; |
359 | GElf_Shdr shdr_rel_plt; | 359 | GElf_Shdr shdr_rel_plt; |
@@ -523,7 +523,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
523 | 523 | ||
524 | elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { | 524 | elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { |
525 | struct symbol *f; | 525 | struct symbol *f; |
526 | __u64 obj_start; | 526 | u64 obj_start; |
527 | 527 | ||
528 | if (!elf_sym__is_function(&sym)) | 528 | if (!elf_sym__is_function(&sym)) |
529 | continue; | 529 | continue; |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 0d1292bd8270..ea332e56e458 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -2,16 +2,18 @@ | |||
2 | #define _PERF_SYMBOL_ 1 | 2 | #define _PERF_SYMBOL_ 1 |
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include "../types.h" | ||
5 | #include "list.h" | 6 | #include "list.h" |
6 | #include "rbtree.h" | 7 | #include "rbtree.h" |
7 | 8 | ||
8 | struct symbol { | 9 | struct symbol { |
9 | struct rb_node rb_node; | 10 | struct rb_node rb_node; |
10 | __u64 start; | 11 | u64 start; |
11 | __u64 end; | 12 | u64 end; |
12 | __u64 obj_start; | 13 | u64 obj_start; |
13 | __u64 hist_sum; | 14 | u64 hist_sum; |
14 | __u64 *hist; | 15 | u64 *hist; |
16 | void *priv; | ||
15 | char name[0]; | 17 | char name[0]; |
16 | }; | 18 | }; |
17 | 19 | ||
@@ -19,7 +21,7 @@ struct dso { | |||
19 | struct list_head node; | 21 | struct list_head node; |
20 | struct rb_root syms; | 22 | struct rb_root syms; |
21 | unsigned int sym_priv_size; | 23 | unsigned int sym_priv_size; |
22 | struct symbol *(*find_symbol)(struct dso *, __u64 ip); | 24 | struct symbol *(*find_symbol)(struct dso *, u64 ip); |
23 | char name[0]; | 25 | char name[0]; |
24 | }; | 26 | }; |
25 | 27 | ||
@@ -35,7 +37,7 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym) | |||
35 | return ((void *)sym) - self->sym_priv_size; | 37 | return ((void *)sym) - self->sym_priv_size; |
36 | } | 38 | } |
37 | 39 | ||
38 | struct symbol *dso__find_symbol(struct dso *self, __u64 ip); | 40 | struct symbol *dso__find_symbol(struct dso *self, u64 ip); |
39 | 41 | ||
40 | int dso__load_kernel(struct dso *self, const char *vmlinux, | 42 | int dso__load_kernel(struct dso *self, const char *vmlinux, |
41 | symbol_filter_t filter, int verbose); | 43 | symbol_filter_t filter, int verbose); |
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 76590a16c271..b8cfed776d81 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -100,11 +100,6 @@ | |||
100 | #include <iconv.h> | 100 | #include <iconv.h> |
101 | #endif | 101 | #endif |
102 | 102 | ||
103 | #ifndef NO_OPENSSL | ||
104 | #include <openssl/ssl.h> | ||
105 | #include <openssl/err.h> | ||
106 | #endif | ||
107 | |||
108 | /* On most systems <limits.h> would have given us this, but | 103 | /* On most systems <limits.h> would have given us this, but |
109 | * not on some systems (e.g. GNU/Hurd). | 104 | * not on some systems (e.g. GNU/Hurd). |
110 | */ | 105 | */ |
@@ -332,17 +327,20 @@ static inline int has_extension(const char *filename, const char *ext) | |||
332 | #undef tolower | 327 | #undef tolower |
333 | #undef toupper | 328 | #undef toupper |
334 | extern unsigned char sane_ctype[256]; | 329 | extern unsigned char sane_ctype[256]; |
335 | #define GIT_SPACE 0x01 | 330 | #define GIT_SPACE 0x01 |
336 | #define GIT_DIGIT 0x02 | 331 | #define GIT_DIGIT 0x02 |
337 | #define GIT_ALPHA 0x04 | 332 | #define GIT_ALPHA 0x04 |
338 | #define GIT_GLOB_SPECIAL 0x08 | 333 | #define GIT_GLOB_SPECIAL 0x08 |
339 | #define GIT_REGEX_SPECIAL 0x10 | 334 | #define GIT_REGEX_SPECIAL 0x10 |
335 | #define GIT_PRINT_EXTRA 0x20 | ||
336 | #define GIT_PRINT 0x3E | ||
340 | #define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0) | 337 | #define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0) |
341 | #define isascii(x) (((x) & ~0x7f) == 0) | 338 | #define isascii(x) (((x) & ~0x7f) == 0) |
342 | #define isspace(x) sane_istest(x,GIT_SPACE) | 339 | #define isspace(x) sane_istest(x,GIT_SPACE) |
343 | #define isdigit(x) sane_istest(x,GIT_DIGIT) | 340 | #define isdigit(x) sane_istest(x,GIT_DIGIT) |
344 | #define isalpha(x) sane_istest(x,GIT_ALPHA) | 341 | #define isalpha(x) sane_istest(x,GIT_ALPHA) |
345 | #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) | 342 | #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) |
343 | #define isprint(x) sane_istest(x,GIT_PRINT) | ||
346 | #define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL) | 344 | #define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL) |
347 | #define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL) | 345 | #define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL) |
348 | #define tolower(x) sane_case((unsigned char)(x), 0x20) | 346 | #define tolower(x) sane_case((unsigned char)(x), 0x20) |