diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-06-25 11:05:54 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-25 15:39:04 -0400 |
commit | 7c6a1c65bbd3be688e581511f45818663efc1877 (patch) | |
tree | 28bfa19c484b266d5ef3daa04aba8a6831277bc2 /tools/perf | |
parent | e5c59547791f171b280bc4c4b2c3ff171824c1a3 (diff) |
perf_counter tools: Rework the file format
Create a structured file format that includes the full
perf_counter_attr and all its relevant counter IDs so that
the reporting program has full information.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Makefile | 3 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 100 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 37 | ||||
-rw-r--r-- | tools/perf/perf.h | 8 | ||||
-rw-r--r-- | tools/perf/util/header.c | 242 | ||||
-rw-r--r-- | tools/perf/util/header.h | 37 | ||||
-rw-r--r-- | tools/perf/util/string.h | 2 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 2 | ||||
-rw-r--r-- | tools/perf/util/types.h (renamed from tools/perf/types.h) | 0 |
9 files changed, 377 insertions, 54 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 36d7eef49913..d3887ed51a64 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -290,7 +290,7 @@ LIB_FILE=libperf.a | |||
290 | 290 | ||
291 | LIB_H += ../../include/linux/perf_counter.h | 291 | LIB_H += ../../include/linux/perf_counter.h |
292 | LIB_H += perf.h | 292 | LIB_H += perf.h |
293 | LIB_H += types.h | 293 | LIB_H += util/types.h |
294 | LIB_H += util/list.h | 294 | LIB_H += util/list.h |
295 | LIB_H += util/rbtree.h | 295 | LIB_H += util/rbtree.h |
296 | LIB_H += util/levenshtein.h | 296 | LIB_H += util/levenshtein.h |
@@ -328,6 +328,7 @@ LIB_OBJS += util/sigchain.o | |||
328 | LIB_OBJS += util/symbol.o | 328 | LIB_OBJS += util/symbol.o |
329 | LIB_OBJS += util/color.o | 329 | LIB_OBJS += util/color.o |
330 | LIB_OBJS += util/pager.o | 330 | LIB_OBJS += util/pager.o |
331 | LIB_OBJS += util/header.o | ||
331 | 332 | ||
332 | BUILTIN_OBJS += builtin-annotate.o | 333 | BUILTIN_OBJS += builtin-annotate.o |
333 | BUILTIN_OBJS += builtin-help.o | 334 | BUILTIN_OBJS += builtin-help.o |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 9b899ba1b410..f4f0240d2302 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -14,6 +14,8 @@ | |||
14 | #include "util/parse-events.h" | 14 | #include "util/parse-events.h" |
15 | #include "util/string.h" | 15 | #include "util/string.h" |
16 | 16 | ||
17 | #include "util/header.h" | ||
18 | |||
17 | #include <unistd.h> | 19 | #include <unistd.h> |
18 | #include <sched.h> | 20 | #include <sched.h> |
19 | 21 | ||
@@ -52,7 +54,8 @@ static int nr_poll; | |||
52 | static int nr_cpu; | 54 | static int nr_cpu; |
53 | 55 | ||
54 | static int file_new = 1; | 56 | static int file_new = 1; |
55 | static struct perf_file_header file_header; | 57 | |
58 | struct perf_header *header; | ||
56 | 59 | ||
57 | struct mmap_event { | 60 | struct mmap_event { |
58 | struct perf_event_header header; | 61 | struct perf_event_header header; |
@@ -328,7 +331,7 @@ static void pid_synthesize_mmap_samples(pid_t pid) | |||
328 | fclose(fp); | 331 | fclose(fp); |
329 | } | 332 | } |
330 | 333 | ||
331 | static void synthesize_samples(void) | 334 | static void synthesize_all(void) |
332 | { | 335 | { |
333 | DIR *proc; | 336 | DIR *proc; |
334 | struct dirent dirent, *next; | 337 | struct dirent dirent, *next; |
@@ -352,10 +355,35 @@ static void synthesize_samples(void) | |||
352 | 355 | ||
353 | static int group_fd; | 356 | static int group_fd; |
354 | 357 | ||
358 | static struct perf_header_attr *get_header_attr(struct perf_counter_attr *a, int nr) | ||
359 | { | ||
360 | struct perf_header_attr *h_attr; | ||
361 | |||
362 | if (nr < header->attrs) { | ||
363 | h_attr = header->attr[nr]; | ||
364 | } else { | ||
365 | h_attr = perf_header_attr__new(a); | ||
366 | perf_header__add_attr(header, h_attr); | ||
367 | } | ||
368 | |||
369 | return h_attr; | ||
370 | } | ||
371 | |||
355 | static void create_counter(int counter, int cpu, pid_t pid) | 372 | static void create_counter(int counter, int cpu, pid_t pid) |
356 | { | 373 | { |
357 | struct perf_counter_attr *attr = attrs + counter; | 374 | struct perf_counter_attr *attr = attrs + counter; |
358 | int track = 1; | 375 | struct perf_header_attr *h_attr; |
376 | int track = !counter; /* only the first counter needs these */ | ||
377 | struct { | ||
378 | u64 count; | ||
379 | u64 time_enabled; | ||
380 | u64 time_running; | ||
381 | u64 id; | ||
382 | } read_data; | ||
383 | |||
384 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | ||
385 | PERF_FORMAT_TOTAL_TIME_RUNNING | | ||
386 | PERF_FORMAT_ID; | ||
359 | 387 | ||
360 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 388 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
361 | 389 | ||
@@ -368,22 +396,11 @@ static void create_counter(int counter, int cpu, pid_t pid) | |||
368 | if (call_graph) | 396 | if (call_graph) |
369 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; | 397 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; |
370 | 398 | ||
371 | if (file_new) { | ||
372 | file_header.sample_type = attr->sample_type; | ||
373 | } else { | ||
374 | if (file_header.sample_type != attr->sample_type) { | ||
375 | fprintf(stderr, "incompatible append\n"); | ||
376 | exit(-1); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | attr->mmap = track; | 399 | attr->mmap = track; |
381 | attr->comm = track; | 400 | attr->comm = track; |
382 | attr->inherit = (cpu < 0) && inherit; | 401 | attr->inherit = (cpu < 0) && inherit; |
383 | attr->disabled = 1; | 402 | attr->disabled = 1; |
384 | 403 | ||
385 | track = 0; /* only the first counter needs these */ | ||
386 | |||
387 | try_again: | 404 | try_again: |
388 | fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0); | 405 | fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0); |
389 | 406 | ||
@@ -414,6 +431,19 @@ try_again: | |||
414 | exit(-1); | 431 | exit(-1); |
415 | } | 432 | } |
416 | 433 | ||
434 | h_attr = get_header_attr(attr, counter); | ||
435 | |||
436 | if (!file_new) { | ||
437 | if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { | ||
438 | fprintf(stderr, "incompatible append\n"); | ||
439 | exit(-1); | ||
440 | } | ||
441 | } | ||
442 | |||
443 | read(fd[nr_cpu][counter], &read_data, sizeof(read_data)); | ||
444 | |||
445 | perf_header_attr__add_id(h_attr, read_data.id); | ||
446 | |||
417 | assert(fd[nr_cpu][counter] >= 0); | 447 | assert(fd[nr_cpu][counter] >= 0); |
418 | fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); | 448 | fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); |
419 | 449 | ||
@@ -444,11 +474,6 @@ static void open_counters(int cpu, pid_t pid) | |||
444 | { | 474 | { |
445 | int counter; | 475 | int counter; |
446 | 476 | ||
447 | if (pid > 0) { | ||
448 | pid_synthesize_comm_event(pid, 0); | ||
449 | pid_synthesize_mmap_samples(pid); | ||
450 | } | ||
451 | |||
452 | group_fd = -1; | 477 | group_fd = -1; |
453 | for (counter = 0; counter < nr_counters; counter++) | 478 | for (counter = 0; counter < nr_counters; counter++) |
454 | create_counter(counter, cpu, pid); | 479 | create_counter(counter, cpu, pid); |
@@ -458,17 +483,16 @@ static void open_counters(int cpu, pid_t pid) | |||
458 | 483 | ||
459 | static void atexit_header(void) | 484 | static void atexit_header(void) |
460 | { | 485 | { |
461 | file_header.data_size += bytes_written; | 486 | header->data_size += bytes_written; |
462 | 487 | ||
463 | if (pwrite(output, &file_header, sizeof(file_header), 0) == -1) | 488 | perf_header__write(header, output); |
464 | perror("failed to write on file headers"); | ||
465 | } | 489 | } |
466 | 490 | ||
467 | static int __cmd_record(int argc, const char **argv) | 491 | static int __cmd_record(int argc, const char **argv) |
468 | { | 492 | { |
469 | int i, counter; | 493 | int i, counter; |
470 | struct stat st; | 494 | struct stat st; |
471 | pid_t pid; | 495 | pid_t pid = 0; |
472 | int flags; | 496 | int flags; |
473 | int ret; | 497 | int ret; |
474 | 498 | ||
@@ -499,22 +523,31 @@ static int __cmd_record(int argc, const char **argv) | |||
499 | exit(-1); | 523 | exit(-1); |
500 | } | 524 | } |
501 | 525 | ||
502 | if (!file_new) { | 526 | if (!file_new) |
503 | if (read(output, &file_header, sizeof(file_header)) == -1) { | 527 | header = perf_header__read(output); |
504 | perror("failed to read file headers"); | 528 | else |
505 | exit(-1); | 529 | header = perf_header__new(); |
506 | } | ||
507 | |||
508 | lseek(output, file_header.data_size, SEEK_CUR); | ||
509 | } | ||
510 | 530 | ||
511 | atexit(atexit_header); | 531 | atexit(atexit_header); |
512 | 532 | ||
513 | if (!system_wide) { | 533 | if (!system_wide) { |
514 | open_counters(-1, target_pid != -1 ? target_pid : getpid()); | 534 | pid = target_pid; |
535 | if (pid == -1) | ||
536 | pid = getpid(); | ||
537 | |||
538 | open_counters(-1, pid); | ||
515 | } else for (i = 0; i < nr_cpus; i++) | 539 | } else for (i = 0; i < nr_cpus; i++) |
516 | open_counters(i, target_pid); | 540 | open_counters(i, target_pid); |
517 | 541 | ||
542 | if (file_new) | ||
543 | perf_header__write(header, output); | ||
544 | |||
545 | if (!system_wide) { | ||
546 | pid_synthesize_comm_event(pid, 0); | ||
547 | pid_synthesize_mmap_samples(pid); | ||
548 | } else | ||
549 | synthesize_all(); | ||
550 | |||
518 | if (target_pid == -1 && argc) { | 551 | if (target_pid == -1 && argc) { |
519 | pid = fork(); | 552 | pid = fork(); |
520 | if (pid < 0) | 553 | if (pid < 0) |
@@ -538,9 +571,6 @@ static int __cmd_record(int argc, const char **argv) | |||
538 | } | 571 | } |
539 | } | 572 | } |
540 | 573 | ||
541 | if (system_wide) | ||
542 | synthesize_samples(); | ||
543 | |||
544 | while (!done) { | 574 | while (!done) { |
545 | int hits = samples; | 575 | int hits = samples; |
546 | 576 | ||
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index b4e76f75ba87..e575f3039766 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include "util/string.h" | 17 | #include "util/string.h" |
18 | 18 | ||
19 | #include "perf.h" | 19 | #include "perf.h" |
20 | #include "util/header.h" | ||
20 | 21 | ||
21 | #include "util/parse-options.h" | 22 | #include "util/parse-options.h" |
22 | #include "util/parse-events.h" | 23 | #include "util/parse-events.h" |
@@ -1385,13 +1386,27 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
1385 | return 0; | 1386 | return 0; |
1386 | } | 1387 | } |
1387 | 1388 | ||
1388 | static struct perf_file_header file_header; | 1389 | static struct perf_header *header; |
1390 | |||
1391 | static int perf_header__has_sample(u64 sample_mask) | ||
1392 | { | ||
1393 | int i; | ||
1394 | |||
1395 | for (i = 0; i < header->attrs; i++) { | ||
1396 | struct perf_header_attr *attr = header->attr[i]; | ||
1397 | |||
1398 | if (!(attr->attr.sample_type & sample_mask)) | ||
1399 | return 0; | ||
1400 | } | ||
1401 | |||
1402 | return 1; | ||
1403 | } | ||
1389 | 1404 | ||
1390 | static int __cmd_report(void) | 1405 | static int __cmd_report(void) |
1391 | { | 1406 | { |
1392 | int ret, rc = EXIT_FAILURE; | 1407 | int ret, rc = EXIT_FAILURE; |
1393 | unsigned long offset = 0; | 1408 | unsigned long offset = 0; |
1394 | unsigned long head = sizeof(file_header); | 1409 | unsigned long head, shift; |
1395 | struct stat stat; | 1410 | struct stat stat; |
1396 | event_t *event; | 1411 | event_t *event; |
1397 | uint32_t size; | 1412 | uint32_t size; |
@@ -1419,13 +1434,11 @@ static int __cmd_report(void) | |||
1419 | exit(0); | 1434 | exit(0); |
1420 | } | 1435 | } |
1421 | 1436 | ||
1422 | if (read(input, &file_header, sizeof(file_header)) == -1) { | 1437 | header = perf_header__read(input); |
1423 | perror("failed to read file headers"); | 1438 | head = header->data_offset; |
1424 | exit(-1); | ||
1425 | } | ||
1426 | 1439 | ||
1427 | if (sort__has_parent && | 1440 | if (sort__has_parent && |
1428 | !(file_header.sample_type & PERF_SAMPLE_CALLCHAIN)) { | 1441 | !perf_header__has_sample(PERF_SAMPLE_CALLCHAIN)) { |
1429 | fprintf(stderr, "selected --sort parent, but no callchain data\n"); | 1442 | fprintf(stderr, "selected --sort parent, but no callchain data\n"); |
1430 | exit(-1); | 1443 | exit(-1); |
1431 | } | 1444 | } |
@@ -1445,6 +1458,11 @@ static int __cmd_report(void) | |||
1445 | cwd = NULL; | 1458 | cwd = NULL; |
1446 | cwdlen = 0; | 1459 | cwdlen = 0; |
1447 | } | 1460 | } |
1461 | |||
1462 | shift = page_size * (head / page_size); | ||
1463 | offset += shift; | ||
1464 | head -= shift; | ||
1465 | |||
1448 | remap: | 1466 | remap: |
1449 | buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, | 1467 | buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, |
1450 | MAP_SHARED, input, offset); | 1468 | MAP_SHARED, input, offset); |
@@ -1461,9 +1479,10 @@ more: | |||
1461 | size = 8; | 1479 | size = 8; |
1462 | 1480 | ||
1463 | if (head + event->header.size >= page_size * mmap_window) { | 1481 | if (head + event->header.size >= page_size * mmap_window) { |
1464 | unsigned long shift = page_size * (head / page_size); | ||
1465 | int ret; | 1482 | int ret; |
1466 | 1483 | ||
1484 | shift = page_size * (head / page_size); | ||
1485 | |||
1467 | ret = munmap(buf, page_size * mmap_window); | 1486 | ret = munmap(buf, page_size * mmap_window); |
1468 | assert(ret == 0); | 1487 | assert(ret == 0); |
1469 | 1488 | ||
@@ -1501,7 +1520,7 @@ more: | |||
1501 | 1520 | ||
1502 | head += size; | 1521 | head += size; |
1503 | 1522 | ||
1504 | if (offset + head >= sizeof(file_header) + file_header.data_size) | 1523 | if (offset + head >= header->data_offset + header->data_size) |
1505 | goto done; | 1524 | goto done; |
1506 | 1525 | ||
1507 | if (offset + head < stat.st_size) | 1526 | if (offset + head < stat.st_size) |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index bccb529dac08..16c84fd73c86 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -19,7 +19,7 @@ | |||
19 | #include <sys/syscall.h> | 19 | #include <sys/syscall.h> |
20 | 20 | ||
21 | #include "../../include/linux/perf_counter.h" | 21 | #include "../../include/linux/perf_counter.h" |
22 | #include "types.h" | 22 | #include "util/types.h" |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all | 25 | * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all |
@@ -66,10 +66,4 @@ sys_perf_counter_open(struct perf_counter_attr *attr, | |||
66 | #define MAX_COUNTERS 256 | 66 | #define MAX_COUNTERS 256 |
67 | #define MAX_NR_CPUS 256 | 67 | #define MAX_NR_CPUS 256 |
68 | 68 | ||
69 | struct perf_file_header { | ||
70 | u64 version; | ||
71 | u64 sample_type; | ||
72 | u64 data_size; | ||
73 | }; | ||
74 | |||
75 | #endif | 69 | #endif |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c new file mode 100644 index 000000000000..450384b3bbe5 --- /dev/null +++ b/tools/perf/util/header.c | |||
@@ -0,0 +1,242 @@ | |||
1 | #include <sys/types.h> | ||
2 | #include <unistd.h> | ||
3 | #include <stdio.h> | ||
4 | #include <stdlib.h> | ||
5 | |||
6 | #include "util.h" | ||
7 | #include "header.h" | ||
8 | |||
9 | /* | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | struct perf_header_attr *perf_header_attr__new(struct perf_counter_attr *attr) | ||
14 | { | ||
15 | struct perf_header_attr *self = malloc(sizeof(*self)); | ||
16 | |||
17 | if (!self) | ||
18 | die("nomem"); | ||
19 | |||
20 | self->attr = *attr; | ||
21 | self->ids = 0; | ||
22 | self->size = 1; | ||
23 | self->id = malloc(sizeof(u64)); | ||
24 | |||
25 | if (!self->id) | ||
26 | die("nomem"); | ||
27 | |||
28 | return self; | ||
29 | } | ||
30 | |||
31 | void perf_header_attr__add_id(struct perf_header_attr *self, u64 id) | ||
32 | { | ||
33 | int pos = self->ids; | ||
34 | |||
35 | self->ids++; | ||
36 | if (self->ids > self->size) { | ||
37 | self->size *= 2; | ||
38 | self->id = realloc(self->id, self->size * sizeof(u64)); | ||
39 | if (!self->id) | ||
40 | die("nomem"); | ||
41 | } | ||
42 | self->id[pos] = id; | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * | ||
47 | */ | ||
48 | |||
49 | struct perf_header *perf_header__new(void) | ||
50 | { | ||
51 | struct perf_header *self = malloc(sizeof(*self)); | ||
52 | |||
53 | if (!self) | ||
54 | die("nomem"); | ||
55 | |||
56 | self->frozen = 0; | ||
57 | |||
58 | self->attrs = 0; | ||
59 | self->size = 1; | ||
60 | self->attr = malloc(sizeof(void *)); | ||
61 | |||
62 | if (!self->attr) | ||
63 | die("nomem"); | ||
64 | |||
65 | self->data_offset = 0; | ||
66 | self->data_size = 0; | ||
67 | |||
68 | return self; | ||
69 | } | ||
70 | |||
71 | void perf_header__add_attr(struct perf_header *self, | ||
72 | struct perf_header_attr *attr) | ||
73 | { | ||
74 | int pos = self->attrs; | ||
75 | |||
76 | if (self->frozen) | ||
77 | die("frozen"); | ||
78 | |||
79 | self->attrs++; | ||
80 | if (self->attrs > self->size) { | ||
81 | self->size *= 2; | ||
82 | self->attr = realloc(self->attr, self->size * sizeof(void *)); | ||
83 | if (!self->attr) | ||
84 | die("nomem"); | ||
85 | } | ||
86 | self->attr[pos] = attr; | ||
87 | } | ||
88 | |||
89 | static const char *__perf_magic = "PERFFILE"; | ||
90 | |||
91 | #define PERF_MAGIC (*(u64 *)__perf_magic) | ||
92 | |||
93 | struct perf_file_section { | ||
94 | u64 offset; | ||
95 | u64 size; | ||
96 | }; | ||
97 | |||
98 | struct perf_file_attr { | ||
99 | struct perf_counter_attr attr; | ||
100 | struct perf_file_section ids; | ||
101 | }; | ||
102 | |||
103 | struct perf_file_header { | ||
104 | u64 magic; | ||
105 | u64 size; | ||
106 | u64 attr_size; | ||
107 | struct perf_file_section attrs; | ||
108 | struct perf_file_section data; | ||
109 | }; | ||
110 | |||
111 | static void do_write(int fd, void *buf, size_t size) | ||
112 | { | ||
113 | while (size) { | ||
114 | int ret = write(fd, buf, size); | ||
115 | |||
116 | if (ret < 0) | ||
117 | die("failed to write"); | ||
118 | |||
119 | size -= ret; | ||
120 | buf += ret; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | void perf_header__write(struct perf_header *self, int fd) | ||
125 | { | ||
126 | struct perf_file_header f_header; | ||
127 | struct perf_file_attr f_attr; | ||
128 | struct perf_header_attr *attr; | ||
129 | int i; | ||
130 | |||
131 | lseek(fd, sizeof(f_header), SEEK_SET); | ||
132 | |||
133 | |||
134 | for (i = 0; i < self->attrs; i++) { | ||
135 | attr = self->attr[i]; | ||
136 | |||
137 | attr->id_offset = lseek(fd, 0, SEEK_CUR); | ||
138 | do_write(fd, attr->id, attr->ids * sizeof(u64)); | ||
139 | } | ||
140 | |||
141 | |||
142 | self->attr_offset = lseek(fd, 0, SEEK_CUR); | ||
143 | |||
144 | for (i = 0; i < self->attrs; i++) { | ||
145 | attr = self->attr[i]; | ||
146 | |||
147 | f_attr = (struct perf_file_attr){ | ||
148 | .attr = attr->attr, | ||
149 | .ids = { | ||
150 | .offset = attr->id_offset, | ||
151 | .size = attr->ids * sizeof(u64), | ||
152 | } | ||
153 | }; | ||
154 | do_write(fd, &f_attr, sizeof(f_attr)); | ||
155 | } | ||
156 | |||
157 | |||
158 | self->data_offset = lseek(fd, 0, SEEK_CUR); | ||
159 | |||
160 | f_header = (struct perf_file_header){ | ||
161 | .magic = PERF_MAGIC, | ||
162 | .size = sizeof(f_header), | ||
163 | .attr_size = sizeof(f_attr), | ||
164 | .attrs = { | ||
165 | .offset = self->attr_offset, | ||
166 | .size = self->attrs * sizeof(f_attr), | ||
167 | }, | ||
168 | .data = { | ||
169 | .offset = self->data_offset, | ||
170 | .size = self->data_size, | ||
171 | }, | ||
172 | }; | ||
173 | |||
174 | lseek(fd, 0, SEEK_SET); | ||
175 | do_write(fd, &f_header, sizeof(f_header)); | ||
176 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); | ||
177 | |||
178 | self->frozen = 1; | ||
179 | } | ||
180 | |||
181 | static void do_read(int fd, void *buf, size_t size) | ||
182 | { | ||
183 | while (size) { | ||
184 | int ret = read(fd, buf, size); | ||
185 | |||
186 | if (ret < 0) | ||
187 | die("failed to read"); | ||
188 | |||
189 | size -= ret; | ||
190 | buf += ret; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | struct perf_header *perf_header__read(int fd) | ||
195 | { | ||
196 | struct perf_header *self = perf_header__new(); | ||
197 | struct perf_file_header f_header; | ||
198 | struct perf_file_attr f_attr; | ||
199 | u64 f_id; | ||
200 | |||
201 | int nr_attrs, nr_ids, i, j; | ||
202 | |||
203 | lseek(fd, 0, SEEK_SET); | ||
204 | do_read(fd, &f_header, sizeof(f_header)); | ||
205 | |||
206 | if (f_header.magic != PERF_MAGIC || | ||
207 | f_header.size != sizeof(f_header) || | ||
208 | f_header.attr_size != sizeof(f_attr)) | ||
209 | die("incompatible file format"); | ||
210 | |||
211 | nr_attrs = f_header.attrs.size / sizeof(f_attr); | ||
212 | lseek(fd, f_header.attrs.offset, SEEK_SET); | ||
213 | |||
214 | for (i = 0; i < nr_attrs; i++) { | ||
215 | struct perf_header_attr *attr; | ||
216 | off_t tmp = lseek(fd, 0, SEEK_CUR); | ||
217 | |||
218 | do_read(fd, &f_attr, sizeof(f_attr)); | ||
219 | |||
220 | attr = perf_header_attr__new(&f_attr.attr); | ||
221 | |||
222 | nr_ids = f_attr.ids.size / sizeof(u64); | ||
223 | lseek(fd, f_attr.ids.offset, SEEK_SET); | ||
224 | |||
225 | for (j = 0; j < nr_ids; j++) { | ||
226 | do_read(fd, &f_id, sizeof(f_id)); | ||
227 | |||
228 | perf_header_attr__add_id(attr, f_id); | ||
229 | } | ||
230 | perf_header__add_attr(self, attr); | ||
231 | lseek(fd, tmp, SEEK_SET); | ||
232 | } | ||
233 | |||
234 | self->data_offset = f_header.data.offset; | ||
235 | self->data_size = f_header.data.size; | ||
236 | |||
237 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); | ||
238 | |||
239 | self->frozen = 1; | ||
240 | |||
241 | return self; | ||
242 | } | ||
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h new file mode 100644 index 000000000000..b5ef53ad4c7a --- /dev/null +++ b/tools/perf/util/header.h | |||
@@ -0,0 +1,37 @@ | |||
1 | #ifndef _PERF_HEADER_H | ||
2 | #define _PERF_HEADER_H | ||
3 | |||
4 | #include "../../../include/linux/perf_counter.h" | ||
5 | #include <sys/types.h> | ||
6 | #include "types.h" | ||
7 | |||
8 | struct perf_header_attr { | ||
9 | struct perf_counter_attr attr; | ||
10 | int ids, size; | ||
11 | u64 *id; | ||
12 | off_t id_offset; | ||
13 | }; | ||
14 | |||
15 | struct perf_header { | ||
16 | int frozen; | ||
17 | int attrs, size; | ||
18 | struct perf_header_attr **attr; | ||
19 | off_t attr_offset; | ||
20 | u64 data_offset; | ||
21 | u64 data_size; | ||
22 | }; | ||
23 | |||
24 | struct perf_header *perf_header__read(int fd); | ||
25 | void perf_header__write(struct perf_header *self, int fd); | ||
26 | |||
27 | void perf_header__add_attr(struct perf_header *self, | ||
28 | struct perf_header_attr *attr); | ||
29 | |||
30 | struct perf_header_attr * | ||
31 | perf_header_attr__new(struct perf_counter_attr *attr); | ||
32 | void perf_header_attr__add_id(struct perf_header_attr *self, u64 id); | ||
33 | |||
34 | |||
35 | struct perf_header *perf_header__new(void); | ||
36 | |||
37 | #endif /* _PERF_HEADER_H */ | ||
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h index 37b03255b425..3dca2f654cd0 100644 --- a/tools/perf/util/string.h +++ b/tools/perf/util/string.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #ifndef _PERF_STRING_H_ | 1 | #ifndef _PERF_STRING_H_ |
2 | #define _PERF_STRING_H_ | 2 | #define _PERF_STRING_H_ |
3 | 3 | ||
4 | #include "../types.h" | 4 | #include "types.h" |
5 | 5 | ||
6 | int hex2u64(const char *ptr, u64 *val); | 6 | int hex2u64(const char *ptr, u64 *val); |
7 | 7 | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index ea332e56e458..940b432db16e 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -2,7 +2,7 @@ | |||
2 | #define _PERF_SYMBOL_ 1 | 2 | #define _PERF_SYMBOL_ 1 |
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include "../types.h" | 5 | #include "types.h" |
6 | #include "list.h" | 6 | #include "list.h" |
7 | #include "rbtree.h" | 7 | #include "rbtree.h" |
8 | 8 | ||
diff --git a/tools/perf/types.h b/tools/perf/util/types.h index 5e75f9005940..5e75f9005940 100644 --- a/tools/perf/types.h +++ b/tools/perf/util/types.h | |||