aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/event.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2010-12-02 07:25:28 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2010-12-04 20:08:40 -0500
commit9c90a61c7e4286aa5a38b314a2d8f5a1e70b5135 (patch)
treed05c5d84db78b2c98c27c3cc83f5da651a6f5707 /tools/perf/util/event.c
parent640c03ce837fe8d4b56342aba376ea0da3960459 (diff)
perf tools: Ask for ID PERF_SAMPLE_ info on all PERF_RECORD_ events
So that we can use -T == --timestamp, asking for PERF_SAMPLE_TIME: $ perf record -aT $ perf report -D | grep PERF_RECORD_ <SNIP> 3 5951915425 0x47530 [0x58]: PERF_RECORD_SAMPLE(IP, 1): 16811/16811: 0xffffffff8138c1a2 period: 215979 cpu:3 3 5952026879 0x47588 [0x90]: PERF_RECORD_SAMPLE(IP, 1): 16811/16811: 0xffffffff810cb480 period: 215979 cpu:3 3 5952059959 0x47618 [0x38]: PERF_RECORD_FORK(6853:6853):(16811:16811) 3 5952138878 0x47650 [0x78]: PERF_RECORD_SAMPLE(IP, 1): 16811/16811: 0xffffffff811bac35 period: 431478 cpu:3 3 5952375068 0x476c8 [0x30]: PERF_RECORD_COMM: find:6853 3 5952395923 0x476f8 [0x50]: PERF_RECORD_MMAP 6853/6853: [0x400000(0x25000) @ 0]: /usr/bin/find 3 5952413756 0x47748 [0xa0]: PERF_RECORD_SAMPLE(IP, 1): 6853/6853: 0xffffffff810d080f period: 859332 cpu:3 3 5952419837 0x477e8 [0x58]: PERF_RECORD_MMAP 6853/6853: [0x3f44600000(0x21d000) @ 0]: /lib64/ld-2.5.so 3 5952437929 0x47840 [0x48]: PERF_RECORD_MMAP 6853/6853: [0x7fff7e1c9000(0x1000) @ 0x7fff7e1c9000]: [vdso] 3 5952570127 0x47888 [0x58]: PERF_RECORD_MMAP 6853/6853: [0x3f46200000(0x218000) @ 0]: /lib64/libselinux.so.1 3 5952623637 0x478e0 [0x58]: PERF_RECORD_MMAP 6853/6853: [0x3f44a00000(0x356000) @ 0]: /lib64/libc-2.5.so 3 5952675720 0x47938 [0x58]: PERF_RECORD_MMAP 6853/6853: [0x3f44e00000(0x204000) @ 0]: /lib64/libdl-2.5.so 3 5952710080 0x47990 [0x58]: PERF_RECORD_MMAP 6853/6853: [0x3f45a00000(0x246000) @ 0]: /lib64/libsepol.so.1 3 5952847802 0x479e8 [0x58]: PERF_RECORD_SAMPLE(IP, 1): 6853/6853: 0xffffffff813897f0 period: 1142536 cpu:3 <SNIP> First column is the cpu and the second the timestamp. That way we can investigate problems in the event stream. If the new perf binary is run on an older kernel, it will disable this feature automatically. Tested-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Ian Munsie <imunsie@au1.ibm.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: Ian Munsie <imunsie@au1.ibm.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Cc: Stephane Eranian <eranian@google.com> LKML-Reference: <1291318772-30880-5-git-send-email-acme@infradead.org> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/event.c')
-rw-r--r--tools/perf/util/event.c285
1 files changed, 200 insertions, 85 deletions
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 34510f441975..e4cdc1ebe0fb 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -33,11 +33,10 @@ static struct sample_data synth_sample = {
33 .period = 1, 33 .period = 1,
34}; 34};
35 35
36static pid_t event__synthesize_comm(pid_t pid, int full, 36static pid_t event__synthesize_comm(event_t *event, pid_t pid, int full,
37 event__handler_t process, 37 event__handler_t process,
38 struct perf_session *session) 38 struct perf_session *session)
39{ 39{
40 event_t ev;
41 char filename[PATH_MAX]; 40 char filename[PATH_MAX];
42 char bf[BUFSIZ]; 41 char bf[BUFSIZ];
43 FILE *fp; 42 FILE *fp;
@@ -58,34 +57,39 @@ out_race:
58 return 0; 57 return 0;
59 } 58 }
60 59
61 memset(&ev.comm, 0, sizeof(ev.comm)); 60 memset(&event->comm, 0, sizeof(event->comm));
62 while (!ev.comm.comm[0] || !ev.comm.pid) { 61
63 if (fgets(bf, sizeof(bf), fp) == NULL) 62 while (!event->comm.comm[0] || !event->comm.pid) {
64 goto out_failure; 63 if (fgets(bf, sizeof(bf), fp) == NULL) {
64 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
65 goto out;
66 }
65 67
66 if (memcmp(bf, "Name:", 5) == 0) { 68 if (memcmp(bf, "Name:", 5) == 0) {
67 char *name = bf + 5; 69 char *name = bf + 5;
68 while (*name && isspace(*name)) 70 while (*name && isspace(*name))
69 ++name; 71 ++name;
70 size = strlen(name) - 1; 72 size = strlen(name) - 1;
71 memcpy(ev.comm.comm, name, size++); 73 memcpy(event->comm.comm, name, size++);
72 } else if (memcmp(bf, "Tgid:", 5) == 0) { 74 } else if (memcmp(bf, "Tgid:", 5) == 0) {
73 char *tgids = bf + 5; 75 char *tgids = bf + 5;
74 while (*tgids && isspace(*tgids)) 76 while (*tgids && isspace(*tgids))
75 ++tgids; 77 ++tgids;
76 tgid = ev.comm.pid = atoi(tgids); 78 tgid = event->comm.pid = atoi(tgids);
77 } 79 }
78 } 80 }
79 81
80 ev.comm.header.type = PERF_RECORD_COMM; 82 event->comm.header.type = PERF_RECORD_COMM;
81 size = ALIGN(size, sizeof(u64)); 83 size = ALIGN(size, sizeof(u64));
82 ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size); 84 memset(event->comm.comm + size, 0, session->id_hdr_size);
83 85 event->comm.header.size = (sizeof(event->comm) -
86 (sizeof(event->comm.comm) - size) +
87 session->id_hdr_size);
84 if (!full) { 88 if (!full) {
85 ev.comm.tid = pid; 89 event->comm.tid = pid;
86 90
87 process(&ev, &synth_sample, session); 91 process(event, &synth_sample, session);
88 goto out_fclose; 92 goto out;
89 } 93 }
90 94
91 snprintf(filename, sizeof(filename), "/proc/%d/task", pid); 95 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
@@ -100,22 +104,19 @@ out_race:
100 if (*end) 104 if (*end)
101 continue; 105 continue;
102 106
103 ev.comm.tid = pid; 107 event->comm.tid = pid;
104 108
105 process(&ev, &synth_sample, session); 109 process(event, &synth_sample, session);
106 } 110 }
107 closedir(tasks);
108 111
109out_fclose: 112 closedir(tasks);
113out:
110 fclose(fp); 114 fclose(fp);
111 return tgid;
112 115
113out_failure: 116 return tgid;
114 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
115 return -1;
116} 117}
117 118
118static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, 119static int event__synthesize_mmap_events(event_t *event, pid_t pid, pid_t tgid,
119 event__handler_t process, 120 event__handler_t process,
120 struct perf_session *session) 121 struct perf_session *session)
121{ 122{
@@ -133,29 +134,25 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
133 return -1; 134 return -1;
134 } 135 }
135 136
137 event->header.type = PERF_RECORD_MMAP;
138 /*
139 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
140 */
141 event->header.misc = PERF_RECORD_MISC_USER;
142
136 while (1) { 143 while (1) {
137 char bf[BUFSIZ], *pbf = bf; 144 char bf[BUFSIZ], *pbf = bf;
138 event_t ev = {
139 .header = {
140 .type = PERF_RECORD_MMAP,
141 /*
142 * Just like the kernel, see __perf_event_mmap
143 * in kernel/perf_event.c
144 */
145 .misc = PERF_RECORD_MISC_USER,
146 },
147 };
148 int n; 145 int n;
149 size_t size; 146 size_t size;
150 if (fgets(bf, sizeof(bf), fp) == NULL) 147 if (fgets(bf, sizeof(bf), fp) == NULL)
151 break; 148 break;
152 149
153 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 150 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
154 n = hex2u64(pbf, &ev.mmap.start); 151 n = hex2u64(pbf, &event->mmap.start);
155 if (n < 0) 152 if (n < 0)
156 continue; 153 continue;
157 pbf += n + 1; 154 pbf += n + 1;
158 n = hex2u64(pbf, &ev.mmap.len); 155 n = hex2u64(pbf, &event->mmap.len);
159 if (n < 0) 156 if (n < 0)
160 continue; 157 continue;
161 pbf += n + 3; 158 pbf += n + 3;
@@ -170,19 +167,21 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
170 continue; 167 continue;
171 168
172 pbf += 3; 169 pbf += 3;
173 n = hex2u64(pbf, &ev.mmap.pgoff); 170 n = hex2u64(pbf, &event->mmap.pgoff);
174 171
175 size = strlen(execname); 172 size = strlen(execname);
176 execname[size - 1] = '\0'; /* Remove \n */ 173 execname[size - 1] = '\0'; /* Remove \n */
177 memcpy(ev.mmap.filename, execname, size); 174 memcpy(event->mmap.filename, execname, size);
178 size = ALIGN(size, sizeof(u64)); 175 size = ALIGN(size, sizeof(u64));
179 ev.mmap.len -= ev.mmap.start; 176 event->mmap.len -= event->mmap.start;
180 ev.mmap.header.size = (sizeof(ev.mmap) - 177 event->mmap.header.size = (sizeof(event->mmap) -
181 (sizeof(ev.mmap.filename) - size)); 178 (sizeof(event->mmap.filename) - size));
182 ev.mmap.pid = tgid; 179 memset(event->mmap.filename + size, 0, session->id_hdr_size);
183 ev.mmap.tid = pid; 180 event->mmap.header.size += session->id_hdr_size;
184 181 event->mmap.pid = tgid;
185 process(&ev, &synth_sample, session); 182 event->mmap.tid = pid;
183
184 process(event, &synth_sample, session);
186 } 185 }
187 } 186 }
188 187
@@ -196,20 +195,27 @@ int event__synthesize_modules(event__handler_t process,
196{ 195{
197 struct rb_node *nd; 196 struct rb_node *nd;
198 struct map_groups *kmaps = &machine->kmaps; 197 struct map_groups *kmaps = &machine->kmaps;
199 u16 misc; 198 event_t *event = zalloc(sizeof(event->mmap) + session->id_hdr_size);
199
200 if (event == NULL) {
201 pr_debug("Not enough memory synthesizing mmap event "
202 "for kernel modules\n");
203 return -1;
204 }
205
206 event->header.type = PERF_RECORD_MMAP;
200 207
201 /* 208 /*
202 * kernel uses 0 for user space maps, see kernel/perf_event.c 209 * kernel uses 0 for user space maps, see kernel/perf_event.c
203 * __perf_event_mmap 210 * __perf_event_mmap
204 */ 211 */
205 if (machine__is_host(machine)) 212 if (machine__is_host(machine))
206 misc = PERF_RECORD_MISC_KERNEL; 213 event->header.misc = PERF_RECORD_MISC_KERNEL;
207 else 214 else
208 misc = PERF_RECORD_MISC_GUEST_KERNEL; 215 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
209 216
210 for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]); 217 for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]);
211 nd; nd = rb_next(nd)) { 218 nd; nd = rb_next(nd)) {
212 event_t ev;
213 size_t size; 219 size_t size;
214 struct map *pos = rb_entry(nd, struct map, rb_node); 220 struct map *pos = rb_entry(nd, struct map, rb_node);
215 221
@@ -217,39 +223,78 @@ int event__synthesize_modules(event__handler_t process,
217 continue; 223 continue;
218 224
219 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); 225 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
220 memset(&ev, 0, sizeof(ev)); 226 event->mmap.header.type = PERF_RECORD_MMAP;
221 ev.mmap.header.misc = misc; 227 event->mmap.header.size = (sizeof(event->mmap) -
222 ev.mmap.header.type = PERF_RECORD_MMAP; 228 (sizeof(event->mmap.filename) - size));
223 ev.mmap.header.size = (sizeof(ev.mmap) - 229 memset(event->mmap.filename + size, 0, session->id_hdr_size);
224 (sizeof(ev.mmap.filename) - size)); 230 event->mmap.header.size += session->id_hdr_size;
225 ev.mmap.start = pos->start; 231 event->mmap.start = pos->start;
226 ev.mmap.len = pos->end - pos->start; 232 event->mmap.len = pos->end - pos->start;
227 ev.mmap.pid = machine->pid; 233 event->mmap.pid = machine->pid;
228 234
229 memcpy(ev.mmap.filename, pos->dso->long_name, 235 memcpy(event->mmap.filename, pos->dso->long_name,
230 pos->dso->long_name_len + 1); 236 pos->dso->long_name_len + 1);
231 process(&ev, &synth_sample, session); 237 process(event, &synth_sample, session);
232 } 238 }
233 239
240 free(event);
234 return 0; 241 return 0;
235} 242}
236 243
237int event__synthesize_thread(pid_t pid, event__handler_t process, 244static int __event__synthesize_thread(event_t *comm_event, event_t *mmap_event,
238 struct perf_session *session) 245 pid_t pid, event__handler_t process,
246 struct perf_session *session)
239{ 247{
240 pid_t tgid = event__synthesize_comm(pid, 1, process, session); 248 pid_t tgid = event__synthesize_comm(comm_event, pid, 1, process,
249 session);
241 if (tgid == -1) 250 if (tgid == -1)
242 return -1; 251 return -1;
243 return event__synthesize_mmap_events(pid, tgid, process, session); 252 return event__synthesize_mmap_events(mmap_event, pid, tgid,
253 process, session);
244} 254}
245 255
246void event__synthesize_threads(event__handler_t process, 256int event__synthesize_thread(pid_t pid, event__handler_t process,
247 struct perf_session *session) 257 struct perf_session *session)
258{
259 event_t *comm_event, *mmap_event;
260 int err = -1;
261
262 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
263 if (comm_event == NULL)
264 goto out;
265
266 mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size);
267 if (mmap_event == NULL)
268 goto out_free_comm;
269
270 err = __event__synthesize_thread(comm_event, mmap_event, pid,
271 process, session);
272 free(mmap_event);
273out_free_comm:
274 free(comm_event);
275out:
276 return err;
277}
278
279int event__synthesize_threads(event__handler_t process,
280 struct perf_session *session)
248{ 281{
249 DIR *proc; 282 DIR *proc;
250 struct dirent dirent, *next; 283 struct dirent dirent, *next;
284 event_t *comm_event, *mmap_event;
285 int err = -1;
286
287 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
288 if (comm_event == NULL)
289 goto out;
290
291 mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size);
292 if (mmap_event == NULL)
293 goto out_free_comm;
251 294
252 proc = opendir("/proc"); 295 proc = opendir("/proc");
296 if (proc == NULL)
297 goto out_free_mmap;
253 298
254 while (!readdir_r(proc, &dirent, &next) && next) { 299 while (!readdir_r(proc, &dirent, &next) && next) {
255 char *end; 300 char *end;
@@ -258,10 +303,18 @@ void event__synthesize_threads(event__handler_t process,
258 if (*end) /* only interested in proper numerical dirents */ 303 if (*end) /* only interested in proper numerical dirents */
259 continue; 304 continue;
260 305
261 event__synthesize_thread(pid, process, session); 306 __event__synthesize_thread(comm_event, mmap_event, pid,
307 process, session);
262 } 308 }
263 309
264 closedir(proc); 310 closedir(proc);
311 err = 0;
312out_free_mmap:
313 free(mmap_event);
314out_free_comm:
315 free(comm_event);
316out:
317 return err;
265} 318}
266 319
267struct process_symbol_args { 320struct process_symbol_args {
@@ -295,18 +348,20 @@ int event__synthesize_kernel_mmap(event__handler_t process,
295 char path[PATH_MAX]; 348 char path[PATH_MAX];
296 char name_buff[PATH_MAX]; 349 char name_buff[PATH_MAX];
297 struct map *map; 350 struct map *map;
298 351 int err;
299 event_t ev = {
300 .header = {
301 .type = PERF_RECORD_MMAP,
302 },
303 };
304 /* 352 /*
305 * We should get this from /sys/kernel/sections/.text, but till that is 353 * We should get this from /sys/kernel/sections/.text, but till that is
306 * available use this, and after it is use this as a fallback for older 354 * available use this, and after it is use this as a fallback for older
307 * kernels. 355 * kernels.
308 */ 356 */
309 struct process_symbol_args args = { .name = symbol_name, }; 357 struct process_symbol_args args = { .name = symbol_name, };
358 event_t *event = zalloc(sizeof(event->mmap) + session->id_hdr_size);
359
360 if (event == NULL) {
361 pr_debug("Not enough memory synthesizing mmap event "
362 "for kernel modules\n");
363 return -1;
364 }
310 365
311 mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff)); 366 mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff));
312 if (machine__is_host(machine)) { 367 if (machine__is_host(machine)) {
@@ -314,10 +369,10 @@ int event__synthesize_kernel_mmap(event__handler_t process,
314 * kernel uses PERF_RECORD_MISC_USER for user space maps, 369 * kernel uses PERF_RECORD_MISC_USER for user space maps,
315 * see kernel/perf_event.c __perf_event_mmap 370 * see kernel/perf_event.c __perf_event_mmap
316 */ 371 */
317 ev.header.misc = PERF_RECORD_MISC_KERNEL; 372 event->header.misc = PERF_RECORD_MISC_KERNEL;
318 filename = "/proc/kallsyms"; 373 filename = "/proc/kallsyms";
319 } else { 374 } else {
320 ev.header.misc = PERF_RECORD_MISC_GUEST_KERNEL; 375 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
321 if (machine__is_default_guest(machine)) 376 if (machine__is_default_guest(machine))
322 filename = (char *) symbol_conf.default_guest_kallsyms; 377 filename = (char *) symbol_conf.default_guest_kallsyms;
323 else { 378 else {
@@ -330,17 +385,21 @@ int event__synthesize_kernel_mmap(event__handler_t process,
330 return -ENOENT; 385 return -ENOENT;
331 386
332 map = machine->vmlinux_maps[MAP__FUNCTION]; 387 map = machine->vmlinux_maps[MAP__FUNCTION];
333 size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename), 388 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
334 "%s%s", mmap_name, symbol_name) + 1; 389 "%s%s", mmap_name, symbol_name) + 1;
335 size = ALIGN(size, sizeof(u64)); 390 size = ALIGN(size, sizeof(u64));
336 ev.mmap.header.size = (sizeof(ev.mmap) - 391 event->mmap.header.type = PERF_RECORD_MMAP;
337 (sizeof(ev.mmap.filename) - size)); 392 event->mmap.header.size = (sizeof(event->mmap) -
338 ev.mmap.pgoff = args.start; 393 (sizeof(event->mmap.filename) - size) + session->id_hdr_size);
339 ev.mmap.start = map->start; 394 event->mmap.pgoff = args.start;
340 ev.mmap.len = map->end - ev.mmap.start; 395 event->mmap.start = map->start;
341 ev.mmap.pid = machine->pid; 396 event->mmap.len = map->end - event->mmap.start;
342 397 event->mmap.pid = machine->pid;
343 return process(&ev, &synth_sample, session); 398
399 err = process(event, &synth_sample, session);
400 free(event);
401
402 return err;
344} 403}
345 404
346static void thread__comm_adjust(struct thread *self, struct hists *hists) 405static void thread__comm_adjust(struct thread *self, struct hists *hists)
@@ -756,9 +815,65 @@ out_filtered:
756 return 0; 815 return 0;
757} 816}
758 817
759int event__parse_sample(const event_t *event, u64 type, struct sample_data *data) 818static int event__parse_id_sample(const event_t *event,
819 struct perf_session *session,
820 struct sample_data *sample)
760{ 821{
761 const u64 *array = event->sample.array; 822 const u64 *array;
823 u64 type;
824
825 sample->cpu = sample->pid = sample->tid = -1;
826 sample->stream_id = sample->id = sample->time = -1ULL;
827
828 if (!session->sample_id_all)
829 return 0;
830
831 array = event->sample.array;
832 array += ((event->header.size -
833 sizeof(event->header)) / sizeof(u64)) - 1;
834 type = session->sample_type;
835
836 if (type & PERF_SAMPLE_CPU) {
837 u32 *p = (u32 *)array;
838 sample->cpu = *p;
839 array--;
840 }
841
842 if (type & PERF_SAMPLE_STREAM_ID) {
843 sample->stream_id = *array;
844 array--;
845 }
846
847 if (type & PERF_SAMPLE_ID) {
848 sample->id = *array;
849 array--;
850 }
851
852 if (type & PERF_SAMPLE_TIME) {
853 sample->time = *array;
854 array--;
855 }
856
857 if (type & PERF_SAMPLE_TID) {
858 u32 *p = (u32 *)array;
859 sample->pid = p[0];
860 sample->tid = p[1];
861 }
862
863 return 0;
864}
865
866int event__parse_sample(const event_t *event, struct perf_session *session,
867 struct sample_data *data)
868{
869 const u64 *array;
870 u64 type;
871
872 if (event->header.type != PERF_RECORD_SAMPLE)
873 return event__parse_id_sample(event, session, data);
874
875 array = event->sample.array;
876 type = session->sample_type;
762 877
763 if (type & PERF_SAMPLE_IP) { 878 if (type & PERF_SAMPLE_IP) {
764 data->ip = event->ip.ip; 879 data->ip = event->ip.ip;