diff options
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Makefile | 1 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 181 | ||||
-rw-r--r-- | tools/perf/util/event.c | 177 | ||||
-rw-r--r-- | tools/perf/util/event.h | 3 |
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 | |||
380 | LIB_OBJS += util/config.o | 380 | LIB_OBJS += util/config.o |
381 | LIB_OBJS += util/ctype.o | 381 | LIB_OBJS += util/ctype.o |
382 | LIB_OBJS += util/environment.o | 382 | LIB_OBJS += util/environment.o |
383 | LIB_OBJS += util/event.o | ||
383 | LIB_OBJS += util/exec_cmd.o | 384 | LIB_OBJS += util/exec_cmd.o |
384 | LIB_OBJS += util/help.o | 385 | LIB_OBJS += util/help.o |
385 | LIB_OBJS += util/levenshtein.o | 386 | LIB_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 | ||
112 | static int process_synthesized_event(event_t *event) | ||
113 | { | ||
114 | write_output(event, event->header.size); | ||
115 | return 0; | ||
116 | } | ||
117 | |||
112 | static void mmap_read(struct mmap_data *md) | 118 | static 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 | ||
194 | static 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) { | ||
209 | out_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 | |||
266 | out_fclose: | ||
267 | fclose(fp); | ||
268 | return tgid; | ||
269 | |||
270 | out_failure: | ||
271 | fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n", | ||
272 | filename); | ||
273 | exit(EXIT_FAILURE); | ||
274 | } | ||
275 | |||
276 | static 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 | |||
338 | static 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 | |||
360 | static int group_fd; | 200 | static int group_fd; |
361 | 201 | ||
362 | static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) | 202 | static 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 | |||
6 | static 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) { | ||
22 | out_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 | |||
78 | out_fclose: | ||
79 | fclose(fp); | ||
80 | return tgid; | ||
81 | |||
82 | out_failure: | ||
83 | pr_warning("couldn't get COMM and pgid, malformed %s\n", filename); | ||
84 | return -1; | ||
85 | } | ||
86 | |||
87 | static 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 | |||
151 | int 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 | |||
159 | void 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); | |||
111 | int map__overlap(struct map *l, struct map *r); | 111 | int map__overlap(struct map *l, struct map *r); |
112 | size_t map__fprintf(struct map *self, FILE *fp); | 112 | size_t map__fprintf(struct map *self, FILE *fp); |
113 | 113 | ||
114 | int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)); | ||
115 | void event__synthesize_threads(int (*process)(event_t *event)); | ||
116 | |||
114 | #endif /* __PERF_RECORD_H */ | 117 | #endif /* __PERF_RECORD_H */ |