diff options
Diffstat (limited to 'tools/perf/util/event.c')
-rw-r--r-- | tools/perf/util/event.c | 156 |
1 files changed, 100 insertions, 56 deletions
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index b0f3ca850e9e..3e580be0f6fb 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -94,14 +94,10 @@ static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len) | |||
94 | 94 | ||
95 | static pid_t perf_event__synthesize_comm(struct perf_tool *tool, | 95 | static pid_t perf_event__synthesize_comm(struct perf_tool *tool, |
96 | union perf_event *event, pid_t pid, | 96 | union perf_event *event, pid_t pid, |
97 | int full, | ||
98 | perf_event__handler_t process, | 97 | perf_event__handler_t process, |
99 | struct machine *machine) | 98 | struct machine *machine) |
100 | { | 99 | { |
101 | char filename[PATH_MAX]; | ||
102 | size_t size; | 100 | size_t size; |
103 | DIR *tasks; | ||
104 | struct dirent dirent, *next; | ||
105 | pid_t tgid; | 101 | pid_t tgid; |
106 | 102 | ||
107 | memset(&event->comm, 0, sizeof(event->comm)); | 103 | memset(&event->comm, 0, sizeof(event->comm)); |
@@ -124,55 +120,35 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool, | |||
124 | event->comm.header.size = (sizeof(event->comm) - | 120 | event->comm.header.size = (sizeof(event->comm) - |
125 | (sizeof(event->comm.comm) - size) + | 121 | (sizeof(event->comm.comm) - size) + |
126 | machine->id_hdr_size); | 122 | machine->id_hdr_size); |
127 | if (!full) { | 123 | event->comm.tid = pid; |
128 | event->comm.tid = pid; | ||
129 | |||
130 | if (process(tool, event, &synth_sample, machine) != 0) | ||
131 | return -1; | ||
132 | 124 | ||
133 | goto out; | 125 | if (process(tool, event, &synth_sample, machine) != 0) |
134 | } | 126 | return -1; |
135 | |||
136 | if (machine__is_default_guest(machine)) | ||
137 | return 0; | ||
138 | |||
139 | snprintf(filename, sizeof(filename), "%s/proc/%d/task", | ||
140 | machine->root_dir, pid); | ||
141 | |||
142 | tasks = opendir(filename); | ||
143 | if (tasks == NULL) { | ||
144 | pr_debug("couldn't open %s\n", filename); | ||
145 | return 0; | ||
146 | } | ||
147 | 127 | ||
148 | while (!readdir_r(tasks, &dirent, &next) && next) { | 128 | out: |
149 | char *end; | 129 | return tgid; |
150 | pid = strtol(dirent.d_name, &end, 10); | 130 | } |
151 | if (*end) | ||
152 | continue; | ||
153 | 131 | ||
154 | /* already have tgid; jut want to update the comm */ | 132 | static int perf_event__synthesize_fork(struct perf_tool *tool, |
155 | (void) perf_event__get_comm_tgid(pid, event->comm.comm, | 133 | union perf_event *event, pid_t pid, |
156 | sizeof(event->comm.comm)); | 134 | pid_t tgid, perf_event__handler_t process, |
135 | struct machine *machine) | ||
136 | { | ||
137 | memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size); | ||
157 | 138 | ||
158 | size = strlen(event->comm.comm) + 1; | 139 | /* this is really a clone event but we use fork to synthesize it */ |
159 | size = PERF_ALIGN(size, sizeof(u64)); | 140 | event->fork.ppid = tgid; |
160 | memset(event->comm.comm + size, 0, machine->id_hdr_size); | 141 | event->fork.ptid = tgid; |
161 | event->comm.header.size = (sizeof(event->comm) - | 142 | event->fork.pid = tgid; |
162 | (sizeof(event->comm.comm) - size) + | 143 | event->fork.tid = pid; |
163 | machine->id_hdr_size); | 144 | event->fork.header.type = PERF_RECORD_FORK; |
164 | 145 | ||
165 | event->comm.tid = pid; | 146 | event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size); |
166 | 147 | ||
167 | if (process(tool, event, &synth_sample, machine) != 0) { | 148 | if (process(tool, event, &synth_sample, machine) != 0) |
168 | tgid = -1; | 149 | return -1; |
169 | break; | ||
170 | } | ||
171 | } | ||
172 | 150 | ||
173 | closedir(tasks); | 151 | return 0; |
174 | out: | ||
175 | return tgid; | ||
176 | } | 152 | } |
177 | 153 | ||
178 | int perf_event__synthesize_mmap_events(struct perf_tool *tool, | 154 | int perf_event__synthesize_mmap_events(struct perf_tool *tool, |
@@ -324,17 +300,71 @@ int perf_event__synthesize_modules(struct perf_tool *tool, | |||
324 | 300 | ||
325 | static int __event__synthesize_thread(union perf_event *comm_event, | 301 | static int __event__synthesize_thread(union perf_event *comm_event, |
326 | union perf_event *mmap_event, | 302 | union perf_event *mmap_event, |
303 | union perf_event *fork_event, | ||
327 | pid_t pid, int full, | 304 | pid_t pid, int full, |
328 | perf_event__handler_t process, | 305 | perf_event__handler_t process, |
329 | struct perf_tool *tool, | 306 | struct perf_tool *tool, |
330 | struct machine *machine, bool mmap_data) | 307 | struct machine *machine, bool mmap_data) |
331 | { | 308 | { |
332 | pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, full, | 309 | char filename[PATH_MAX]; |
310 | DIR *tasks; | ||
311 | struct dirent dirent, *next; | ||
312 | pid_t tgid; | ||
313 | |||
314 | /* special case: only send one comm event using passed in pid */ | ||
315 | if (!full) { | ||
316 | tgid = perf_event__synthesize_comm(tool, comm_event, pid, | ||
317 | process, machine); | ||
318 | |||
319 | if (tgid == -1) | ||
320 | return -1; | ||
321 | |||
322 | return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, | ||
323 | process, machine, mmap_data); | ||
324 | } | ||
325 | |||
326 | if (machine__is_default_guest(machine)) | ||
327 | return 0; | ||
328 | |||
329 | snprintf(filename, sizeof(filename), "%s/proc/%d/task", | ||
330 | machine->root_dir, pid); | ||
331 | |||
332 | tasks = opendir(filename); | ||
333 | if (tasks == NULL) { | ||
334 | pr_debug("couldn't open %s\n", filename); | ||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | while (!readdir_r(tasks, &dirent, &next) && next) { | ||
339 | char *end; | ||
340 | int rc = 0; | ||
341 | pid_t _pid; | ||
342 | |||
343 | _pid = strtol(dirent.d_name, &end, 10); | ||
344 | if (*end) | ||
345 | continue; | ||
346 | |||
347 | tgid = perf_event__synthesize_comm(tool, comm_event, _pid, | ||
348 | process, machine); | ||
349 | if (tgid == -1) | ||
350 | return -1; | ||
351 | |||
352 | if (_pid == pid) { | ||
353 | /* process the parent's maps too */ | ||
354 | rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, | ||
355 | process, machine, mmap_data); | ||
356 | } else { | ||
357 | /* only fork the tid's map, to save time */ | ||
358 | rc = perf_event__synthesize_fork(tool, fork_event, _pid, tgid, | ||
333 | process, machine); | 359 | process, machine); |
334 | if (tgid == -1) | 360 | } |
335 | return -1; | 361 | |
336 | return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, | 362 | if (rc) |
337 | process, machine, mmap_data); | 363 | return rc; |
364 | } | ||
365 | |||
366 | closedir(tasks); | ||
367 | return 0; | ||
338 | } | 368 | } |
339 | 369 | ||
340 | int perf_event__synthesize_thread_map(struct perf_tool *tool, | 370 | int perf_event__synthesize_thread_map(struct perf_tool *tool, |
@@ -343,7 +373,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, | |||
343 | struct machine *machine, | 373 | struct machine *machine, |
344 | bool mmap_data) | 374 | bool mmap_data) |
345 | { | 375 | { |
346 | union perf_event *comm_event, *mmap_event; | 376 | union perf_event *comm_event, *mmap_event, *fork_event; |
347 | int err = -1, thread, j; | 377 | int err = -1, thread, j; |
348 | 378 | ||
349 | comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); | 379 | comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); |
@@ -354,9 +384,14 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, | |||
354 | if (mmap_event == NULL) | 384 | if (mmap_event == NULL) |
355 | goto out_free_comm; | 385 | goto out_free_comm; |
356 | 386 | ||
387 | fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); | ||
388 | if (fork_event == NULL) | ||
389 | goto out_free_mmap; | ||
390 | |||
357 | err = 0; | 391 | err = 0; |
358 | for (thread = 0; thread < threads->nr; ++thread) { | 392 | for (thread = 0; thread < threads->nr; ++thread) { |
359 | if (__event__synthesize_thread(comm_event, mmap_event, | 393 | if (__event__synthesize_thread(comm_event, mmap_event, |
394 | fork_event, | ||
360 | threads->map[thread], 0, | 395 | threads->map[thread], 0, |
361 | process, tool, machine, | 396 | process, tool, machine, |
362 | mmap_data)) { | 397 | mmap_data)) { |
@@ -382,6 +417,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, | |||
382 | /* if not, generate events for it */ | 417 | /* if not, generate events for it */ |
383 | if (need_leader && | 418 | if (need_leader && |
384 | __event__synthesize_thread(comm_event, mmap_event, | 419 | __event__synthesize_thread(comm_event, mmap_event, |
420 | fork_event, | ||
385 | comm_event->comm.pid, 0, | 421 | comm_event->comm.pid, 0, |
386 | process, tool, machine, | 422 | process, tool, machine, |
387 | mmap_data)) { | 423 | mmap_data)) { |
@@ -390,6 +426,8 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, | |||
390 | } | 426 | } |
391 | } | 427 | } |
392 | } | 428 | } |
429 | free(fork_event); | ||
430 | out_free_mmap: | ||
393 | free(mmap_event); | 431 | free(mmap_event); |
394 | out_free_comm: | 432 | out_free_comm: |
395 | free(comm_event); | 433 | free(comm_event); |
@@ -404,7 +442,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
404 | DIR *proc; | 442 | DIR *proc; |
405 | char proc_path[PATH_MAX]; | 443 | char proc_path[PATH_MAX]; |
406 | struct dirent dirent, *next; | 444 | struct dirent dirent, *next; |
407 | union perf_event *comm_event, *mmap_event; | 445 | union perf_event *comm_event, *mmap_event, *fork_event; |
408 | int err = -1; | 446 | int err = -1; |
409 | 447 | ||
410 | comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); | 448 | comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); |
@@ -415,6 +453,10 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
415 | if (mmap_event == NULL) | 453 | if (mmap_event == NULL) |
416 | goto out_free_comm; | 454 | goto out_free_comm; |
417 | 455 | ||
456 | fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); | ||
457 | if (fork_event == NULL) | ||
458 | goto out_free_mmap; | ||
459 | |||
418 | if (machine__is_default_guest(machine)) | 460 | if (machine__is_default_guest(machine)) |
419 | return 0; | 461 | return 0; |
420 | 462 | ||
@@ -422,7 +464,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
422 | proc = opendir(proc_path); | 464 | proc = opendir(proc_path); |
423 | 465 | ||
424 | if (proc == NULL) | 466 | if (proc == NULL) |
425 | goto out_free_mmap; | 467 | goto out_free_fork; |
426 | 468 | ||
427 | while (!readdir_r(proc, &dirent, &next) && next) { | 469 | while (!readdir_r(proc, &dirent, &next) && next) { |
428 | char *end; | 470 | char *end; |
@@ -434,12 +476,14 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
434 | * We may race with exiting thread, so don't stop just because | 476 | * We may race with exiting thread, so don't stop just because |
435 | * one thread couldn't be synthesized. | 477 | * one thread couldn't be synthesized. |
436 | */ | 478 | */ |
437 | __event__synthesize_thread(comm_event, mmap_event, pid, 1, | 479 | __event__synthesize_thread(comm_event, mmap_event, fork_event, pid, |
438 | process, tool, machine, mmap_data); | 480 | 1, process, tool, machine, mmap_data); |
439 | } | 481 | } |
440 | 482 | ||
441 | err = 0; | 483 | err = 0; |
442 | closedir(proc); | 484 | closedir(proc); |
485 | out_free_fork: | ||
486 | free(fork_event); | ||
443 | out_free_mmap: | 487 | out_free_mmap: |
444 | free(mmap_event); | 488 | free(mmap_event); |
445 | out_free_comm: | 489 | out_free_comm: |