diff options
| -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 | |||
