diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-03-23 13:22:12 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-04-06 03:30:28 -0400 |
commit | bcbcb37cdb67d8100acfa66df40c4d636c28c4d1 (patch) | |
tree | fbd624736ad77f079e531495f557953d4d875229 | |
parent | 803d4f3980f6e220b27311a283aab0a4d68b6709 (diff) |
perf_counter tools: use mmap() output
update kerneltop to use the mmap() output to gather overflow information
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Wu Fengguang <fengguang.wu@intel.com>
Cc: Paul Mackerras <paulus@samba.org>
Orig-LKML-Reference: <20090323172417.677932499@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | Documentation/perf_counter/kerneltop.c | 93 |
1 files changed, 79 insertions, 14 deletions
diff --git a/Documentation/perf_counter/kerneltop.c b/Documentation/perf_counter/kerneltop.c index a72c9bd28071..80b790553ec8 100644 --- a/Documentation/perf_counter/kerneltop.c +++ b/Documentation/perf_counter/kerneltop.c | |||
@@ -84,6 +84,7 @@ | |||
84 | #include <sys/prctl.h> | 84 | #include <sys/prctl.h> |
85 | #include <sys/wait.h> | 85 | #include <sys/wait.h> |
86 | #include <sys/uio.h> | 86 | #include <sys/uio.h> |
87 | #include <sys/mman.h> | ||
87 | 88 | ||
88 | #include <linux/unistd.h> | 89 | #include <linux/unistd.h> |
89 | 90 | ||
@@ -119,17 +120,25 @@ typedef long long __s64; | |||
119 | 120 | ||
120 | 121 | ||
121 | #ifdef __x86_64__ | 122 | #ifdef __x86_64__ |
122 | # define __NR_perf_counter_open 295 | 123 | #define __NR_perf_counter_open 295 |
124 | #define rmb() asm volatile("lfence" ::: "memory") | ||
125 | #define cpu_relax() asm volatile("rep; nop" ::: "memory"); | ||
123 | #endif | 126 | #endif |
124 | 127 | ||
125 | #ifdef __i386__ | 128 | #ifdef __i386__ |
126 | # define __NR_perf_counter_open 333 | 129 | #define __NR_perf_counter_open 333 |
130 | #define rmb() asm volatile("lfence" ::: "memory") | ||
131 | #define cpu_relax() asm volatile("rep; nop" ::: "memory"); | ||
127 | #endif | 132 | #endif |
128 | 133 | ||
129 | #ifdef __powerpc__ | 134 | #ifdef __powerpc__ |
130 | #define __NR_perf_counter_open 319 | 135 | #define __NR_perf_counter_open 319 |
136 | #define rmb() asm volatile ("sync" ::: "memory") | ||
137 | #define cpu_relax() asm volatile ("" ::: "memory"); | ||
131 | #endif | 138 | #endif |
132 | 139 | ||
140 | #define unlikely(x) __builtin_expect(!!(x), 0) | ||
141 | |||
133 | asmlinkage int sys_perf_counter_open( | 142 | asmlinkage int sys_perf_counter_open( |
134 | struct perf_counter_hw_event *hw_event_uptr __user, | 143 | struct perf_counter_hw_event *hw_event_uptr __user, |
135 | pid_t pid, | 144 | pid_t pid, |
@@ -181,6 +190,7 @@ static int profile_cpu = -1; | |||
181 | static int nr_cpus = 0; | 190 | static int nr_cpus = 0; |
182 | static int nmi = 1; | 191 | static int nmi = 1; |
183 | static int group = 0; | 192 | static int group = 0; |
193 | static unsigned int page_size; | ||
184 | 194 | ||
185 | static char *vmlinux; | 195 | static char *vmlinux; |
186 | 196 | ||
@@ -1117,16 +1127,68 @@ static void process_options(int argc, char *argv[]) | |||
1117 | } | 1127 | } |
1118 | } | 1128 | } |
1119 | 1129 | ||
1130 | struct mmap_data { | ||
1131 | int counter; | ||
1132 | void *base; | ||
1133 | unsigned int mask; | ||
1134 | unsigned int prev; | ||
1135 | }; | ||
1136 | |||
1137 | static unsigned int mmap_read_head(struct mmap_data *md) | ||
1138 | { | ||
1139 | struct perf_counter_mmap_page *pc = md->base; | ||
1140 | unsigned int seq, head; | ||
1141 | |||
1142 | repeat: | ||
1143 | rmb(); | ||
1144 | seq = pc->lock; | ||
1145 | |||
1146 | if (unlikely(seq & 1)) { | ||
1147 | cpu_relax(); | ||
1148 | goto repeat; | ||
1149 | } | ||
1150 | |||
1151 | head = pc->data_head; | ||
1152 | |||
1153 | rmb(); | ||
1154 | if (pc->lock != seq) | ||
1155 | goto repeat; | ||
1156 | |||
1157 | return head; | ||
1158 | } | ||
1159 | |||
1160 | static void mmap_read(struct mmap_data *md) | ||
1161 | { | ||
1162 | unsigned int head = mmap_read_head(md); | ||
1163 | unsigned int old = md->prev; | ||
1164 | unsigned char *data = md->base + page_size; | ||
1165 | |||
1166 | if (head - old > md->mask) { | ||
1167 | printf("ERROR: failed to keep up with mmap data\n"); | ||
1168 | exit(-1); | ||
1169 | } | ||
1170 | |||
1171 | for (; old != head;) { | ||
1172 | __u64 *ptr = (__u64 *)&data[old & md->mask]; | ||
1173 | old += sizeof(__u64); | ||
1174 | |||
1175 | process_event(*ptr, md->counter); | ||
1176 | } | ||
1177 | |||
1178 | md->prev = old; | ||
1179 | } | ||
1180 | |||
1120 | int main(int argc, char *argv[]) | 1181 | int main(int argc, char *argv[]) |
1121 | { | 1182 | { |
1122 | struct pollfd event_array[MAX_NR_CPUS][MAX_COUNTERS]; | 1183 | struct pollfd event_array[MAX_NR_CPUS][MAX_COUNTERS]; |
1184 | struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; | ||
1123 | struct perf_counter_hw_event hw_event; | 1185 | struct perf_counter_hw_event hw_event; |
1124 | int i, counter, group_fd; | 1186 | int i, counter, group_fd; |
1125 | unsigned int cpu; | 1187 | unsigned int cpu; |
1126 | uint64_t ip; | ||
1127 | ssize_t res; | ||
1128 | int ret; | 1188 | int ret; |
1129 | 1189 | ||
1190 | page_size = sysconf(_SC_PAGE_SIZE); | ||
1191 | |||
1130 | process_options(argc, argv); | 1192 | process_options(argc, argv); |
1131 | 1193 | ||
1132 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); | 1194 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); |
@@ -1153,8 +1215,6 @@ int main(int argc, char *argv[]) | |||
1153 | hw_event.record_type = PERF_RECORD_IRQ; | 1215 | hw_event.record_type = PERF_RECORD_IRQ; |
1154 | hw_event.nmi = nmi; | 1216 | hw_event.nmi = nmi; |
1155 | 1217 | ||
1156 | printf("FOO: %d %llx %llx\n", counter, event_id[counter], event_count[counter]); | ||
1157 | |||
1158 | fd[i][counter] = sys_perf_counter_open(&hw_event, tid, cpu, group_fd, 0); | 1218 | fd[i][counter] = sys_perf_counter_open(&hw_event, tid, cpu, group_fd, 0); |
1159 | fcntl(fd[i][counter], F_SETFL, O_NONBLOCK); | 1219 | fcntl(fd[i][counter], F_SETFL, O_NONBLOCK); |
1160 | if (fd[i][counter] < 0) { | 1220 | if (fd[i][counter] < 0) { |
@@ -1174,6 +1234,17 @@ int main(int argc, char *argv[]) | |||
1174 | 1234 | ||
1175 | event_array[i][counter].fd = fd[i][counter]; | 1235 | event_array[i][counter].fd = fd[i][counter]; |
1176 | event_array[i][counter].events = POLLIN; | 1236 | event_array[i][counter].events = POLLIN; |
1237 | |||
1238 | mmap_array[i][counter].counter = counter; | ||
1239 | mmap_array[i][counter].prev = 0; | ||
1240 | mmap_array[i][counter].mask = 2*page_size - 1; | ||
1241 | mmap_array[i][counter].base = mmap(NULL, 3*page_size, | ||
1242 | PROT_READ, MAP_SHARED, fd[i][counter], 0); | ||
1243 | if (mmap_array[i][counter].base == MAP_FAILED) { | ||
1244 | printf("kerneltop error: failed to mmap with %d (%s)\n", | ||
1245 | errno, strerror(errno)); | ||
1246 | exit(-1); | ||
1247 | } | ||
1177 | } | 1248 | } |
1178 | } | 1249 | } |
1179 | 1250 | ||
@@ -1188,14 +1259,8 @@ int main(int argc, char *argv[]) | |||
1188 | int hits = events; | 1259 | int hits = events; |
1189 | 1260 | ||
1190 | for (i = 0; i < nr_cpus; i++) { | 1261 | for (i = 0; i < nr_cpus; i++) { |
1191 | for (counter = 0; counter < nr_counters; counter++) { | 1262 | for (counter = 0; counter < nr_counters; counter++) |
1192 | res = read(fd[i][counter], (char *) &ip, sizeof(ip)); | 1263 | mmap_read(&mmap_array[i][counter]); |
1193 | if (res > 0) { | ||
1194 | assert(res == sizeof(ip)); | ||
1195 | |||
1196 | process_event(ip, counter); | ||
1197 | } | ||
1198 | } | ||
1199 | } | 1264 | } |
1200 | 1265 | ||
1201 | if (time(NULL) >= last_refresh + delay_secs) { | 1266 | if (time(NULL) >= last_refresh + delay_secs) { |