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 /tools | |
| 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>
Diffstat (limited to 'tools')
| -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 |
