aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDon Zickus <dzickus@redhat.com>2014-02-26 10:45:26 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2014-03-14 10:20:44 -0400
commitbfd66cc71a3f831ba7c2116d79416cfb8883f6cf (patch)
treef816efa6ebb791f3bac6bed9843a405c6729cff1 /tools
parent5b4398209d646635a4d84c46a5c7193fbce1a07c (diff)
perf tools: Fix synthesizing mmaps for threads
Currently if a process creates a bunch of threads using pthread_create and then perf is run in system_wide mode, the mmaps for those threads are not captured with a synthesized mmap event. The reason is those threads are not visible when walking the /proc/ directory looking for /proc/<pid>/maps files. Instead they are discovered using the /proc/<pid>/tasks file (which the synthesized comm event uses). This causes problems when a program is trying to map a data address to a tid. Because the tid has no maps, the event is dropped. Changing the program to look up using the pid instead of the tid, finds the correct maps but creates ugly hacks in the program to carry the correct tid around. Fix this by moving the walking of the /proc/<pid>/tasks up a level (out of the comm function) based on Arnaldo's suggestion. Tweaked things a bit to special case the 'full' bit and 'guest' check. Signed-off-by: Don Zickus <dzickus@redhat.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/r/1393429527-167840-2-git-send-email-dzickus@redhat.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/util/event.c111
1 files changed, 56 insertions, 55 deletions
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index b0f3ca850e9e..55eebe936513 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
95static pid_t perf_event__synthesize_comm(struct perf_tool *tool, 95static 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,53 +120,11 @@ 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
148 while (!readdir_r(tasks, &dirent, &next) && next) {
149 char *end;
150 pid = strtol(dirent.d_name, &end, 10);
151 if (*end)
152 continue;
153
154 /* already have tgid; jut want to update the comm */
155 (void) perf_event__get_comm_tgid(pid, event->comm.comm,
156 sizeof(event->comm.comm));
157
158 size = strlen(event->comm.comm) + 1;
159 size = PERF_ALIGN(size, sizeof(u64));
160 memset(event->comm.comm + size, 0, machine->id_hdr_size);
161 event->comm.header.size = (sizeof(event->comm) -
162 (sizeof(event->comm.comm) - size) +
163 machine->id_hdr_size);
164
165 event->comm.tid = pid;
166
167 if (process(tool, event, &synth_sample, machine) != 0) {
168 tgid = -1;
169 break;
170 }
171 }
172 127
173 closedir(tasks);
174out: 128out:
175 return tgid; 129 return tgid;
176} 130}
@@ -329,12 +283,59 @@ static int __event__synthesize_thread(union perf_event *comm_event,
329 struct perf_tool *tool, 283 struct perf_tool *tool,
330 struct machine *machine, bool mmap_data) 284 struct machine *machine, bool mmap_data)
331{ 285{
332 pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, full, 286 char filename[PATH_MAX];
333 process, machine); 287 DIR *tasks;
334 if (tgid == -1) 288 struct dirent dirent, *next;
335 return -1; 289 pid_t tgid;
336 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 290
337 process, machine, mmap_data); 291 /* special case: only send one comm event using passed in pid */
292 if (!full) {
293 tgid = perf_event__synthesize_comm(tool, comm_event, pid,
294 process, machine);
295
296 if (tgid == -1)
297 return -1;
298
299 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
300 process, machine, mmap_data);
301 }
302
303 if (machine__is_default_guest(machine))
304 return 0;
305
306 snprintf(filename, sizeof(filename), "%s/proc/%d/task",
307 machine->root_dir, pid);
308
309 tasks = opendir(filename);
310 if (tasks == NULL) {
311 pr_debug("couldn't open %s\n", filename);
312 return 0;
313 }
314
315 while (!readdir_r(tasks, &dirent, &next) && next) {
316 char *end;
317 int rc = 0;
318 pid_t _pid;
319
320 _pid = strtol(dirent.d_name, &end, 10);
321 if (*end)
322 continue;
323
324 tgid = perf_event__synthesize_comm(tool, comm_event, _pid,
325 process, machine);
326 if (tgid == -1)
327 return -1;
328
329 /* process the thread's maps too */
330 rc = perf_event__synthesize_mmap_events(tool, mmap_event, _pid, tgid,
331 process, machine, mmap_data);
332
333 if (rc)
334 return rc;
335 }
336
337 closedir(tasks);
338 return 0;
338} 339}
339 340
340int perf_event__synthesize_thread_map(struct perf_tool *tool, 341int perf_event__synthesize_thread_map(struct perf_tool *tool,