diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-06-02 08:13:24 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-02 10:16:26 -0400 |
commit | f70e87d7a6d9c5a23d5f43ed0a0c224c157ef597 (patch) | |
tree | 4ab2bd0cf9db9ada8edd49266765d7c9df2ade5f /Documentation/perf_counter/builtin-record.c | |
parent | 709e50cf870e61745b39552044aa6c7c38e4f9e0 (diff) |
perf_counter: tools: Expand the COMM,MMAP event synthesizer
Include code to pre-construct mappings based on /proc,
on system wide recording.
Fix the existing code to properly fill out ->pid and ->tid.
The PID should be the Thread Group ID (PIDTYPE_PID of task->group_leader)
The TID should be the Thread ID (PIDTYPE_PID of task)
Furthermore, change the default sorting of report to comm,dso for a
better quick overview.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: John Kacur <jkacur@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'Documentation/perf_counter/builtin-record.c')
-rw-r--r-- | Documentation/perf_counter/builtin-record.c | 84 |
1 files changed, 64 insertions, 20 deletions
diff --git a/Documentation/perf_counter/builtin-record.c b/Documentation/perf_counter/builtin-record.c index 9c151ded22fa..810fc275ca65 100644 --- a/Documentation/perf_counter/builtin-record.c +++ b/Documentation/perf_counter/builtin-record.c | |||
@@ -162,7 +162,7 @@ struct comm_event { | |||
162 | char comm[16]; | 162 | char comm[16]; |
163 | }; | 163 | }; |
164 | 164 | ||
165 | static pid_t pid_synthesize_comm_event(pid_t pid) | 165 | static void pid_synthesize_comm_event(pid_t pid, int full) |
166 | { | 166 | { |
167 | struct comm_event comm_ev; | 167 | struct comm_event comm_ev; |
168 | char filename[PATH_MAX]; | 168 | char filename[PATH_MAX]; |
@@ -170,6 +170,8 @@ static pid_t pid_synthesize_comm_event(pid_t pid) | |||
170 | int fd, ret; | 170 | int fd, ret; |
171 | size_t size; | 171 | size_t size; |
172 | char *field, *sep; | 172 | char *field, *sep; |
173 | DIR *tasks; | ||
174 | struct dirent dirent, *next; | ||
173 | 175 | ||
174 | snprintf(filename, sizeof(filename), "/proc/%d/stat", pid); | 176 | snprintf(filename, sizeof(filename), "/proc/%d/stat", pid); |
175 | 177 | ||
@@ -194,29 +196,50 @@ static pid_t pid_synthesize_comm_event(pid_t pid) | |||
194 | goto out_failure; | 196 | goto out_failure; |
195 | size = sep - field; | 197 | size = sep - field; |
196 | memcpy(comm_ev.comm, field, size++); | 198 | memcpy(comm_ev.comm, field, size++); |
197 | field = strchr(sep + 4, ' '); | 199 | |
198 | if (field == NULL) | 200 | comm_ev.pid = pid; |
199 | goto out_failure; | ||
200 | comm_ev.pid = atoi(++field); | ||
201 | comm_ev.header.type = PERF_EVENT_COMM; | 201 | comm_ev.header.type = PERF_EVENT_COMM; |
202 | comm_ev.tid = pid; | ||
203 | size = ALIGN(size, sizeof(uint64_t)); | 202 | size = ALIGN(size, sizeof(uint64_t)); |
204 | comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); | 203 | comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); |
205 | 204 | ||
206 | ret = write(output, &comm_ev, comm_ev.header.size); | 205 | if (!full) { |
207 | if (ret < 0) { | 206 | comm_ev.tid = pid; |
208 | perror("failed to write"); | 207 | |
209 | exit(-1); | 208 | ret = write(output, &comm_ev, comm_ev.header.size); |
209 | if (ret < 0) { | ||
210 | perror("failed to write"); | ||
211 | exit(-1); | ||
212 | } | ||
213 | return; | ||
214 | } | ||
215 | |||
216 | snprintf(filename, sizeof(filename), "/proc/%d/task", pid); | ||
217 | |||
218 | tasks = opendir(filename); | ||
219 | while (!readdir_r(tasks, &dirent, &next) && next) { | ||
220 | char *end; | ||
221 | pid = strtol(dirent.d_name, &end, 10); | ||
222 | if (*end) | ||
223 | continue; | ||
224 | |||
225 | comm_ev.tid = pid; | ||
226 | |||
227 | ret = write(output, &comm_ev, comm_ev.header.size); | ||
228 | if (ret < 0) { | ||
229 | perror("failed to write"); | ||
230 | exit(-1); | ||
231 | } | ||
210 | } | 232 | } |
211 | return comm_ev.pid; | 233 | closedir(tasks); |
234 | return; | ||
235 | |||
212 | out_failure: | 236 | out_failure: |
213 | fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n", | 237 | fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n", |
214 | filename); | 238 | filename); |
215 | exit(EXIT_FAILURE); | 239 | exit(EXIT_FAILURE); |
216 | return -1; | ||
217 | } | 240 | } |
218 | 241 | ||
219 | static void pid_synthesize_mmap_events(pid_t pid, pid_t pgid) | 242 | static void pid_synthesize_mmap_events(pid_t pid) |
220 | { | 243 | { |
221 | char filename[PATH_MAX]; | 244 | char filename[PATH_MAX]; |
222 | FILE *fp; | 245 | FILE *fp; |
@@ -261,7 +284,7 @@ static void pid_synthesize_mmap_events(pid_t pid, pid_t pgid) | |||
261 | mmap_ev.len -= mmap_ev.start; | 284 | mmap_ev.len -= mmap_ev.start; |
262 | mmap_ev.header.size = (sizeof(mmap_ev) - | 285 | mmap_ev.header.size = (sizeof(mmap_ev) - |
263 | (sizeof(mmap_ev.filename) - size)); | 286 | (sizeof(mmap_ev.filename) - size)); |
264 | mmap_ev.pid = pgid; | 287 | mmap_ev.pid = pid; |
265 | mmap_ev.tid = pid; | 288 | mmap_ev.tid = pid; |
266 | 289 | ||
267 | if (write(output, &mmap_ev, mmap_ev.header.size) < 0) { | 290 | if (write(output, &mmap_ev, mmap_ev.header.size) < 0) { |
@@ -274,6 +297,28 @@ static void pid_synthesize_mmap_events(pid_t pid, pid_t pgid) | |||
274 | fclose(fp); | 297 | fclose(fp); |
275 | } | 298 | } |
276 | 299 | ||
300 | static void synthesize_events(void) | ||
301 | { | ||
302 | DIR *proc; | ||
303 | struct dirent dirent, *next; | ||
304 | |||
305 | proc = opendir("/proc"); | ||
306 | |||
307 | while (!readdir_r(proc, &dirent, &next) && next) { | ||
308 | char *end; | ||
309 | pid_t pid; | ||
310 | |||
311 | pid = strtol(dirent.d_name, &end, 10); | ||
312 | if (*end) /* only interested in proper numerical dirents */ | ||
313 | continue; | ||
314 | |||
315 | pid_synthesize_comm_event(pid, 1); | ||
316 | pid_synthesize_mmap_events(pid); | ||
317 | } | ||
318 | |||
319 | closedir(proc); | ||
320 | } | ||
321 | |||
277 | static void open_counters(int cpu, pid_t pid) | 322 | static void open_counters(int cpu, pid_t pid) |
278 | { | 323 | { |
279 | struct perf_counter_hw_event hw_event; | 324 | struct perf_counter_hw_event hw_event; |
@@ -281,8 +326,8 @@ static void open_counters(int cpu, pid_t pid) | |||
281 | int track = 1; | 326 | int track = 1; |
282 | 327 | ||
283 | if (pid > 0) { | 328 | if (pid > 0) { |
284 | pid_t pgid = pid_synthesize_comm_event(pid); | 329 | pid_synthesize_comm_event(pid, 0); |
285 | pid_synthesize_mmap_events(pid, pgid); | 330 | pid_synthesize_mmap_events(pid); |
286 | } | 331 | } |
287 | 332 | ||
288 | group_fd = -1; | 333 | group_fd = -1; |
@@ -348,7 +393,7 @@ static int __cmd_record(int argc, const char **argv) | |||
348 | assert(nr_cpus <= MAX_NR_CPUS); | 393 | assert(nr_cpus <= MAX_NR_CPUS); |
349 | assert(nr_cpus >= 0); | 394 | assert(nr_cpus >= 0); |
350 | 395 | ||
351 | output = open(output_name, O_CREAT|O_EXCL|O_RDWR, S_IRWXU); | 396 | output = open(output_name, O_CREAT|O_EXCL|O_TRUNC|O_RDWR, S_IRUSR|S_IWUSR); |
352 | if (output < 0) { | 397 | if (output < 0) { |
353 | perror("failed to create output file"); | 398 | perror("failed to create output file"); |
354 | exit(-1); | 399 | exit(-1); |
@@ -385,9 +430,8 @@ static int __cmd_record(int argc, const char **argv) | |||
385 | } | 430 | } |
386 | } | 431 | } |
387 | 432 | ||
388 | /* | 433 | if (system_wide) |
389 | * TODO: store the current /proc/$/maps information somewhere | 434 | synthesize_events(); |
390 | */ | ||
391 | 435 | ||
392 | while (!done) { | 436 | while (!done) { |
393 | int hits = events; | 437 | int hits = events; |