aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
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/perf/util
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/perf/util')
-rw-r--r--tools/perf/util/event.c177
-rw-r--r--tools/perf/util/event.h3
2 files changed, 180 insertions, 0 deletions
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 */