diff options
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r-- | tools/perf/builtin-record.c | 181 |
1 files changed, 10 insertions, 171 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 9e1638cc19c..4a73d89ce5d 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(); |