diff options
Diffstat (limited to 'tools/perf/util/event.c')
-rw-r--r-- | tools/perf/util/event.c | 285 |
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 | ||
36 | static pid_t event__synthesize_comm(pid_t pid, int full, | 36 | static 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 | ||
109 | out_fclose: | 112 | closedir(tasks); |
113 | out: | ||
110 | fclose(fp); | 114 | fclose(fp); |
111 | return tgid; | ||
112 | 115 | ||
113 | out_failure: | 116 | return tgid; |
114 | pr_warning("couldn't get COMM and pgid, malformed %s\n", filename); | ||
115 | return -1; | ||
116 | } | 117 | } |
117 | 118 | ||
118 | static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, | 119 | static 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 | ||
237 | int event__synthesize_thread(pid_t pid, event__handler_t process, | 244 | static 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 | ||
246 | void event__synthesize_threads(event__handler_t process, | 256 | int 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); | ||
273 | out_free_comm: | ||
274 | free(comm_event); | ||
275 | out: | ||
276 | return err; | ||
277 | } | ||
278 | |||
279 | int 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; | ||
312 | out_free_mmap: | ||
313 | free(mmap_event); | ||
314 | out_free_comm: | ||
315 | free(comm_event); | ||
316 | out: | ||
317 | return err; | ||
265 | } | 318 | } |
266 | 319 | ||
267 | struct process_symbol_args { | 320 | struct 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 | ||
346 | static void thread__comm_adjust(struct thread *self, struct hists *hists) | 405 | static 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 | ||
759 | int event__parse_sample(const event_t *event, u64 type, struct sample_data *data) | 818 | static 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 | |||
866 | int 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; |