aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2009-10-26 17:23:18 -0400
committerIngo Molnar <mingo@elte.hu>2009-10-27 08:51:53 -0400
commit234fbbf508c58c5084292b11b242377553897459 (patch)
treeecda0e2b0aaa0e3ebd5cab7376817baacc7e2718 /tools
parent7f3bedcc93f935631d2363f23de1cc80f04fdf3e (diff)
perf tools: Generalize event synthesizing routines
Because we will need it in 'perf top' to support userspace symbols for existing threads. Now we pass a callback that will receive the synthesized event and then write it to the output file in 'perf record' and in the upcoming patch for 'perf top' we will just immediatelly create the in memory representation of threads and maps. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Mike Galbraith <efault@gmx.de> LKML-Reference: <1256592199-9608-2-git-send-email-acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Makefile1
-rw-r--r--tools/perf/builtin-record.c181
-rw-r--r--tools/perf/util/event.c177
-rw-r--r--tools/perf/util/event.h3
4 files changed, 191 insertions, 171 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 0a40c29b2387..9f4488d6f8e6 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -380,6 +380,7 @@ LIB_OBJS += util/alias.o
380LIB_OBJS += util/config.o 380LIB_OBJS += util/config.o
381LIB_OBJS += util/ctype.o 381LIB_OBJS += util/ctype.o
382LIB_OBJS += util/environment.o 382LIB_OBJS += util/environment.o
383LIB_OBJS += util/event.o
383LIB_OBJS += util/exec_cmd.o 384LIB_OBJS += util/exec_cmd.o
384LIB_OBJS += util/help.o 385LIB_OBJS += util/help.o
385LIB_OBJS += util/levenshtein.o 386LIB_OBJS += util/levenshtein.o
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 9e1638cc19c8..4a73d89ce5d1 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -109,6 +109,12 @@ static void write_output(void *buf, size_t size)
109 } 109 }
110} 110}
111 111
112static int process_synthesized_event(event_t *event)
113{
114 write_output(event, event->header.size);
115 return 0;
116}
117
112static void mmap_read(struct mmap_data *md) 118static void mmap_read(struct mmap_data *md)
113{ 119{
114 unsigned int head = mmap_read_head(md); 120 unsigned int head = mmap_read_head(md);
@@ -191,172 +197,6 @@ static void sig_atexit(void)
191 kill(getpid(), signr); 197 kill(getpid(), signr);
192} 198}
193 199
194static pid_t pid_synthesize_comm_event(pid_t pid, int full)
195{
196 struct comm_event comm_ev;
197 char filename[PATH_MAX];
198 char bf[BUFSIZ];
199 FILE *fp;
200 size_t size = 0;
201 DIR *tasks;
202 struct dirent dirent, *next;
203 pid_t tgid = 0;
204
205 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
206
207 fp = fopen(filename, "r");
208 if (fp == NULL) {
209out_race:
210 /*
211 * We raced with a task exiting - just return:
212 */
213 if (verbose)
214 fprintf(stderr, "couldn't open %s\n", filename);
215 return 0;
216 }
217
218 memset(&comm_ev, 0, sizeof(comm_ev));
219 while (!comm_ev.comm[0] || !comm_ev.pid) {
220 if (fgets(bf, sizeof(bf), fp) == NULL)
221 goto out_failure;
222
223 if (memcmp(bf, "Name:", 5) == 0) {
224 char *name = bf + 5;
225 while (*name && isspace(*name))
226 ++name;
227 size = strlen(name) - 1;
228 memcpy(comm_ev.comm, name, size++);
229 } else if (memcmp(bf, "Tgid:", 5) == 0) {
230 char *tgids = bf + 5;
231 while (*tgids && isspace(*tgids))
232 ++tgids;
233 tgid = comm_ev.pid = atoi(tgids);
234 }
235 }
236
237 comm_ev.header.type = PERF_RECORD_COMM;
238 size = ALIGN(size, sizeof(u64));
239 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size);
240
241 if (!full) {
242 comm_ev.tid = pid;
243
244 write_output(&comm_ev, comm_ev.header.size);
245 goto out_fclose;
246 }
247
248 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
249
250 tasks = opendir(filename);
251 if (tasks == NULL)
252 goto out_race;
253
254 while (!readdir_r(tasks, &dirent, &next) && next) {
255 char *end;
256 pid = strtol(dirent.d_name, &end, 10);
257 if (*end)
258 continue;
259
260 comm_ev.tid = pid;
261
262 write_output(&comm_ev, comm_ev.header.size);
263 }
264 closedir(tasks);
265
266out_fclose:
267 fclose(fp);
268 return tgid;
269
270out_failure:
271 fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n",
272 filename);
273 exit(EXIT_FAILURE);
274}
275
276static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid)
277{
278 char filename[PATH_MAX];
279 FILE *fp;
280
281 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
282
283 fp = fopen(filename, "r");
284 if (fp == NULL) {
285 /*
286 * We raced with a task exiting - just return:
287 */
288 if (verbose)
289 fprintf(stderr, "couldn't open %s\n", filename);
290 return;
291 }
292 while (1) {
293 char bf[BUFSIZ], *pbf = bf;
294 struct mmap_event mmap_ev = {
295 .header = { .type = PERF_RECORD_MMAP },
296 };
297 int n;
298 size_t size;
299 if (fgets(bf, sizeof(bf), fp) == NULL)
300 break;
301
302 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
303 n = hex2u64(pbf, &mmap_ev.start);
304 if (n < 0)
305 continue;
306 pbf += n + 1;
307 n = hex2u64(pbf, &mmap_ev.len);
308 if (n < 0)
309 continue;
310 pbf += n + 3;
311 if (*pbf == 'x') { /* vm_exec */
312 char *execname = strchr(bf, '/');
313
314 /* Catch VDSO */
315 if (execname == NULL)
316 execname = strstr(bf, "[vdso]");
317
318 if (execname == NULL)
319 continue;
320
321 size = strlen(execname);
322 execname[size - 1] = '\0'; /* Remove \n */
323 memcpy(mmap_ev.filename, execname, size);
324 size = ALIGN(size, sizeof(u64));
325 mmap_ev.len -= mmap_ev.start;
326 mmap_ev.header.size = (sizeof(mmap_ev) -
327 (sizeof(mmap_ev.filename) - size));
328 mmap_ev.pid = tgid;
329 mmap_ev.tid = pid;
330
331 write_output(&mmap_ev, mmap_ev.header.size);
332 }
333 }
334
335 fclose(fp);
336}
337
338static void synthesize_all(void)
339{
340 DIR *proc;
341 struct dirent dirent, *next;
342
343 proc = opendir("/proc");
344
345 while (!readdir_r(proc, &dirent, &next) && next) {
346 char *end;
347 pid_t pid, tgid;
348
349 pid = strtol(dirent.d_name, &end, 10);
350 if (*end) /* only interested in proper numerical dirents */
351 continue;
352
353 tgid = pid_synthesize_comm_event(pid, 1);
354 pid_synthesize_mmap_samples(pid, tgid);
355 }
356
357 closedir(proc);
358}
359
360static int group_fd; 200static int group_fd;
361 201
362static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) 202static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
@@ -608,11 +448,10 @@ static int __cmd_record(int argc, const char **argv)
608 if (file_new) 448 if (file_new)
609 perf_header__write(header, output); 449 perf_header__write(header, output);
610 450
611 if (!system_wide) { 451 if (!system_wide)
612 pid_t tgid = pid_synthesize_comm_event(pid, 0); 452 event__synthesize_thread(pid, process_synthesized_event);
613 pid_synthesize_mmap_samples(pid, tgid); 453 else
614 } else 454 event__synthesize_threads(process_synthesized_event);
615 synthesize_all();
616 455
617 if (target_pid == -1 && argc) { 456 if (target_pid == -1 && argc) {
618 pid = fork(); 457 pid = fork();
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
new file mode 100644
index 000000000000..1dae7e3b400d
--- /dev/null
+++ b/tools/perf/util/event.c
@@ -0,0 +1,177 @@
1#include <linux/types.h>
2#include "event.h"
3#include "debug.h"
4#include "string.h"
5
6static pid_t event__synthesize_comm(pid_t pid, int full,
7 int (*process)(event_t *event))
8{
9 event_t ev;
10 char filename[PATH_MAX];
11 char bf[BUFSIZ];
12 FILE *fp;
13 size_t size = 0;
14 DIR *tasks;
15 struct dirent dirent, *next;
16 pid_t tgid = 0;
17
18 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
19
20 fp = fopen(filename, "r");
21 if (fp == NULL) {
22out_race:
23 /*
24 * We raced with a task exiting - just return:
25 */
26 pr_debug("couldn't open %s\n", filename);
27 return 0;
28 }
29
30 memset(&ev.comm, 0, sizeof(ev.comm));
31 while (!ev.comm.comm[0] || !ev.comm.pid) {
32 if (fgets(bf, sizeof(bf), fp) == NULL)
33 goto out_failure;
34
35 if (memcmp(bf, "Name:", 5) == 0) {
36 char *name = bf + 5;
37 while (*name && isspace(*name))
38 ++name;
39 size = strlen(name) - 1;
40 memcpy(ev.comm.comm, name, size++);
41 } else if (memcmp(bf, "Tgid:", 5) == 0) {
42 char *tgids = bf + 5;
43 while (*tgids && isspace(*tgids))
44 ++tgids;
45 tgid = ev.comm.pid = atoi(tgids);
46 }
47 }
48
49 ev.comm.header.type = PERF_RECORD_COMM;
50 size = ALIGN(size, sizeof(u64));
51 ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size);
52
53 if (!full) {
54 ev.comm.tid = pid;
55
56 process(&ev);
57 goto out_fclose;
58 }
59
60 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
61
62 tasks = opendir(filename);
63 if (tasks == NULL)
64 goto out_race;
65
66 while (!readdir_r(tasks, &dirent, &next) && next) {
67 char *end;
68 pid = strtol(dirent.d_name, &end, 10);
69 if (*end)
70 continue;
71
72 ev.comm.tid = pid;
73
74 process(&ev);
75 }
76 closedir(tasks);
77
78out_fclose:
79 fclose(fp);
80 return tgid;
81
82out_failure:
83 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
84 return -1;
85}
86
87static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
88 int (*process)(event_t *event))
89{
90 char filename[PATH_MAX];
91 FILE *fp;
92
93 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
94
95 fp = fopen(filename, "r");
96 if (fp == NULL) {
97 /*
98 * We raced with a task exiting - just return:
99 */
100 pr_debug("couldn't open %s\n", filename);
101 return -1;
102 }
103
104 while (1) {
105 char bf[BUFSIZ], *pbf = bf;
106 event_t ev = {
107 .header = { .type = PERF_RECORD_MMAP },
108 };
109 int n;
110 size_t size;
111 if (fgets(bf, sizeof(bf), fp) == NULL)
112 break;
113
114 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
115 n = hex2u64(pbf, &ev.mmap.start);
116 if (n < 0)
117 continue;
118 pbf += n + 1;
119 n = hex2u64(pbf, &ev.mmap.len);
120 if (n < 0)
121 continue;
122 pbf += n + 3;
123 if (*pbf == 'x') { /* vm_exec */
124 char *execname = strchr(bf, '/');
125
126 /* Catch VDSO */
127 if (execname == NULL)
128 execname = strstr(bf, "[vdso]");
129
130 if (execname == NULL)
131 continue;
132
133 size = strlen(execname);
134 execname[size - 1] = '\0'; /* Remove \n */
135 memcpy(ev.mmap.filename, execname, size);
136 size = ALIGN(size, sizeof(u64));
137 ev.mmap.len -= ev.mmap.start;
138 ev.mmap.header.size = (sizeof(ev.mmap) -
139 (sizeof(ev.mmap.filename) - size));
140 ev.mmap.pid = tgid;
141 ev.mmap.tid = pid;
142
143 process(&ev);
144 }
145 }
146
147 fclose(fp);
148 return 0;
149}
150
151int event__synthesize_thread(pid_t pid, int (*process)(event_t *event))
152{
153 pid_t tgid = event__synthesize_comm(pid, 1, process);
154 if (tgid == -1)
155 return -1;
156 return event__synthesize_mmap_events(pid, tgid, process);
157}
158
159void event__synthesize_threads(int (*process)(event_t *event))
160{
161 DIR *proc;
162 struct dirent dirent, *next;
163
164 proc = opendir("/proc");
165
166 while (!readdir_r(proc, &dirent, &next) && next) {
167 char *end;
168 pid_t pid = strtol(dirent.d_name, &end, 10);
169
170 if (*end) /* only interested in proper numerical dirents */
171 continue;
172
173 event__synthesize_thread(pid, process);
174 }
175
176 closedir(proc);
177}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index d972b4b0d38c..2ae1177be40b 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -111,4 +111,7 @@ struct map *map__clone(struct map *self);
111int map__overlap(struct map *l, struct map *r); 111int map__overlap(struct map *l, struct map *r);
112size_t map__fprintf(struct map *self, FILE *fp); 112size_t map__fprintf(struct map *self, FILE *fp);
113 113
114int event__synthesize_thread(pid_t pid, int (*process)(event_t *event));
115void event__synthesize_threads(int (*process)(event_t *event));
116
114#endif /* __PERF_RECORD_H */ 117#endif /* __PERF_RECORD_H */