diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2009-12-11 18:24:02 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-12-12 01:42:12 -0500 |
commit | 94c744b6c0c6c5802a85ebfebbec429ac5851f2b (patch) | |
tree | e34dcaca54f1d7752ab1e7974bb73f94ff3cf94c /tools/perf/util | |
parent | ea08d8cbd162fe3756e3e2298efbe0b8b12f92d1 (diff) |
perf tools: Introduce perf_session class
That does all the initialization boilerplate, opening the file,
reading the header, checking if it is valid, etc.
And that will as well have the threads list, kmap (now) global
variable, etc, so that we can handle two (or more) perf.data files
describing sessions to compare.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1260573842-19720-1-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/data_map.c | 71 | ||||
-rw-r--r-- | tools/perf/util/data_map.h | 9 | ||||
-rw-r--r-- | tools/perf/util/header.c | 28 | ||||
-rw-r--r-- | tools/perf/util/header.h | 4 | ||||
-rw-r--r-- | tools/perf/util/session.c | 80 | ||||
-rw-r--r-- | tools/perf/util/session.h | 16 |
6 files changed, 118 insertions, 90 deletions
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index 59b65d0bd7c1..6d46dda53a29 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c | |||
@@ -129,23 +129,16 @@ out: | |||
129 | return err; | 129 | return err; |
130 | } | 130 | } |
131 | 131 | ||
132 | int mmap_dispatch_perf_file(struct perf_header **pheader, | 132 | int perf_session__process_events(struct perf_session *self, |
133 | const char *input_name, | 133 | int full_paths, int *cwdlen, char **cwd) |
134 | int force, | ||
135 | int full_paths, | ||
136 | int *cwdlen, | ||
137 | char **cwd) | ||
138 | { | 134 | { |
139 | int err; | 135 | int err; |
140 | struct perf_header *header; | ||
141 | unsigned long head, shift; | 136 | unsigned long head, shift; |
142 | unsigned long offset = 0; | 137 | unsigned long offset = 0; |
143 | struct stat input_stat; | ||
144 | size_t page_size; | 138 | size_t page_size; |
145 | u64 sample_type; | 139 | u64 sample_type; |
146 | event_t *event; | 140 | event_t *event; |
147 | uint32_t size; | 141 | uint32_t size; |
148 | int input; | ||
149 | char *buf; | 142 | char *buf; |
150 | 143 | ||
151 | if (curr_handler == NULL) { | 144 | if (curr_handler == NULL) { |
@@ -155,56 +148,19 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, | |||
155 | 148 | ||
156 | page_size = getpagesize(); | 149 | page_size = getpagesize(); |
157 | 150 | ||
158 | input = open(input_name, O_RDONLY); | 151 | head = self->header.data_offset; |
159 | if (input < 0) { | 152 | sample_type = perf_header__sample_type(&self->header); |
160 | pr_err("Failed to open file: %s", input_name); | ||
161 | if (!strcmp(input_name, "perf.data")) | ||
162 | pr_err(" (try 'perf record' first)"); | ||
163 | pr_err("\n"); | ||
164 | return -errno; | ||
165 | } | ||
166 | |||
167 | if (fstat(input, &input_stat) < 0) { | ||
168 | pr_err("failed to stat file"); | ||
169 | err = -errno; | ||
170 | goto out_close; | ||
171 | } | ||
172 | |||
173 | err = -EACCES; | ||
174 | if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) { | ||
175 | pr_err("file: %s not owned by current user or root\n", | ||
176 | input_name); | ||
177 | goto out_close; | ||
178 | } | ||
179 | |||
180 | if (input_stat.st_size == 0) { | ||
181 | pr_info("zero-sized file, nothing to do!\n"); | ||
182 | goto done; | ||
183 | } | ||
184 | |||
185 | err = -ENOMEM; | ||
186 | header = perf_header__new(); | ||
187 | if (header == NULL) | ||
188 | goto out_close; | ||
189 | |||
190 | err = perf_header__read(header, input); | ||
191 | if (err < 0) | ||
192 | goto out_delete; | ||
193 | *pheader = header; | ||
194 | head = header->data_offset; | ||
195 | |||
196 | sample_type = perf_header__sample_type(header); | ||
197 | 153 | ||
198 | err = -EINVAL; | 154 | err = -EINVAL; |
199 | if (curr_handler->sample_type_check && | 155 | if (curr_handler->sample_type_check && |
200 | curr_handler->sample_type_check(sample_type) < 0) | 156 | curr_handler->sample_type_check(sample_type) < 0) |
201 | goto out_delete; | 157 | goto out_err; |
202 | 158 | ||
203 | if (!full_paths) { | 159 | if (!full_paths) { |
204 | if (getcwd(__cwd, sizeof(__cwd)) == NULL) { | 160 | if (getcwd(__cwd, sizeof(__cwd)) == NULL) { |
205 | pr_err("failed to get the current directory\n"); | 161 | pr_err("failed to get the current directory\n"); |
206 | err = -errno; | 162 | err = -errno; |
207 | goto out_delete; | 163 | goto out_err; |
208 | } | 164 | } |
209 | *cwd = __cwd; | 165 | *cwd = __cwd; |
210 | *cwdlen = strlen(*cwd); | 166 | *cwdlen = strlen(*cwd); |
@@ -219,11 +175,11 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, | |||
219 | 175 | ||
220 | remap: | 176 | remap: |
221 | buf = mmap(NULL, page_size * mmap_window, PROT_READ, | 177 | buf = mmap(NULL, page_size * mmap_window, PROT_READ, |
222 | MAP_SHARED, input, offset); | 178 | MAP_SHARED, self->fd, offset); |
223 | if (buf == MAP_FAILED) { | 179 | if (buf == MAP_FAILED) { |
224 | pr_err("failed to mmap file\n"); | 180 | pr_err("failed to mmap file\n"); |
225 | err = -errno; | 181 | err = -errno; |
226 | goto out_delete; | 182 | goto out_err; |
227 | } | 183 | } |
228 | 184 | ||
229 | more: | 185 | more: |
@@ -273,19 +229,14 @@ more: | |||
273 | 229 | ||
274 | head += size; | 230 | head += size; |
275 | 231 | ||
276 | if (offset + head >= header->data_offset + header->data_size) | 232 | if (offset + head >= self->header.data_offset + self->header.data_size) |
277 | goto done; | 233 | goto done; |
278 | 234 | ||
279 | if (offset + head < (unsigned long)input_stat.st_size) | 235 | if (offset + head < self->size) |
280 | goto more; | 236 | goto more; |
281 | 237 | ||
282 | done: | 238 | done: |
283 | err = 0; | 239 | err = 0; |
284 | out_close: | 240 | out_err: |
285 | close(input); | ||
286 | |||
287 | return err; | 241 | return err; |
288 | out_delete: | ||
289 | perf_header__delete(header); | ||
290 | goto out_close; | ||
291 | } | 242 | } |
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h index 258a87bcc4fb..98c5b823388c 100644 --- a/tools/perf/util/data_map.h +++ b/tools/perf/util/data_map.h | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include "event.h" | 4 | #include "event.h" |
5 | #include "header.h" | 5 | #include "header.h" |
6 | #include "session.h" | ||
6 | 7 | ||
7 | typedef int (*event_type_handler_t)(event_t *); | 8 | typedef int (*event_type_handler_t)(event_t *); |
8 | 9 | ||
@@ -21,12 +22,8 @@ struct perf_file_handler { | |||
21 | }; | 22 | }; |
22 | 23 | ||
23 | void register_perf_file_handler(struct perf_file_handler *handler); | 24 | void register_perf_file_handler(struct perf_file_handler *handler); |
24 | int mmap_dispatch_perf_file(struct perf_header **pheader, | 25 | int perf_session__process_events(struct perf_session *self, |
25 | const char *input_name, | 26 | int full_paths, int *cwdlen, char **cwd); |
26 | int force, | ||
27 | int full_paths, | ||
28 | int *cwdlen, | ||
29 | char **cwd); | ||
30 | int perf_header__read_build_ids(int input, u64 offset, u64 file_size); | 27 | int perf_header__read_build_ids(int input, u64 offset, u64 file_size); |
31 | 28 | ||
32 | #endif | 29 | #endif |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 59a9c0b3033e..f2e8d8715111 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -58,35 +58,19 @@ int perf_header_attr__add_id(struct perf_header_attr *self, u64 id) | |||
58 | return 0; | 58 | return 0; |
59 | } | 59 | } |
60 | 60 | ||
61 | /* | 61 | int perf_header__init(struct perf_header *self) |
62 | * Create new perf.data header: | ||
63 | */ | ||
64 | struct perf_header *perf_header__new(void) | ||
65 | { | 62 | { |
66 | struct perf_header *self = zalloc(sizeof(*self)); | 63 | self->size = 1; |
67 | 64 | self->attr = malloc(sizeof(void *)); | |
68 | if (self != NULL) { | 65 | return self->attr == NULL ? -ENOMEM : 0; |
69 | self->size = 1; | ||
70 | self->attr = malloc(sizeof(void *)); | ||
71 | |||
72 | if (self->attr == NULL) { | ||
73 | free(self); | ||
74 | self = NULL; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | return self; | ||
79 | } | 66 | } |
80 | 67 | ||
81 | void perf_header__delete(struct perf_header *self) | 68 | void perf_header__exit(struct perf_header *self) |
82 | { | 69 | { |
83 | int i; | 70 | int i; |
84 | |||
85 | for (i = 0; i < self->attrs; ++i) | 71 | for (i = 0; i < self->attrs; ++i) |
86 | perf_header_attr__delete(self->attr[i]); | 72 | perf_header_attr__delete(self->attr[i]); |
87 | |||
88 | free(self->attr); | 73 | free(self->attr); |
89 | free(self); | ||
90 | } | 74 | } |
91 | 75 | ||
92 | int perf_header__add_attr(struct perf_header *self, | 76 | int perf_header__add_attr(struct perf_header *self, |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index d1dbe2b79c42..d118d05d3abe 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -55,8 +55,8 @@ struct perf_header { | |||
55 | DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); | 55 | DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); |
56 | }; | 56 | }; |
57 | 57 | ||
58 | struct perf_header *perf_header__new(void); | 58 | int perf_header__init(struct perf_header *self); |
59 | void perf_header__delete(struct perf_header *self); | 59 | void perf_header__exit(struct perf_header *self); |
60 | 60 | ||
61 | int perf_header__read(struct perf_header *self, int fd); | 61 | int perf_header__read(struct perf_header *self, int fd); |
62 | int perf_header__write(struct perf_header *self, int fd, bool at_exit); | 62 | int perf_header__write(struct perf_header *self, int fd, bool at_exit); |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c new file mode 100644 index 000000000000..707ce1cb1621 --- /dev/null +++ b/tools/perf/util/session.c | |||
@@ -0,0 +1,80 @@ | |||
1 | #include <linux/kernel.h> | ||
2 | |||
3 | #include <unistd.h> | ||
4 | #include <sys/types.h> | ||
5 | |||
6 | #include "session.h" | ||
7 | #include "util.h" | ||
8 | |||
9 | static int perf_session__open(struct perf_session *self, bool force) | ||
10 | { | ||
11 | struct stat input_stat; | ||
12 | |||
13 | self->fd = open(self->filename, O_RDONLY); | ||
14 | if (self->fd < 0) { | ||
15 | pr_err("failed to open file: %s", self->filename); | ||
16 | if (!strcmp(self->filename, "perf.data")) | ||
17 | pr_err(" (try 'perf record' first)"); | ||
18 | pr_err("\n"); | ||
19 | return -errno; | ||
20 | } | ||
21 | |||
22 | if (fstat(self->fd, &input_stat) < 0) | ||
23 | goto out_close; | ||
24 | |||
25 | if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) { | ||
26 | pr_err("file %s not owned by current user or root\n", | ||
27 | self->filename); | ||
28 | goto out_close; | ||
29 | } | ||
30 | |||
31 | if (!input_stat.st_size) { | ||
32 | pr_info("zero-sized file (%s), nothing to do!\n", | ||
33 | self->filename); | ||
34 | goto out_close; | ||
35 | } | ||
36 | |||
37 | if (perf_header__read(&self->header, self->fd) < 0) { | ||
38 | pr_err("incompatible file format"); | ||
39 | goto out_close; | ||
40 | } | ||
41 | |||
42 | self->size = input_stat.st_size; | ||
43 | return 0; | ||
44 | |||
45 | out_close: | ||
46 | close(self->fd); | ||
47 | self->fd = -1; | ||
48 | return -1; | ||
49 | } | ||
50 | |||
51 | struct perf_session *perf_session__new(const char *filename, int mode, bool force) | ||
52 | { | ||
53 | size_t len = strlen(filename) + 1; | ||
54 | struct perf_session *self = zalloc(sizeof(*self) + len); | ||
55 | |||
56 | if (self == NULL) | ||
57 | goto out; | ||
58 | |||
59 | if (perf_header__init(&self->header) < 0) | ||
60 | goto out_delete; | ||
61 | |||
62 | memcpy(self->filename, filename, len); | ||
63 | |||
64 | if (mode == O_RDONLY && perf_session__open(self, force) < 0) { | ||
65 | perf_session__delete(self); | ||
66 | self = NULL; | ||
67 | } | ||
68 | out: | ||
69 | return self; | ||
70 | out_delete: | ||
71 | free(self); | ||
72 | return NULL; | ||
73 | } | ||
74 | |||
75 | void perf_session__delete(struct perf_session *self) | ||
76 | { | ||
77 | perf_header__exit(&self->header); | ||
78 | close(self->fd); | ||
79 | free(self); | ||
80 | } | ||
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h new file mode 100644 index 000000000000..f3699c8c8ed4 --- /dev/null +++ b/tools/perf/util/session.h | |||
@@ -0,0 +1,16 @@ | |||
1 | #ifndef __PERF_SESSION_H | ||
2 | #define __PERF_SESSION_H | ||
3 | |||
4 | #include "header.h" | ||
5 | |||
6 | struct perf_session { | ||
7 | struct perf_header header; | ||
8 | unsigned long size; | ||
9 | int fd; | ||
10 | char filename[0]; | ||
11 | }; | ||
12 | |||
13 | struct perf_session *perf_session__new(const char *filename, int mode, bool force); | ||
14 | void perf_session__delete(struct perf_session *self); | ||
15 | |||
16 | #endif /* __PERF_SESSION_H */ | ||