aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/Makefile3
-rw-r--r--tools/perf/builtin-record.c100
-rw-r--r--tools/perf/builtin-report.c37
-rw-r--r--tools/perf/perf.h8
-rw-r--r--tools/perf/util/header.c242
-rw-r--r--tools/perf/util/header.h37
-rw-r--r--tools/perf/util/string.h2
-rw-r--r--tools/perf/util/symbol.h2
-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
291LIB_H += ../../include/linux/perf_counter.h 291LIB_H += ../../include/linux/perf_counter.h
292LIB_H += perf.h 292LIB_H += perf.h
293LIB_H += types.h 293LIB_H += util/types.h
294LIB_H += util/list.h 294LIB_H += util/list.h
295LIB_H += util/rbtree.h 295LIB_H += util/rbtree.h
296LIB_H += util/levenshtein.h 296LIB_H += util/levenshtein.h
@@ -328,6 +328,7 @@ LIB_OBJS += util/sigchain.o
328LIB_OBJS += util/symbol.o 328LIB_OBJS += util/symbol.o
329LIB_OBJS += util/color.o 329LIB_OBJS += util/color.o
330LIB_OBJS += util/pager.o 330LIB_OBJS += util/pager.o
331LIB_OBJS += util/header.o
331 332
332BUILTIN_OBJS += builtin-annotate.o 333BUILTIN_OBJS += builtin-annotate.o
333BUILTIN_OBJS += builtin-help.o 334BUILTIN_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;
52static int nr_cpu; 54static int nr_cpu;
53 55
54static int file_new = 1; 56static int file_new = 1;
55static struct perf_file_header file_header; 57
58struct perf_header *header;
56 59
57struct mmap_event { 60struct 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
331static void synthesize_samples(void) 334static 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
353static int group_fd; 356static int group_fd;
354 357
358static 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
355static void create_counter(int counter, int cpu, pid_t pid) 372static 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
387try_again: 404try_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
459static void atexit_header(void) 484static 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
467static int __cmd_record(int argc, const char **argv) 491static 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
1388static struct perf_file_header file_header; 1389static struct perf_header *header;
1390
1391static 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
1390static int __cmd_report(void) 1405static 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
1448remap: 1466remap:
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
69struct 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
13struct 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
31void 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
49struct 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
71void 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
89static const char *__perf_magic = "PERFFILE";
90
91#define PERF_MAGIC (*(u64 *)__perf_magic)
92
93struct perf_file_section {
94 u64 offset;
95 u64 size;
96};
97
98struct perf_file_attr {
99 struct perf_counter_attr attr;
100 struct perf_file_section ids;
101};
102
103struct 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
111static 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
124void 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
181static 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
194struct 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
8struct perf_header_attr {
9 struct perf_counter_attr attr;
10 int ids, size;
11 u64 *id;
12 off_t id_offset;
13};
14
15struct 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
24struct perf_header *perf_header__read(int fd);
25void perf_header__write(struct perf_header *self, int fd);
26
27void perf_header__add_attr(struct perf_header *self,
28 struct perf_header_attr *attr);
29
30struct perf_header_attr *
31perf_header_attr__new(struct perf_counter_attr *attr);
32void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
33
34
35struct 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
6int hex2u64(const char *ptr, u64 *val); 6int 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