aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-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 */