diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-06-18 17:22:55 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-19 07:42:36 -0400 |
commit | f5970550d5ccf90453cbd7d260370ea99d1f6513 (patch) | |
tree | f09c265d9c44bf0cb74d5e998626c6dede5e14c9 | |
parent | 2a0a50fe9def21835d65035cc8109c0b6dd6099d (diff) |
perf_counter tools: Add a data file header
Add a data file header so we can transfer data between record and report.
LKML-Reference: <new-submission>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | tools/perf/builtin-record.c | 94 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 16 | ||||
-rw-r--r-- | tools/perf/perf.h | 6 |
3 files changed, 73 insertions, 43 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 06fdfb8b4828..28304677c73e 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -51,6 +51,9 @@ static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; | |||
51 | static int nr_poll; | 51 | static int nr_poll; |
52 | static int nr_cpu; | 52 | static int nr_cpu; |
53 | 53 | ||
54 | static int file_new = 1; | ||
55 | static struct perf_file_header file_header; | ||
56 | |||
54 | struct mmap_event { | 57 | struct mmap_event { |
55 | struct perf_event_header header; | 58 | struct perf_event_header header; |
56 | __u32 pid; | 59 | __u32 pid; |
@@ -100,6 +103,21 @@ static void mmap_write_tail(struct mmap_data *md, unsigned long tail) | |||
100 | pc->data_tail = tail; | 103 | pc->data_tail = tail; |
101 | } | 104 | } |
102 | 105 | ||
106 | static void write_output(void *buf, size_t size) | ||
107 | { | ||
108 | while (size) { | ||
109 | int ret = write(output, buf, size); | ||
110 | |||
111 | if (ret < 0) | ||
112 | die("failed to write"); | ||
113 | |||
114 | size -= ret; | ||
115 | buf += ret; | ||
116 | |||
117 | bytes_written += ret; | ||
118 | } | ||
119 | } | ||
120 | |||
103 | static void mmap_read(struct mmap_data *md) | 121 | static void mmap_read(struct mmap_data *md) |
104 | { | 122 | { |
105 | unsigned int head = mmap_read_head(md); | 123 | unsigned int head = mmap_read_head(md); |
@@ -148,34 +166,14 @@ static void mmap_read(struct mmap_data *md) | |||
148 | size = md->mask + 1 - (old & md->mask); | 166 | size = md->mask + 1 - (old & md->mask); |
149 | old += size; | 167 | old += size; |
150 | 168 | ||
151 | while (size) { | 169 | write_output(buf, size); |
152 | int ret = write(output, buf, size); | ||
153 | |||
154 | if (ret < 0) | ||
155 | die("failed to write"); | ||
156 | |||
157 | size -= ret; | ||
158 | buf += ret; | ||
159 | |||
160 | bytes_written += ret; | ||
161 | } | ||
162 | } | 170 | } |
163 | 171 | ||
164 | buf = &data[old & md->mask]; | 172 | buf = &data[old & md->mask]; |
165 | size = head - old; | 173 | size = head - old; |
166 | old += size; | 174 | old += size; |
167 | 175 | ||
168 | while (size) { | 176 | write_output(buf, size); |
169 | int ret = write(output, buf, size); | ||
170 | |||
171 | if (ret < 0) | ||
172 | die("failed to write"); | ||
173 | |||
174 | size -= ret; | ||
175 | buf += ret; | ||
176 | |||
177 | bytes_written += ret; | ||
178 | } | ||
179 | 177 | ||
180 | md->prev = old; | 178 | md->prev = old; |
181 | mmap_write_tail(md, old); | 179 | mmap_write_tail(md, old); |
@@ -204,7 +202,7 @@ static void pid_synthesize_comm_event(pid_t pid, int full) | |||
204 | struct comm_event comm_ev; | 202 | struct comm_event comm_ev; |
205 | char filename[PATH_MAX]; | 203 | char filename[PATH_MAX]; |
206 | char bf[BUFSIZ]; | 204 | char bf[BUFSIZ]; |
207 | int fd, ret; | 205 | int fd; |
208 | size_t size; | 206 | size_t size; |
209 | char *field, *sep; | 207 | char *field, *sep; |
210 | DIR *tasks; | 208 | DIR *tasks; |
@@ -246,11 +244,7 @@ static void pid_synthesize_comm_event(pid_t pid, int full) | |||
246 | if (!full) { | 244 | if (!full) { |
247 | comm_ev.tid = pid; | 245 | comm_ev.tid = pid; |
248 | 246 | ||
249 | ret = write(output, &comm_ev, comm_ev.header.size); | 247 | write_output(&comm_ev, comm_ev.header.size); |
250 | if (ret < 0) { | ||
251 | perror("failed to write"); | ||
252 | exit(-1); | ||
253 | } | ||
254 | return; | 248 | return; |
255 | } | 249 | } |
256 | 250 | ||
@@ -265,11 +259,7 @@ static void pid_synthesize_comm_event(pid_t pid, int full) | |||
265 | 259 | ||
266 | comm_ev.tid = pid; | 260 | comm_ev.tid = pid; |
267 | 261 | ||
268 | ret = write(output, &comm_ev, comm_ev.header.size); | 262 | write_output(&comm_ev, comm_ev.header.size); |
269 | if (ret < 0) { | ||
270 | perror("failed to write"); | ||
271 | exit(-1); | ||
272 | } | ||
273 | } | 263 | } |
274 | closedir(tasks); | 264 | closedir(tasks); |
275 | return; | 265 | return; |
@@ -332,10 +322,7 @@ static void pid_synthesize_mmap_samples(pid_t pid) | |||
332 | mmap_ev.pid = pid; | 322 | mmap_ev.pid = pid; |
333 | mmap_ev.tid = pid; | 323 | mmap_ev.tid = pid; |
334 | 324 | ||
335 | if (write(output, &mmap_ev, mmap_ev.header.size) < 0) { | 325 | write_output(&mmap_ev, mmap_ev.header.size); |
336 | perror("failed to write"); | ||
337 | exit(-1); | ||
338 | } | ||
339 | } | 326 | } |
340 | } | 327 | } |
341 | 328 | ||
@@ -382,6 +369,15 @@ static void create_counter(int counter, int cpu, pid_t pid) | |||
382 | if (call_graph) | 369 | if (call_graph) |
383 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; | 370 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; |
384 | 371 | ||
372 | if (file_new) { | ||
373 | file_header.sample_type = attr->sample_type; | ||
374 | } else { | ||
375 | if (file_header.sample_type != attr->sample_type) { | ||
376 | fprintf(stderr, "incompatible append\n"); | ||
377 | exit(-1); | ||
378 | } | ||
379 | } | ||
380 | |||
385 | attr->mmap = track; | 381 | attr->mmap = track; |
386 | attr->comm = track; | 382 | attr->comm = track; |
387 | attr->inherit = (cpu < 0) && inherit; | 383 | attr->inherit = (cpu < 0) && inherit; |
@@ -461,6 +457,13 @@ static void open_counters(int cpu, pid_t pid) | |||
461 | nr_cpu++; | 457 | nr_cpu++; |
462 | } | 458 | } |
463 | 459 | ||
460 | static void atexit_header(void) | ||
461 | { | ||
462 | file_header.data_size += bytes_written; | ||
463 | |||
464 | pwrite(output, &file_header, sizeof(file_header), 0); | ||
465 | } | ||
466 | |||
464 | static int __cmd_record(int argc, const char **argv) | 467 | static int __cmd_record(int argc, const char **argv) |
465 | { | 468 | { |
466 | int i, counter; | 469 | int i, counter; |
@@ -474,6 +477,10 @@ static int __cmd_record(int argc, const char **argv) | |||
474 | assert(nr_cpus <= MAX_NR_CPUS); | 477 | assert(nr_cpus <= MAX_NR_CPUS); |
475 | assert(nr_cpus >= 0); | 478 | assert(nr_cpus >= 0); |
476 | 479 | ||
480 | atexit(sig_atexit); | ||
481 | signal(SIGCHLD, sig_handler); | ||
482 | signal(SIGINT, sig_handler); | ||
483 | |||
477 | if (!stat(output_name, &st) && !force && !append_file) { | 484 | if (!stat(output_name, &st) && !force && !append_file) { |
478 | fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", | 485 | fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", |
479 | output_name); | 486 | output_name); |
@@ -482,7 +489,7 @@ static int __cmd_record(int argc, const char **argv) | |||
482 | 489 | ||
483 | flags = O_CREAT|O_RDWR; | 490 | flags = O_CREAT|O_RDWR; |
484 | if (append_file) | 491 | if (append_file) |
485 | flags |= O_APPEND; | 492 | file_new = 0; |
486 | else | 493 | else |
487 | flags |= O_TRUNC; | 494 | flags |= O_TRUNC; |
488 | 495 | ||
@@ -492,15 +499,18 @@ static int __cmd_record(int argc, const char **argv) | |||
492 | exit(-1); | 499 | exit(-1); |
493 | } | 500 | } |
494 | 501 | ||
502 | if (!file_new) { | ||
503 | read(output, &file_header, sizeof(file_header)); | ||
504 | lseek(output, file_header.data_size, SEEK_CUR); | ||
505 | } | ||
506 | |||
507 | atexit(atexit_header); | ||
508 | |||
495 | if (!system_wide) { | 509 | if (!system_wide) { |
496 | open_counters(-1, target_pid != -1 ? target_pid : getpid()); | 510 | open_counters(-1, target_pid != -1 ? target_pid : getpid()); |
497 | } else for (i = 0; i < nr_cpus; i++) | 511 | } else for (i = 0; i < nr_cpus; i++) |
498 | open_counters(i, target_pid); | 512 | open_counters(i, target_pid); |
499 | 513 | ||
500 | atexit(sig_atexit); | ||
501 | signal(SIGCHLD, sig_handler); | ||
502 | signal(SIGINT, sig_handler); | ||
503 | |||
504 | if (target_pid == -1 && argc) { | 514 | if (target_pid == -1 && argc) { |
505 | pid = fork(); | 515 | pid = fork(); |
506 | if (pid < 0) | 516 | if (pid < 0) |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 7a6577bf9a41..37b26ecb0d0b 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -1366,11 +1366,13 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
1366 | return 0; | 1366 | return 0; |
1367 | } | 1367 | } |
1368 | 1368 | ||
1369 | static struct perf_file_header file_header; | ||
1370 | |||
1369 | static int __cmd_report(void) | 1371 | static int __cmd_report(void) |
1370 | { | 1372 | { |
1371 | int ret, rc = EXIT_FAILURE; | 1373 | int ret, rc = EXIT_FAILURE; |
1372 | unsigned long offset = 0; | 1374 | unsigned long offset = 0; |
1373 | unsigned long head = 0; | 1375 | unsigned long head = sizeof(file_header); |
1374 | struct stat stat; | 1376 | struct stat stat; |
1375 | event_t *event; | 1377 | event_t *event; |
1376 | uint32_t size; | 1378 | uint32_t size; |
@@ -1398,6 +1400,14 @@ static int __cmd_report(void) | |||
1398 | exit(0); | 1400 | exit(0); |
1399 | } | 1401 | } |
1400 | 1402 | ||
1403 | read(input, &file_header, sizeof(file_header)); | ||
1404 | |||
1405 | if (sort__has_parent && | ||
1406 | !(file_header.sample_type & PERF_SAMPLE_CALLCHAIN)) { | ||
1407 | fprintf(stderr, "selected --sort parent, but no callchain data\n"); | ||
1408 | exit(-1); | ||
1409 | } | ||
1410 | |||
1401 | if (load_kernel() < 0) { | 1411 | if (load_kernel() < 0) { |
1402 | perror("failed to load kernel symbols"); | 1412 | perror("failed to load kernel symbols"); |
1403 | return EXIT_FAILURE; | 1413 | return EXIT_FAILURE; |
@@ -1469,9 +1479,13 @@ more: | |||
1469 | 1479 | ||
1470 | head += size; | 1480 | head += size; |
1471 | 1481 | ||
1482 | if (offset + head >= sizeof(file_header) + file_header.data_size) | ||
1483 | goto done; | ||
1484 | |||
1472 | if (offset + head < stat.st_size) | 1485 | if (offset + head < stat.st_size) |
1473 | goto more; | 1486 | goto more; |
1474 | 1487 | ||
1488 | done: | ||
1475 | rc = EXIT_SUCCESS; | 1489 | rc = EXIT_SUCCESS; |
1476 | close(input); | 1490 | close(input); |
1477 | 1491 | ||
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 87a1aca4a424..55c62f4b990b 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -65,4 +65,10 @@ sys_perf_counter_open(struct perf_counter_attr *attr, | |||
65 | #define MAX_COUNTERS 256 | 65 | #define MAX_COUNTERS 256 |
66 | #define MAX_NR_CPUS 256 | 66 | #define MAX_NR_CPUS 256 |
67 | 67 | ||
68 | struct perf_file_header { | ||
69 | __u64 version; | ||
70 | __u64 sample_type; | ||
71 | __u64 data_size; | ||
72 | }; | ||
73 | |||
68 | #endif | 74 | #endif |