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/util | |
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/util')
-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 | 17 |
5 files changed, 298 insertions, 2 deletions
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/util/types.h b/tools/perf/util/types.h new file mode 100644 index 000000000000..5e75f9005940 --- /dev/null +++ b/tools/perf/util/types.h | |||
@@ -0,0 +1,17 @@ | |||
1 | #ifndef _PERF_TYPES_H | ||
2 | #define _PERF_TYPES_H | ||
3 | |||
4 | /* | ||
5 | * We define u64 as unsigned long long for every architecture | ||
6 | * so that we can print it with %Lx without getting warnings. | ||
7 | */ | ||
8 | typedef unsigned long long u64; | ||
9 | typedef signed long long s64; | ||
10 | typedef unsigned int u32; | ||
11 | typedef signed int s32; | ||
12 | typedef unsigned short u16; | ||
13 | typedef signed short s16; | ||
14 | typedef unsigned char u8; | ||
15 | typedef signed char s8; | ||
16 | |||
17 | #endif /* _PERF_TYPES_H */ | ||