]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - tools/perf/util/event.c
perf tools: Reorganize event processing routines, lotsa dups killed
[mirror_ubuntu-artful-kernel.git] / tools / perf / util / event.c
CommitLineData
234fbbf5
ACM
1#include <linux/types.h>
2#include "event.h"
3#include "debug.h"
4#include "string.h"
62daacb5 5#include "thread.h"
234fbbf5
ACM
6
7static pid_t event__synthesize_comm(pid_t pid, int full,
8 int (*process)(event_t *event))
9{
10 event_t ev;
11 char filename[PATH_MAX];
12 char bf[BUFSIZ];
13 FILE *fp;
14 size_t size = 0;
15 DIR *tasks;
16 struct dirent dirent, *next;
17 pid_t tgid = 0;
18
19 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
20
21 fp = fopen(filename, "r");
22 if (fp == NULL) {
23out_race:
24 /*
25 * We raced with a task exiting - just return:
26 */
27 pr_debug("couldn't open %s\n", filename);
28 return 0;
29 }
30
31 memset(&ev.comm, 0, sizeof(ev.comm));
32 while (!ev.comm.comm[0] || !ev.comm.pid) {
33 if (fgets(bf, sizeof(bf), fp) == NULL)
34 goto out_failure;
35
36 if (memcmp(bf, "Name:", 5) == 0) {
37 char *name = bf + 5;
38 while (*name && isspace(*name))
39 ++name;
40 size = strlen(name) - 1;
41 memcpy(ev.comm.comm, name, size++);
42 } else if (memcmp(bf, "Tgid:", 5) == 0) {
43 char *tgids = bf + 5;
44 while (*tgids && isspace(*tgids))
45 ++tgids;
46 tgid = ev.comm.pid = atoi(tgids);
47 }
48 }
49
50 ev.comm.header.type = PERF_RECORD_COMM;
51 size = ALIGN(size, sizeof(u64));
52 ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size);
53
54 if (!full) {
55 ev.comm.tid = pid;
56
57 process(&ev);
58 goto out_fclose;
59 }
60
61 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
62
63 tasks = opendir(filename);
64 if (tasks == NULL)
65 goto out_race;
66
67 while (!readdir_r(tasks, &dirent, &next) && next) {
68 char *end;
69 pid = strtol(dirent.d_name, &end, 10);
70 if (*end)
71 continue;
72
73 ev.comm.tid = pid;
74
75 process(&ev);
76 }
77 closedir(tasks);
78
79out_fclose:
80 fclose(fp);
81 return tgid;
82
83out_failure:
84 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
85 return -1;
86}
87
88static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
89 int (*process)(event_t *event))
90{
91 char filename[PATH_MAX];
92 FILE *fp;
93
94 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
95
96 fp = fopen(filename, "r");
97 if (fp == NULL) {
98 /*
99 * We raced with a task exiting - just return:
100 */
101 pr_debug("couldn't open %s\n", filename);
102 return -1;
103 }
104
105 while (1) {
106 char bf[BUFSIZ], *pbf = bf;
107 event_t ev = {
108 .header = { .type = PERF_RECORD_MMAP },
109 };
110 int n;
111 size_t size;
112 if (fgets(bf, sizeof(bf), fp) == NULL)
113 break;
114
115 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
116 n = hex2u64(pbf, &ev.mmap.start);
117 if (n < 0)
118 continue;
119 pbf += n + 1;
120 n = hex2u64(pbf, &ev.mmap.len);
121 if (n < 0)
122 continue;
123 pbf += n + 3;
124 if (*pbf == 'x') { /* vm_exec */
125 char *execname = strchr(bf, '/');
126
127 /* Catch VDSO */
128 if (execname == NULL)
129 execname = strstr(bf, "[vdso]");
130
131 if (execname == NULL)
132 continue;
133
134 size = strlen(execname);
135 execname[size - 1] = '\0'; /* Remove \n */
136 memcpy(ev.mmap.filename, execname, size);
137 size = ALIGN(size, sizeof(u64));
138 ev.mmap.len -= ev.mmap.start;
139 ev.mmap.header.size = (sizeof(ev.mmap) -
140 (sizeof(ev.mmap.filename) - size));
141 ev.mmap.pid = tgid;
142 ev.mmap.tid = pid;
143
144 process(&ev);
145 }
146 }
147
148 fclose(fp);
149 return 0;
150}
151
152int event__synthesize_thread(pid_t pid, int (*process)(event_t *event))
153{
154 pid_t tgid = event__synthesize_comm(pid, 1, process);
155 if (tgid == -1)
156 return -1;
157 return event__synthesize_mmap_events(pid, tgid, process);
158}
159
160void event__synthesize_threads(int (*process)(event_t *event))
161{
162 DIR *proc;
163 struct dirent dirent, *next;
164
165 proc = opendir("/proc");
166
167 while (!readdir_r(proc, &dirent, &next) && next) {
168 char *end;
169 pid_t pid = strtol(dirent.d_name, &end, 10);
170
171 if (*end) /* only interested in proper numerical dirents */
172 continue;
173
174 event__synthesize_thread(pid, process);
175 }
176
177 closedir(proc);
178}
62daacb5
ACM
179
180char *event__cwd;
181int event__cwdlen;
182
183struct events_stats event__stats;
184
185int event__process_comm(event_t *self)
186{
187 struct thread *thread = threads__findnew(self->comm.pid);
188
189 dump_printf("PERF_RECORD_COMM: %s:%d\n",
190 self->comm.comm, self->comm.pid);
191
192 if (thread == NULL || thread__set_comm(thread, self->comm.comm)) {
193 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
194 return -1;
195 }
196
197 return 0;
198}
199
200int event__process_lost(event_t *self)
201{
202 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
203 event__stats.lost += self->lost.lost;
204 return 0;
205}
206
207int event__process_mmap(event_t *self)
208{
209 struct thread *thread = threads__findnew(self->mmap.pid);
210 struct map *map = map__new(&self->mmap, MAP__FUNCTION,
211 event__cwd, event__cwdlen);
212
213 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n",
214 self->mmap.pid, self->mmap.tid,
215 (void *)(long)self->mmap.start,
216 (void *)(long)self->mmap.len,
217 (void *)(long)self->mmap.pgoff,
218 self->mmap.filename);
219
220 if (thread == NULL || map == NULL)
221 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
222 else
223 thread__insert_map(thread, map);
224
225 return 0;
226}
227
228int event__process_task(event_t *self)
229{
230 struct thread *thread = threads__findnew(self->fork.pid);
231 struct thread *parent = threads__findnew(self->fork.ppid);
232
233 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
234 self->fork.ppid, self->fork.ptid);
235 /*
236 * A thread clone will have the same PID for both parent and child.
237 */
238 if (thread == parent)
239 return 0;
240
241 if (self->header.type == PERF_RECORD_EXIT)
242 return 0;
243
244 if (thread == NULL || parent == NULL ||
245 thread__fork(thread, parent) < 0) {
246 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
247 return -1;
248 }
249
250 return 0;
251}