diff options
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r-- | tools/perf/util/header.c | 615 |
1 files changed, 299 insertions, 316 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index d7e67b167ea3..afb0849fe530 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -8,6 +8,8 @@ | |||
8 | #include <linux/list.h> | 8 | #include <linux/list.h> |
9 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
10 | 10 | ||
11 | #include "evlist.h" | ||
12 | #include "evsel.h" | ||
11 | #include "util.h" | 13 | #include "util.h" |
12 | #include "header.h" | 14 | #include "header.h" |
13 | #include "../perf.h" | 15 | #include "../perf.h" |
@@ -18,89 +20,6 @@ | |||
18 | 20 | ||
19 | static bool no_buildid_cache = false; | 21 | static bool no_buildid_cache = false; |
20 | 22 | ||
21 | /* | ||
22 | * Create new perf.data header attribute: | ||
23 | */ | ||
24 | struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr) | ||
25 | { | ||
26 | struct perf_header_attr *self = malloc(sizeof(*self)); | ||
27 | |||
28 | if (self != NULL) { | ||
29 | self->attr = *attr; | ||
30 | self->ids = 0; | ||
31 | self->size = 1; | ||
32 | self->id = malloc(sizeof(u64)); | ||
33 | if (self->id == NULL) { | ||
34 | free(self); | ||
35 | self = NULL; | ||
36 | } | ||
37 | } | ||
38 | |||
39 | return self; | ||
40 | } | ||
41 | |||
42 | void perf_header_attr__delete(struct perf_header_attr *self) | ||
43 | { | ||
44 | free(self->id); | ||
45 | free(self); | ||
46 | } | ||
47 | |||
48 | int perf_header_attr__add_id(struct perf_header_attr *self, u64 id) | ||
49 | { | ||
50 | int pos = self->ids; | ||
51 | |||
52 | self->ids++; | ||
53 | if (self->ids > self->size) { | ||
54 | int nsize = self->size * 2; | ||
55 | u64 *nid = realloc(self->id, nsize * sizeof(u64)); | ||
56 | |||
57 | if (nid == NULL) | ||
58 | return -1; | ||
59 | |||
60 | self->size = nsize; | ||
61 | self->id = nid; | ||
62 | } | ||
63 | self->id[pos] = id; | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | int perf_header__init(struct perf_header *self) | ||
68 | { | ||
69 | self->size = 1; | ||
70 | self->attr = malloc(sizeof(void *)); | ||
71 | return self->attr == NULL ? -ENOMEM : 0; | ||
72 | } | ||
73 | |||
74 | void perf_header__exit(struct perf_header *self) | ||
75 | { | ||
76 | int i; | ||
77 | for (i = 0; i < self->attrs; ++i) | ||
78 | perf_header_attr__delete(self->attr[i]); | ||
79 | free(self->attr); | ||
80 | } | ||
81 | |||
82 | int perf_header__add_attr(struct perf_header *self, | ||
83 | struct perf_header_attr *attr) | ||
84 | { | ||
85 | if (self->frozen) | ||
86 | return -1; | ||
87 | |||
88 | if (self->attrs == self->size) { | ||
89 | int nsize = self->size * 2; | ||
90 | struct perf_header_attr **nattr; | ||
91 | |||
92 | nattr = realloc(self->attr, nsize * sizeof(void *)); | ||
93 | if (nattr == NULL) | ||
94 | return -1; | ||
95 | |||
96 | self->size = nsize; | ||
97 | self->attr = nattr; | ||
98 | } | ||
99 | |||
100 | self->attr[self->attrs++] = attr; | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int event_count; | 23 | static int event_count; |
105 | static struct perf_trace_event_type *events; | 24 | static struct perf_trace_event_type *events; |
106 | 25 | ||
@@ -147,14 +66,19 @@ struct perf_file_attr { | |||
147 | struct perf_file_section ids; | 66 | struct perf_file_section ids; |
148 | }; | 67 | }; |
149 | 68 | ||
150 | void perf_header__set_feat(struct perf_header *self, int feat) | 69 | void perf_header__set_feat(struct perf_header *header, int feat) |
70 | { | ||
71 | set_bit(feat, header->adds_features); | ||
72 | } | ||
73 | |||
74 | void perf_header__clear_feat(struct perf_header *header, int feat) | ||
151 | { | 75 | { |
152 | set_bit(feat, self->adds_features); | 76 | clear_bit(feat, header->adds_features); |
153 | } | 77 | } |
154 | 78 | ||
155 | bool perf_header__has_feat(const struct perf_header *self, int feat) | 79 | bool perf_header__has_feat(const struct perf_header *header, int feat) |
156 | { | 80 | { |
157 | return test_bit(feat, self->adds_features); | 81 | return test_bit(feat, header->adds_features); |
158 | } | 82 | } |
159 | 83 | ||
160 | static int do_write(int fd, const void *buf, size_t size) | 84 | static int do_write(int fd, const void *buf, size_t size) |
@@ -223,22 +147,22 @@ static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, | |||
223 | return 0; | 147 | return 0; |
224 | } | 148 | } |
225 | 149 | ||
226 | static int machine__write_buildid_table(struct machine *self, int fd) | 150 | static int machine__write_buildid_table(struct machine *machine, int fd) |
227 | { | 151 | { |
228 | int err; | 152 | int err; |
229 | u16 kmisc = PERF_RECORD_MISC_KERNEL, | 153 | u16 kmisc = PERF_RECORD_MISC_KERNEL, |
230 | umisc = PERF_RECORD_MISC_USER; | 154 | umisc = PERF_RECORD_MISC_USER; |
231 | 155 | ||
232 | if (!machine__is_host(self)) { | 156 | if (!machine__is_host(machine)) { |
233 | kmisc = PERF_RECORD_MISC_GUEST_KERNEL; | 157 | kmisc = PERF_RECORD_MISC_GUEST_KERNEL; |
234 | umisc = PERF_RECORD_MISC_GUEST_USER; | 158 | umisc = PERF_RECORD_MISC_GUEST_USER; |
235 | } | 159 | } |
236 | 160 | ||
237 | err = __dsos__write_buildid_table(&self->kernel_dsos, self->pid, | 161 | err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid, |
238 | kmisc, fd); | 162 | kmisc, fd); |
239 | if (err == 0) | 163 | if (err == 0) |
240 | err = __dsos__write_buildid_table(&self->user_dsos, | 164 | err = __dsos__write_buildid_table(&machine->user_dsos, |
241 | self->pid, umisc, fd); | 165 | machine->pid, umisc, fd); |
242 | return err; | 166 | return err; |
243 | } | 167 | } |
244 | 168 | ||
@@ -265,15 +189,24 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | |||
265 | const char *name, bool is_kallsyms) | 189 | const char *name, bool is_kallsyms) |
266 | { | 190 | { |
267 | const size_t size = PATH_MAX; | 191 | const size_t size = PATH_MAX; |
268 | char *filename = malloc(size), | 192 | char *realname, *filename = malloc(size), |
269 | *linkname = malloc(size), *targetname; | 193 | *linkname = malloc(size), *targetname; |
270 | int len, err = -1; | 194 | int len, err = -1; |
271 | 195 | ||
272 | if (filename == NULL || linkname == NULL) | 196 | if (is_kallsyms) { |
197 | if (symbol_conf.kptr_restrict) { | ||
198 | pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); | ||
199 | return 0; | ||
200 | } | ||
201 | realname = (char *)name; | ||
202 | } else | ||
203 | realname = realpath(name, NULL); | ||
204 | |||
205 | if (realname == NULL || filename == NULL || linkname == NULL) | ||
273 | goto out_free; | 206 | goto out_free; |
274 | 207 | ||
275 | len = snprintf(filename, size, "%s%s%s", | 208 | len = snprintf(filename, size, "%s%s%s", |
276 | debugdir, is_kallsyms ? "/" : "", name); | 209 | debugdir, is_kallsyms ? "/" : "", realname); |
277 | if (mkdir_p(filename, 0755)) | 210 | if (mkdir_p(filename, 0755)) |
278 | goto out_free; | 211 | goto out_free; |
279 | 212 | ||
@@ -283,7 +216,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | |||
283 | if (is_kallsyms) { | 216 | if (is_kallsyms) { |
284 | if (copyfile("/proc/kallsyms", filename)) | 217 | if (copyfile("/proc/kallsyms", filename)) |
285 | goto out_free; | 218 | goto out_free; |
286 | } else if (link(name, filename) && copyfile(name, filename)) | 219 | } else if (link(realname, filename) && copyfile(name, filename)) |
287 | goto out_free; | 220 | goto out_free; |
288 | } | 221 | } |
289 | 222 | ||
@@ -300,6 +233,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | |||
300 | if (symlink(targetname, linkname) == 0) | 233 | if (symlink(targetname, linkname) == 0) |
301 | err = 0; | 234 | err = 0; |
302 | out_free: | 235 | out_free: |
236 | if (!is_kallsyms) | ||
237 | free(realname); | ||
303 | free(filename); | 238 | free(filename); |
304 | free(linkname); | 239 | free(linkname); |
305 | return err; | 240 | return err; |
@@ -354,12 +289,12 @@ out_free: | |||
354 | return err; | 289 | return err; |
355 | } | 290 | } |
356 | 291 | ||
357 | static int dso__cache_build_id(struct dso *self, const char *debugdir) | 292 | static int dso__cache_build_id(struct dso *dso, const char *debugdir) |
358 | { | 293 | { |
359 | bool is_kallsyms = self->kernel && self->long_name[0] != '/'; | 294 | bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; |
360 | 295 | ||
361 | return build_id_cache__add_b(self->build_id, sizeof(self->build_id), | 296 | return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), |
362 | self->long_name, debugdir, is_kallsyms); | 297 | dso->long_name, debugdir, is_kallsyms); |
363 | } | 298 | } |
364 | 299 | ||
365 | static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) | 300 | static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) |
@@ -374,14 +309,14 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) | |||
374 | return err; | 309 | return err; |
375 | } | 310 | } |
376 | 311 | ||
377 | static int machine__cache_build_ids(struct machine *self, const char *debugdir) | 312 | static int machine__cache_build_ids(struct machine *machine, const char *debugdir) |
378 | { | 313 | { |
379 | int ret = __dsos__cache_build_ids(&self->kernel_dsos, debugdir); | 314 | int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir); |
380 | ret |= __dsos__cache_build_ids(&self->user_dsos, debugdir); | 315 | ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir); |
381 | return ret; | 316 | return ret; |
382 | } | 317 | } |
383 | 318 | ||
384 | static int perf_session__cache_build_ids(struct perf_session *self) | 319 | static int perf_session__cache_build_ids(struct perf_session *session) |
385 | { | 320 | { |
386 | struct rb_node *nd; | 321 | struct rb_node *nd; |
387 | int ret; | 322 | int ret; |
@@ -392,28 +327,28 @@ static int perf_session__cache_build_ids(struct perf_session *self) | |||
392 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) | 327 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) |
393 | return -1; | 328 | return -1; |
394 | 329 | ||
395 | ret = machine__cache_build_ids(&self->host_machine, debugdir); | 330 | ret = machine__cache_build_ids(&session->host_machine, debugdir); |
396 | 331 | ||
397 | for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) { | 332 | for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { |
398 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 333 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
399 | ret |= machine__cache_build_ids(pos, debugdir); | 334 | ret |= machine__cache_build_ids(pos, debugdir); |
400 | } | 335 | } |
401 | return ret ? -1 : 0; | 336 | return ret ? -1 : 0; |
402 | } | 337 | } |
403 | 338 | ||
404 | static bool machine__read_build_ids(struct machine *self, bool with_hits) | 339 | static bool machine__read_build_ids(struct machine *machine, bool with_hits) |
405 | { | 340 | { |
406 | bool ret = __dsos__read_build_ids(&self->kernel_dsos, with_hits); | 341 | bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits); |
407 | ret |= __dsos__read_build_ids(&self->user_dsos, with_hits); | 342 | ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits); |
408 | return ret; | 343 | return ret; |
409 | } | 344 | } |
410 | 345 | ||
411 | static bool perf_session__read_build_ids(struct perf_session *self, bool with_hits) | 346 | static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) |
412 | { | 347 | { |
413 | struct rb_node *nd; | 348 | struct rb_node *nd; |
414 | bool ret = machine__read_build_ids(&self->host_machine, with_hits); | 349 | bool ret = machine__read_build_ids(&session->host_machine, with_hits); |
415 | 350 | ||
416 | for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) { | 351 | for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { |
417 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 352 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
418 | ret |= machine__read_build_ids(pos, with_hits); | 353 | ret |= machine__read_build_ids(pos, with_hits); |
419 | } | 354 | } |
@@ -421,7 +356,8 @@ static bool perf_session__read_build_ids(struct perf_session *self, bool with_hi | |||
421 | return ret; | 356 | return ret; |
422 | } | 357 | } |
423 | 358 | ||
424 | static int perf_header__adds_write(struct perf_header *self, int fd) | 359 | static int perf_header__adds_write(struct perf_header *header, |
360 | struct perf_evlist *evlist, int fd) | ||
425 | { | 361 | { |
426 | int nr_sections; | 362 | int nr_sections; |
427 | struct perf_session *session; | 363 | struct perf_session *session; |
@@ -430,11 +366,13 @@ static int perf_header__adds_write(struct perf_header *self, int fd) | |||
430 | u64 sec_start; | 366 | u64 sec_start; |
431 | int idx = 0, err; | 367 | int idx = 0, err; |
432 | 368 | ||
433 | session = container_of(self, struct perf_session, header); | 369 | session = container_of(header, struct perf_session, header); |
434 | if (perf_session__read_build_ids(session, true)) | ||
435 | perf_header__set_feat(self, HEADER_BUILD_ID); | ||
436 | 370 | ||
437 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); | 371 | if (perf_header__has_feat(header, HEADER_BUILD_ID && |
372 | !perf_session__read_build_ids(session, true))) | ||
373 | perf_header__clear_feat(header, HEADER_BUILD_ID); | ||
374 | |||
375 | nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); | ||
438 | if (!nr_sections) | 376 | if (!nr_sections) |
439 | return 0; | 377 | return 0; |
440 | 378 | ||
@@ -444,28 +382,28 @@ static int perf_header__adds_write(struct perf_header *self, int fd) | |||
444 | 382 | ||
445 | sec_size = sizeof(*feat_sec) * nr_sections; | 383 | sec_size = sizeof(*feat_sec) * nr_sections; |
446 | 384 | ||
447 | sec_start = self->data_offset + self->data_size; | 385 | sec_start = header->data_offset + header->data_size; |
448 | lseek(fd, sec_start + sec_size, SEEK_SET); | 386 | lseek(fd, sec_start + sec_size, SEEK_SET); |
449 | 387 | ||
450 | if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { | 388 | if (perf_header__has_feat(header, HEADER_TRACE_INFO)) { |
451 | struct perf_file_section *trace_sec; | 389 | struct perf_file_section *trace_sec; |
452 | 390 | ||
453 | trace_sec = &feat_sec[idx++]; | 391 | trace_sec = &feat_sec[idx++]; |
454 | 392 | ||
455 | /* Write trace info */ | 393 | /* Write trace info */ |
456 | trace_sec->offset = lseek(fd, 0, SEEK_CUR); | 394 | trace_sec->offset = lseek(fd, 0, SEEK_CUR); |
457 | read_tracing_data(fd, attrs, nr_counters); | 395 | read_tracing_data(fd, &evlist->entries); |
458 | trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; | 396 | trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; |
459 | } | 397 | } |
460 | 398 | ||
461 | if (perf_header__has_feat(self, HEADER_BUILD_ID)) { | 399 | if (perf_header__has_feat(header, HEADER_BUILD_ID)) { |
462 | struct perf_file_section *buildid_sec; | 400 | struct perf_file_section *buildid_sec; |
463 | 401 | ||
464 | buildid_sec = &feat_sec[idx++]; | 402 | buildid_sec = &feat_sec[idx++]; |
465 | 403 | ||
466 | /* Write build-ids */ | 404 | /* Write build-ids */ |
467 | buildid_sec->offset = lseek(fd, 0, SEEK_CUR); | 405 | buildid_sec->offset = lseek(fd, 0, SEEK_CUR); |
468 | err = dsos__write_buildid_table(self, fd); | 406 | err = dsos__write_buildid_table(header, fd); |
469 | if (err < 0) { | 407 | if (err < 0) { |
470 | pr_debug("failed to write buildid table\n"); | 408 | pr_debug("failed to write buildid table\n"); |
471 | goto out_free; | 409 | goto out_free; |
@@ -504,32 +442,41 @@ int perf_header__write_pipe(int fd) | |||
504 | return 0; | 442 | return 0; |
505 | } | 443 | } |
506 | 444 | ||
507 | int perf_header__write(struct perf_header *self, int fd, bool at_exit) | 445 | int perf_session__write_header(struct perf_session *session, |
446 | struct perf_evlist *evlist, | ||
447 | int fd, bool at_exit) | ||
508 | { | 448 | { |
509 | struct perf_file_header f_header; | 449 | struct perf_file_header f_header; |
510 | struct perf_file_attr f_attr; | 450 | struct perf_file_attr f_attr; |
511 | struct perf_header_attr *attr; | 451 | struct perf_header *header = &session->header; |
512 | int i, err; | 452 | struct perf_evsel *attr, *pair = NULL; |
453 | int err; | ||
513 | 454 | ||
514 | lseek(fd, sizeof(f_header), SEEK_SET); | 455 | lseek(fd, sizeof(f_header), SEEK_SET); |
515 | 456 | ||
516 | for (i = 0; i < self->attrs; i++) { | 457 | if (session->evlist != evlist) |
517 | attr = self->attr[i]; | 458 | pair = list_entry(session->evlist->entries.next, struct perf_evsel, node); |
518 | 459 | ||
460 | list_for_each_entry(attr, &evlist->entries, node) { | ||
519 | attr->id_offset = lseek(fd, 0, SEEK_CUR); | 461 | attr->id_offset = lseek(fd, 0, SEEK_CUR); |
520 | err = do_write(fd, attr->id, attr->ids * sizeof(u64)); | 462 | err = do_write(fd, attr->id, attr->ids * sizeof(u64)); |
521 | if (err < 0) { | 463 | if (err < 0) { |
464 | out_err_write: | ||
522 | pr_debug("failed to write perf header\n"); | 465 | pr_debug("failed to write perf header\n"); |
523 | return err; | 466 | return err; |
524 | } | 467 | } |
468 | if (session->evlist != evlist) { | ||
469 | err = do_write(fd, pair->id, pair->ids * sizeof(u64)); | ||
470 | if (err < 0) | ||
471 | goto out_err_write; | ||
472 | attr->ids += pair->ids; | ||
473 | pair = list_entry(pair->node.next, struct perf_evsel, node); | ||
474 | } | ||
525 | } | 475 | } |
526 | 476 | ||
477 | header->attr_offset = lseek(fd, 0, SEEK_CUR); | ||
527 | 478 | ||
528 | self->attr_offset = lseek(fd, 0, SEEK_CUR); | 479 | list_for_each_entry(attr, &evlist->entries, node) { |
529 | |||
530 | for (i = 0; i < self->attrs; i++) { | ||
531 | attr = self->attr[i]; | ||
532 | |||
533 | f_attr = (struct perf_file_attr){ | 480 | f_attr = (struct perf_file_attr){ |
534 | .attr = attr->attr, | 481 | .attr = attr->attr, |
535 | .ids = { | 482 | .ids = { |
@@ -544,20 +491,20 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit) | |||
544 | } | 491 | } |
545 | } | 492 | } |
546 | 493 | ||
547 | self->event_offset = lseek(fd, 0, SEEK_CUR); | 494 | header->event_offset = lseek(fd, 0, SEEK_CUR); |
548 | self->event_size = event_count * sizeof(struct perf_trace_event_type); | 495 | header->event_size = event_count * sizeof(struct perf_trace_event_type); |
549 | if (events) { | 496 | if (events) { |
550 | err = do_write(fd, events, self->event_size); | 497 | err = do_write(fd, events, header->event_size); |
551 | if (err < 0) { | 498 | if (err < 0) { |
552 | pr_debug("failed to write perf header events\n"); | 499 | pr_debug("failed to write perf header events\n"); |
553 | return err; | 500 | return err; |
554 | } | 501 | } |
555 | } | 502 | } |
556 | 503 | ||
557 | self->data_offset = lseek(fd, 0, SEEK_CUR); | 504 | header->data_offset = lseek(fd, 0, SEEK_CUR); |
558 | 505 | ||
559 | if (at_exit) { | 506 | if (at_exit) { |
560 | err = perf_header__adds_write(self, fd); | 507 | err = perf_header__adds_write(header, evlist, fd); |
561 | if (err < 0) | 508 | if (err < 0) |
562 | return err; | 509 | return err; |
563 | } | 510 | } |
@@ -567,20 +514,20 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit) | |||
567 | .size = sizeof(f_header), | 514 | .size = sizeof(f_header), |
568 | .attr_size = sizeof(f_attr), | 515 | .attr_size = sizeof(f_attr), |
569 | .attrs = { | 516 | .attrs = { |
570 | .offset = self->attr_offset, | 517 | .offset = header->attr_offset, |
571 | .size = self->attrs * sizeof(f_attr), | 518 | .size = evlist->nr_entries * sizeof(f_attr), |
572 | }, | 519 | }, |
573 | .data = { | 520 | .data = { |
574 | .offset = self->data_offset, | 521 | .offset = header->data_offset, |
575 | .size = self->data_size, | 522 | .size = header->data_size, |
576 | }, | 523 | }, |
577 | .event_types = { | 524 | .event_types = { |
578 | .offset = self->event_offset, | 525 | .offset = header->event_offset, |
579 | .size = self->event_size, | 526 | .size = header->event_size, |
580 | }, | 527 | }, |
581 | }; | 528 | }; |
582 | 529 | ||
583 | memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features)); | 530 | memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features)); |
584 | 531 | ||
585 | lseek(fd, 0, SEEK_SET); | 532 | lseek(fd, 0, SEEK_SET); |
586 | err = do_write(fd, &f_header, sizeof(f_header)); | 533 | err = do_write(fd, &f_header, sizeof(f_header)); |
@@ -588,26 +535,26 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit) | |||
588 | pr_debug("failed to write perf header\n"); | 535 | pr_debug("failed to write perf header\n"); |
589 | return err; | 536 | return err; |
590 | } | 537 | } |
591 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); | 538 | lseek(fd, header->data_offset + header->data_size, SEEK_SET); |
592 | 539 | ||
593 | self->frozen = 1; | 540 | header->frozen = 1; |
594 | return 0; | 541 | return 0; |
595 | } | 542 | } |
596 | 543 | ||
597 | static int perf_header__getbuffer64(struct perf_header *self, | 544 | static int perf_header__getbuffer64(struct perf_header *header, |
598 | int fd, void *buf, size_t size) | 545 | int fd, void *buf, size_t size) |
599 | { | 546 | { |
600 | if (do_read(fd, buf, size) <= 0) | 547 | if (readn(fd, buf, size) <= 0) |
601 | return -1; | 548 | return -1; |
602 | 549 | ||
603 | if (self->needs_swap) | 550 | if (header->needs_swap) |
604 | mem_bswap_64(buf, size); | 551 | mem_bswap_64(buf, size); |
605 | 552 | ||
606 | return 0; | 553 | return 0; |
607 | } | 554 | } |
608 | 555 | ||
609 | int perf_header__process_sections(struct perf_header *self, int fd, | 556 | int perf_header__process_sections(struct perf_header *header, int fd, |
610 | int (*process)(struct perf_file_section *self, | 557 | int (*process)(struct perf_file_section *section, |
611 | struct perf_header *ph, | 558 | struct perf_header *ph, |
612 | int feat, int fd)) | 559 | int feat, int fd)) |
613 | { | 560 | { |
@@ -617,7 +564,7 @@ int perf_header__process_sections(struct perf_header *self, int fd, | |||
617 | int idx = 0; | 564 | int idx = 0; |
618 | int err = -1, feat = 1; | 565 | int err = -1, feat = 1; |
619 | 566 | ||
620 | nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); | 567 | nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); |
621 | if (!nr_sections) | 568 | if (!nr_sections) |
622 | return 0; | 569 | return 0; |
623 | 570 | ||
@@ -627,17 +574,17 @@ int perf_header__process_sections(struct perf_header *self, int fd, | |||
627 | 574 | ||
628 | sec_size = sizeof(*feat_sec) * nr_sections; | 575 | sec_size = sizeof(*feat_sec) * nr_sections; |
629 | 576 | ||
630 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); | 577 | lseek(fd, header->data_offset + header->data_size, SEEK_SET); |
631 | 578 | ||
632 | if (perf_header__getbuffer64(self, fd, feat_sec, sec_size)) | 579 | if (perf_header__getbuffer64(header, fd, feat_sec, sec_size)) |
633 | goto out_free; | 580 | goto out_free; |
634 | 581 | ||
635 | err = 0; | 582 | err = 0; |
636 | while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { | 583 | while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { |
637 | if (perf_header__has_feat(self, feat)) { | 584 | if (perf_header__has_feat(header, feat)) { |
638 | struct perf_file_section *sec = &feat_sec[idx++]; | 585 | struct perf_file_section *sec = &feat_sec[idx++]; |
639 | 586 | ||
640 | err = process(sec, self, feat, fd); | 587 | err = process(sec, header, feat, fd); |
641 | if (err < 0) | 588 | if (err < 0) |
642 | break; | 589 | break; |
643 | } | 590 | } |
@@ -648,35 +595,35 @@ out_free: | |||
648 | return err; | 595 | return err; |
649 | } | 596 | } |
650 | 597 | ||
651 | int perf_file_header__read(struct perf_file_header *self, | 598 | int perf_file_header__read(struct perf_file_header *header, |
652 | struct perf_header *ph, int fd) | 599 | struct perf_header *ph, int fd) |
653 | { | 600 | { |
654 | lseek(fd, 0, SEEK_SET); | 601 | lseek(fd, 0, SEEK_SET); |
655 | 602 | ||
656 | if (do_read(fd, self, sizeof(*self)) <= 0 || | 603 | if (readn(fd, header, sizeof(*header)) <= 0 || |
657 | memcmp(&self->magic, __perf_magic, sizeof(self->magic))) | 604 | memcmp(&header->magic, __perf_magic, sizeof(header->magic))) |
658 | return -1; | 605 | return -1; |
659 | 606 | ||
660 | if (self->attr_size != sizeof(struct perf_file_attr)) { | 607 | if (header->attr_size != sizeof(struct perf_file_attr)) { |
661 | u64 attr_size = bswap_64(self->attr_size); | 608 | u64 attr_size = bswap_64(header->attr_size); |
662 | 609 | ||
663 | if (attr_size != sizeof(struct perf_file_attr)) | 610 | if (attr_size != sizeof(struct perf_file_attr)) |
664 | return -1; | 611 | return -1; |
665 | 612 | ||
666 | mem_bswap_64(self, offsetof(struct perf_file_header, | 613 | mem_bswap_64(header, offsetof(struct perf_file_header, |
667 | adds_features)); | 614 | adds_features)); |
668 | ph->needs_swap = true; | 615 | ph->needs_swap = true; |
669 | } | 616 | } |
670 | 617 | ||
671 | if (self->size != sizeof(*self)) { | 618 | if (header->size != sizeof(*header)) { |
672 | /* Support the previous format */ | 619 | /* Support the previous format */ |
673 | if (self->size == offsetof(typeof(*self), adds_features)) | 620 | if (header->size == offsetof(typeof(*header), adds_features)) |
674 | bitmap_zero(self->adds_features, HEADER_FEAT_BITS); | 621 | bitmap_zero(header->adds_features, HEADER_FEAT_BITS); |
675 | else | 622 | else |
676 | return -1; | 623 | return -1; |
677 | } | 624 | } |
678 | 625 | ||
679 | memcpy(&ph->adds_features, &self->adds_features, | 626 | memcpy(&ph->adds_features, &header->adds_features, |
680 | sizeof(ph->adds_features)); | 627 | sizeof(ph->adds_features)); |
681 | /* | 628 | /* |
682 | * FIXME: hack that assumes that if we need swap the perf.data file | 629 | * FIXME: hack that assumes that if we need swap the perf.data file |
@@ -690,10 +637,10 @@ int perf_file_header__read(struct perf_file_header *self, | |||
690 | perf_header__set_feat(ph, HEADER_BUILD_ID); | 637 | perf_header__set_feat(ph, HEADER_BUILD_ID); |
691 | } | 638 | } |
692 | 639 | ||
693 | ph->event_offset = self->event_types.offset; | 640 | ph->event_offset = header->event_types.offset; |
694 | ph->event_size = self->event_types.size; | 641 | ph->event_size = header->event_types.size; |
695 | ph->data_offset = self->data.offset; | 642 | ph->data_offset = header->data.offset; |
696 | ph->data_size = self->data.size; | 643 | ph->data_size = header->data.size; |
697 | return 0; | 644 | return 0; |
698 | } | 645 | } |
699 | 646 | ||
@@ -752,14 +699,50 @@ out: | |||
752 | return err; | 699 | return err; |
753 | } | 700 | } |
754 | 701 | ||
755 | static int perf_header__read_build_ids(struct perf_header *self, | 702 | static int perf_header__read_build_ids_abi_quirk(struct perf_header *header, |
756 | int input, u64 offset, u64 size) | 703 | int input, u64 offset, u64 size) |
757 | { | 704 | { |
758 | struct perf_session *session = container_of(self, | 705 | struct perf_session *session = container_of(header, struct perf_session, header); |
759 | struct perf_session, header); | 706 | struct { |
707 | struct perf_event_header header; | ||
708 | u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))]; | ||
709 | char filename[0]; | ||
710 | } old_bev; | ||
760 | struct build_id_event bev; | 711 | struct build_id_event bev; |
761 | char filename[PATH_MAX]; | 712 | char filename[PATH_MAX]; |
762 | u64 limit = offset + size; | 713 | u64 limit = offset + size; |
714 | |||
715 | while (offset < limit) { | ||
716 | ssize_t len; | ||
717 | |||
718 | if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) | ||
719 | return -1; | ||
720 | |||
721 | if (header->needs_swap) | ||
722 | perf_event_header__bswap(&old_bev.header); | ||
723 | |||
724 | len = old_bev.header.size - sizeof(old_bev); | ||
725 | if (read(input, filename, len) != len) | ||
726 | return -1; | ||
727 | |||
728 | bev.header = old_bev.header; | ||
729 | bev.pid = 0; | ||
730 | memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); | ||
731 | __event_process_build_id(&bev, filename, session); | ||
732 | |||
733 | offset += bev.header.size; | ||
734 | } | ||
735 | |||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | static int perf_header__read_build_ids(struct perf_header *header, | ||
740 | int input, u64 offset, u64 size) | ||
741 | { | ||
742 | struct perf_session *session = container_of(header, struct perf_session, header); | ||
743 | struct build_id_event bev; | ||
744 | char filename[PATH_MAX]; | ||
745 | u64 limit = offset + size, orig_offset = offset; | ||
763 | int err = -1; | 746 | int err = -1; |
764 | 747 | ||
765 | while (offset < limit) { | 748 | while (offset < limit) { |
@@ -768,12 +751,30 @@ static int perf_header__read_build_ids(struct perf_header *self, | |||
768 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) | 751 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) |
769 | goto out; | 752 | goto out; |
770 | 753 | ||
771 | if (self->needs_swap) | 754 | if (header->needs_swap) |
772 | perf_event_header__bswap(&bev.header); | 755 | perf_event_header__bswap(&bev.header); |
773 | 756 | ||
774 | len = bev.header.size - sizeof(bev); | 757 | len = bev.header.size - sizeof(bev); |
775 | if (read(input, filename, len) != len) | 758 | if (read(input, filename, len) != len) |
776 | goto out; | 759 | goto out; |
760 | /* | ||
761 | * The a1645ce1 changeset: | ||
762 | * | ||
763 | * "perf: 'perf kvm' tool for monitoring guest performance from host" | ||
764 | * | ||
765 | * Added a field to struct build_id_event that broke the file | ||
766 | * format. | ||
767 | * | ||
768 | * Since the kernel build-id is the first entry, process the | ||
769 | * table using the old format if the well known | ||
770 | * '[kernel.kallsyms]' string for the kernel build-id has the | ||
771 | * first 4 characters chopped off (where the pid_t sits). | ||
772 | */ | ||
773 | if (memcmp(filename, "nel.kallsyms]", 13) == 0) { | ||
774 | if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1) | ||
775 | return -1; | ||
776 | return perf_header__read_build_ids_abi_quirk(header, input, offset, size); | ||
777 | } | ||
777 | 778 | ||
778 | __event_process_build_id(&bev, filename, session); | 779 | __event_process_build_id(&bev, filename, session); |
779 | 780 | ||
@@ -784,13 +785,13 @@ out: | |||
784 | return err; | 785 | return err; |
785 | } | 786 | } |
786 | 787 | ||
787 | static int perf_file_section__process(struct perf_file_section *self, | 788 | static int perf_file_section__process(struct perf_file_section *section, |
788 | struct perf_header *ph, | 789 | struct perf_header *ph, |
789 | int feat, int fd) | 790 | int feat, int fd) |
790 | { | 791 | { |
791 | if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) { | 792 | if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { |
792 | pr_debug("Failed to lseek to %Ld offset for feature %d, " | 793 | pr_debug("Failed to lseek to %" PRIu64 " offset for feature " |
793 | "continuing...\n", self->offset, feat); | 794 | "%d, continuing...\n", section->offset, feat); |
794 | return 0; | 795 | return 0; |
795 | } | 796 | } |
796 | 797 | ||
@@ -800,7 +801,7 @@ static int perf_file_section__process(struct perf_file_section *self, | |||
800 | break; | 801 | break; |
801 | 802 | ||
802 | case HEADER_BUILD_ID: | 803 | case HEADER_BUILD_ID: |
803 | if (perf_header__read_build_ids(ph, fd, self->offset, self->size)) | 804 | if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) |
804 | pr_debug("Failed to read buildids, continuing...\n"); | 805 | pr_debug("Failed to read buildids, continuing...\n"); |
805 | break; | 806 | break; |
806 | default: | 807 | default: |
@@ -810,21 +811,21 @@ static int perf_file_section__process(struct perf_file_section *self, | |||
810 | return 0; | 811 | return 0; |
811 | } | 812 | } |
812 | 813 | ||
813 | static int perf_file_header__read_pipe(struct perf_pipe_file_header *self, | 814 | static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, |
814 | struct perf_header *ph, int fd, | 815 | struct perf_header *ph, int fd, |
815 | bool repipe) | 816 | bool repipe) |
816 | { | 817 | { |
817 | if (do_read(fd, self, sizeof(*self)) <= 0 || | 818 | if (readn(fd, header, sizeof(*header)) <= 0 || |
818 | memcmp(&self->magic, __perf_magic, sizeof(self->magic))) | 819 | memcmp(&header->magic, __perf_magic, sizeof(header->magic))) |
819 | return -1; | 820 | return -1; |
820 | 821 | ||
821 | if (repipe && do_write(STDOUT_FILENO, self, sizeof(*self)) < 0) | 822 | if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0) |
822 | return -1; | 823 | return -1; |
823 | 824 | ||
824 | if (self->size != sizeof(*self)) { | 825 | if (header->size != sizeof(*header)) { |
825 | u64 size = bswap_64(self->size); | 826 | u64 size = bswap_64(header->size); |
826 | 827 | ||
827 | if (size != sizeof(*self)) | 828 | if (size != sizeof(*header)) |
828 | return -1; | 829 | return -1; |
829 | 830 | ||
830 | ph->needs_swap = true; | 831 | ph->needs_swap = true; |
@@ -835,10 +836,10 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *self, | |||
835 | 836 | ||
836 | static int perf_header__read_pipe(struct perf_session *session, int fd) | 837 | static int perf_header__read_pipe(struct perf_session *session, int fd) |
837 | { | 838 | { |
838 | struct perf_header *self = &session->header; | 839 | struct perf_header *header = &session->header; |
839 | struct perf_pipe_file_header f_header; | 840 | struct perf_pipe_file_header f_header; |
840 | 841 | ||
841 | if (perf_file_header__read_pipe(&f_header, self, fd, | 842 | if (perf_file_header__read_pipe(&f_header, header, fd, |
842 | session->repipe) < 0) { | 843 | session->repipe) < 0) { |
843 | pr_debug("incompatible file format\n"); | 844 | pr_debug("incompatible file format\n"); |
844 | return -EINVAL; | 845 | return -EINVAL; |
@@ -849,18 +850,22 @@ static int perf_header__read_pipe(struct perf_session *session, int fd) | |||
849 | return 0; | 850 | return 0; |
850 | } | 851 | } |
851 | 852 | ||
852 | int perf_header__read(struct perf_session *session, int fd) | 853 | int perf_session__read_header(struct perf_session *session, int fd) |
853 | { | 854 | { |
854 | struct perf_header *self = &session->header; | 855 | struct perf_header *header = &session->header; |
855 | struct perf_file_header f_header; | 856 | struct perf_file_header f_header; |
856 | struct perf_file_attr f_attr; | 857 | struct perf_file_attr f_attr; |
857 | u64 f_id; | 858 | u64 f_id; |
858 | int nr_attrs, nr_ids, i, j; | 859 | int nr_attrs, nr_ids, i, j; |
859 | 860 | ||
861 | session->evlist = perf_evlist__new(NULL, NULL); | ||
862 | if (session->evlist == NULL) | ||
863 | return -ENOMEM; | ||
864 | |||
860 | if (session->fd_pipe) | 865 | if (session->fd_pipe) |
861 | return perf_header__read_pipe(session, fd); | 866 | return perf_header__read_pipe(session, fd); |
862 | 867 | ||
863 | if (perf_file_header__read(&f_header, self, fd) < 0) { | 868 | if (perf_file_header__read(&f_header, header, fd) < 0) { |
864 | pr_debug("incompatible file format\n"); | 869 | pr_debug("incompatible file format\n"); |
865 | return -EINVAL; | 870 | return -EINVAL; |
866 | } | 871 | } |
@@ -869,33 +874,39 @@ int perf_header__read(struct perf_session *session, int fd) | |||
869 | lseek(fd, f_header.attrs.offset, SEEK_SET); | 874 | lseek(fd, f_header.attrs.offset, SEEK_SET); |
870 | 875 | ||
871 | for (i = 0; i < nr_attrs; i++) { | 876 | for (i = 0; i < nr_attrs; i++) { |
872 | struct perf_header_attr *attr; | 877 | struct perf_evsel *evsel; |
873 | off_t tmp; | 878 | off_t tmp; |
874 | 879 | ||
875 | if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr))) | 880 | if (perf_header__getbuffer64(header, fd, &f_attr, sizeof(f_attr))) |
876 | goto out_errno; | 881 | goto out_errno; |
877 | 882 | ||
878 | tmp = lseek(fd, 0, SEEK_CUR); | 883 | tmp = lseek(fd, 0, SEEK_CUR); |
884 | evsel = perf_evsel__new(&f_attr.attr, i); | ||
879 | 885 | ||
880 | attr = perf_header_attr__new(&f_attr.attr); | 886 | if (evsel == NULL) |
881 | if (attr == NULL) | 887 | goto out_delete_evlist; |
882 | return -ENOMEM; | 888 | /* |
889 | * Do it before so that if perf_evsel__alloc_id fails, this | ||
890 | * entry gets purged too at perf_evlist__delete(). | ||
891 | */ | ||
892 | perf_evlist__add(session->evlist, evsel); | ||
883 | 893 | ||
884 | nr_ids = f_attr.ids.size / sizeof(u64); | 894 | nr_ids = f_attr.ids.size / sizeof(u64); |
895 | /* | ||
896 | * We don't have the cpu and thread maps on the header, so | ||
897 | * for allocating the perf_sample_id table we fake 1 cpu and | ||
898 | * hattr->ids threads. | ||
899 | */ | ||
900 | if (perf_evsel__alloc_id(evsel, 1, nr_ids)) | ||
901 | goto out_delete_evlist; | ||
902 | |||
885 | lseek(fd, f_attr.ids.offset, SEEK_SET); | 903 | lseek(fd, f_attr.ids.offset, SEEK_SET); |
886 | 904 | ||
887 | for (j = 0; j < nr_ids; j++) { | 905 | for (j = 0; j < nr_ids; j++) { |
888 | if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id))) | 906 | if (perf_header__getbuffer64(header, fd, &f_id, sizeof(f_id))) |
889 | goto out_errno; | 907 | goto out_errno; |
890 | 908 | ||
891 | if (perf_header_attr__add_id(attr, f_id) < 0) { | 909 | perf_evlist__id_add(session->evlist, evsel, 0, j, f_id); |
892 | perf_header_attr__delete(attr); | ||
893 | return -ENOMEM; | ||
894 | } | ||
895 | } | ||
896 | if (perf_header__add_attr(self, attr) < 0) { | ||
897 | perf_header_attr__delete(attr); | ||
898 | return -ENOMEM; | ||
899 | } | 910 | } |
900 | 911 | ||
901 | lseek(fd, tmp, SEEK_SET); | 912 | lseek(fd, tmp, SEEK_SET); |
@@ -906,70 +917,32 @@ int perf_header__read(struct perf_session *session, int fd) | |||
906 | events = malloc(f_header.event_types.size); | 917 | events = malloc(f_header.event_types.size); |
907 | if (events == NULL) | 918 | if (events == NULL) |
908 | return -ENOMEM; | 919 | return -ENOMEM; |
909 | if (perf_header__getbuffer64(self, fd, events, | 920 | if (perf_header__getbuffer64(header, fd, events, |
910 | f_header.event_types.size)) | 921 | f_header.event_types.size)) |
911 | goto out_errno; | 922 | goto out_errno; |
912 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); | 923 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); |
913 | } | 924 | } |
914 | 925 | ||
915 | perf_header__process_sections(self, fd, perf_file_section__process); | 926 | perf_header__process_sections(header, fd, perf_file_section__process); |
916 | 927 | ||
917 | lseek(fd, self->data_offset, SEEK_SET); | 928 | lseek(fd, header->data_offset, SEEK_SET); |
918 | 929 | ||
919 | self->frozen = 1; | 930 | header->frozen = 1; |
920 | return 0; | 931 | return 0; |
921 | out_errno: | 932 | out_errno: |
922 | return -errno; | 933 | return -errno; |
923 | } | ||
924 | |||
925 | u64 perf_header__sample_type(struct perf_header *header) | ||
926 | { | ||
927 | u64 type = 0; | ||
928 | int i; | ||
929 | |||
930 | for (i = 0; i < header->attrs; i++) { | ||
931 | struct perf_header_attr *attr = header->attr[i]; | ||
932 | |||
933 | if (!type) | ||
934 | type = attr->attr.sample_type; | ||
935 | else if (type != attr->attr.sample_type) | ||
936 | die("non matching sample_type"); | ||
937 | } | ||
938 | |||
939 | return type; | ||
940 | } | ||
941 | |||
942 | struct perf_event_attr * | ||
943 | perf_header__find_attr(u64 id, struct perf_header *header) | ||
944 | { | ||
945 | int i; | ||
946 | |||
947 | /* | ||
948 | * We set id to -1 if the data file doesn't contain sample | ||
949 | * ids. Check for this and avoid walking through the entire | ||
950 | * list of ids which may be large. | ||
951 | */ | ||
952 | if (id == -1ULL) | ||
953 | return NULL; | ||
954 | |||
955 | for (i = 0; i < header->attrs; i++) { | ||
956 | struct perf_header_attr *attr = header->attr[i]; | ||
957 | int j; | ||
958 | |||
959 | for (j = 0; j < attr->ids; j++) { | ||
960 | if (attr->id[j] == id) | ||
961 | return &attr->attr; | ||
962 | } | ||
963 | } | ||
964 | 934 | ||
965 | return NULL; | 935 | out_delete_evlist: |
936 | perf_evlist__delete(session->evlist); | ||
937 | session->evlist = NULL; | ||
938 | return -ENOMEM; | ||
966 | } | 939 | } |
967 | 940 | ||
968 | int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, | 941 | int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, |
969 | event__handler_t process, | 942 | perf_event__handler_t process, |
970 | struct perf_session *session) | 943 | struct perf_session *session) |
971 | { | 944 | { |
972 | event_t *ev; | 945 | union perf_event *ev; |
973 | size_t size; | 946 | size_t size; |
974 | int err; | 947 | int err; |
975 | 948 | ||
@@ -980,31 +953,31 @@ int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, | |||
980 | 953 | ||
981 | ev = malloc(size); | 954 | ev = malloc(size); |
982 | 955 | ||
956 | if (ev == NULL) | ||
957 | return -ENOMEM; | ||
958 | |||
983 | ev->attr.attr = *attr; | 959 | ev->attr.attr = *attr; |
984 | memcpy(ev->attr.id, id, ids * sizeof(u64)); | 960 | memcpy(ev->attr.id, id, ids * sizeof(u64)); |
985 | 961 | ||
986 | ev->attr.header.type = PERF_RECORD_HEADER_ATTR; | 962 | ev->attr.header.type = PERF_RECORD_HEADER_ATTR; |
987 | ev->attr.header.size = size; | 963 | ev->attr.header.size = size; |
988 | 964 | ||
989 | err = process(ev, session); | 965 | err = process(ev, NULL, session); |
990 | 966 | ||
991 | free(ev); | 967 | free(ev); |
992 | 968 | ||
993 | return err; | 969 | return err; |
994 | } | 970 | } |
995 | 971 | ||
996 | int event__synthesize_attrs(struct perf_header *self, | 972 | int perf_session__synthesize_attrs(struct perf_session *session, |
997 | event__handler_t process, | 973 | perf_event__handler_t process) |
998 | struct perf_session *session) | ||
999 | { | 974 | { |
1000 | struct perf_header_attr *attr; | 975 | struct perf_evsel *attr; |
1001 | int i, err = 0; | 976 | int err = 0; |
1002 | |||
1003 | for (i = 0; i < self->attrs; i++) { | ||
1004 | attr = self->attr[i]; | ||
1005 | 977 | ||
1006 | err = event__synthesize_attr(&attr->attr, attr->ids, attr->id, | 978 | list_for_each_entry(attr, &session->evlist->entries, node) { |
1007 | process, session); | 979 | err = perf_event__synthesize_attr(&attr->attr, attr->ids, |
980 | attr->id, process, session); | ||
1008 | if (err) { | 981 | if (err) { |
1009 | pr_debug("failed to create perf header attribute\n"); | 982 | pr_debug("failed to create perf header attribute\n"); |
1010 | return err; | 983 | return err; |
@@ -1014,29 +987,39 @@ int event__synthesize_attrs(struct perf_header *self, | |||
1014 | return err; | 987 | return err; |
1015 | } | 988 | } |
1016 | 989 | ||
1017 | int event__process_attr(event_t *self, struct perf_session *session) | 990 | int perf_event__process_attr(union perf_event *event, |
991 | struct perf_session *session) | ||
1018 | { | 992 | { |
1019 | struct perf_header_attr *attr; | ||
1020 | unsigned int i, ids, n_ids; | 993 | unsigned int i, ids, n_ids; |
994 | struct perf_evsel *evsel; | ||
995 | |||
996 | if (session->evlist == NULL) { | ||
997 | session->evlist = perf_evlist__new(NULL, NULL); | ||
998 | if (session->evlist == NULL) | ||
999 | return -ENOMEM; | ||
1000 | } | ||
1021 | 1001 | ||
1022 | attr = perf_header_attr__new(&self->attr.attr); | 1002 | evsel = perf_evsel__new(&event->attr.attr, |
1023 | if (attr == NULL) | 1003 | session->evlist->nr_entries); |
1004 | if (evsel == NULL) | ||
1024 | return -ENOMEM; | 1005 | return -ENOMEM; |
1025 | 1006 | ||
1026 | ids = self->header.size; | 1007 | perf_evlist__add(session->evlist, evsel); |
1027 | ids -= (void *)&self->attr.id - (void *)self; | 1008 | |
1009 | ids = event->header.size; | ||
1010 | ids -= (void *)&event->attr.id - (void *)event; | ||
1028 | n_ids = ids / sizeof(u64); | 1011 | n_ids = ids / sizeof(u64); |
1012 | /* | ||
1013 | * We don't have the cpu and thread maps on the header, so | ||
1014 | * for allocating the perf_sample_id table we fake 1 cpu and | ||
1015 | * hattr->ids threads. | ||
1016 | */ | ||
1017 | if (perf_evsel__alloc_id(evsel, 1, n_ids)) | ||
1018 | return -ENOMEM; | ||
1029 | 1019 | ||
1030 | for (i = 0; i < n_ids; i++) { | 1020 | for (i = 0; i < n_ids; i++) { |
1031 | if (perf_header_attr__add_id(attr, self->attr.id[i]) < 0) { | 1021 | perf_evlist__id_add(session->evlist, evsel, 0, i, |
1032 | perf_header_attr__delete(attr); | 1022 | event->attr.id[i]); |
1033 | return -ENOMEM; | ||
1034 | } | ||
1035 | } | ||
1036 | |||
1037 | if (perf_header__add_attr(&session->header, attr) < 0) { | ||
1038 | perf_header_attr__delete(attr); | ||
1039 | return -ENOMEM; | ||
1040 | } | 1023 | } |
1041 | 1024 | ||
1042 | perf_session__update_sample_type(session); | 1025 | perf_session__update_sample_type(session); |
@@ -1044,11 +1027,11 @@ int event__process_attr(event_t *self, struct perf_session *session) | |||
1044 | return 0; | 1027 | return 0; |
1045 | } | 1028 | } |
1046 | 1029 | ||
1047 | int event__synthesize_event_type(u64 event_id, char *name, | 1030 | int perf_event__synthesize_event_type(u64 event_id, char *name, |
1048 | event__handler_t process, | 1031 | perf_event__handler_t process, |
1049 | struct perf_session *session) | 1032 | struct perf_session *session) |
1050 | { | 1033 | { |
1051 | event_t ev; | 1034 | union perf_event ev; |
1052 | size_t size = 0; | 1035 | size_t size = 0; |
1053 | int err = 0; | 1036 | int err = 0; |
1054 | 1037 | ||
@@ -1064,13 +1047,13 @@ int event__synthesize_event_type(u64 event_id, char *name, | |||
1064 | ev.event_type.header.size = sizeof(ev.event_type) - | 1047 | ev.event_type.header.size = sizeof(ev.event_type) - |
1065 | (sizeof(ev.event_type.event_type.name) - size); | 1048 | (sizeof(ev.event_type.event_type.name) - size); |
1066 | 1049 | ||
1067 | err = process(&ev, session); | 1050 | err = process(&ev, NULL, session); |
1068 | 1051 | ||
1069 | return err; | 1052 | return err; |
1070 | } | 1053 | } |
1071 | 1054 | ||
1072 | int event__synthesize_event_types(event__handler_t process, | 1055 | int perf_event__synthesize_event_types(perf_event__handler_t process, |
1073 | struct perf_session *session) | 1056 | struct perf_session *session) |
1074 | { | 1057 | { |
1075 | struct perf_trace_event_type *type; | 1058 | struct perf_trace_event_type *type; |
1076 | int i, err = 0; | 1059 | int i, err = 0; |
@@ -1078,8 +1061,9 @@ int event__synthesize_event_types(event__handler_t process, | |||
1078 | for (i = 0; i < event_count; i++) { | 1061 | for (i = 0; i < event_count; i++) { |
1079 | type = &events[i]; | 1062 | type = &events[i]; |
1080 | 1063 | ||
1081 | err = event__synthesize_event_type(type->event_id, type->name, | 1064 | err = perf_event__synthesize_event_type(type->event_id, |
1082 | process, session); | 1065 | type->name, process, |
1066 | session); | ||
1083 | if (err) { | 1067 | if (err) { |
1084 | pr_debug("failed to create perf header event type\n"); | 1068 | pr_debug("failed to create perf header event type\n"); |
1085 | return err; | 1069 | return err; |
@@ -1089,29 +1073,28 @@ int event__synthesize_event_types(event__handler_t process, | |||
1089 | return err; | 1073 | return err; |
1090 | } | 1074 | } |
1091 | 1075 | ||
1092 | int event__process_event_type(event_t *self, | 1076 | int perf_event__process_event_type(union perf_event *event, |
1093 | struct perf_session *session __unused) | 1077 | struct perf_session *session __unused) |
1094 | { | 1078 | { |
1095 | if (perf_header__push_event(self->event_type.event_type.event_id, | 1079 | if (perf_header__push_event(event->event_type.event_type.event_id, |
1096 | self->event_type.event_type.name) < 0) | 1080 | event->event_type.event_type.name) < 0) |
1097 | return -ENOMEM; | 1081 | return -ENOMEM; |
1098 | 1082 | ||
1099 | return 0; | 1083 | return 0; |
1100 | } | 1084 | } |
1101 | 1085 | ||
1102 | int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs, | 1086 | int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, |
1103 | int nb_events, | 1087 | perf_event__handler_t process, |
1104 | event__handler_t process, | ||
1105 | struct perf_session *session __unused) | 1088 | struct perf_session *session __unused) |
1106 | { | 1089 | { |
1107 | event_t ev; | 1090 | union perf_event ev; |
1108 | ssize_t size = 0, aligned_size = 0, padding; | 1091 | ssize_t size = 0, aligned_size = 0, padding; |
1109 | int err = 0; | 1092 | int err __used = 0; |
1110 | 1093 | ||
1111 | memset(&ev, 0, sizeof(ev)); | 1094 | memset(&ev, 0, sizeof(ev)); |
1112 | 1095 | ||
1113 | ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; | 1096 | ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; |
1114 | size = read_tracing_data_size(fd, pattrs, nb_events); | 1097 | size = read_tracing_data_size(fd, &evlist->entries); |
1115 | if (size <= 0) | 1098 | if (size <= 0) |
1116 | return size; | 1099 | return size; |
1117 | aligned_size = ALIGN(size, sizeof(u64)); | 1100 | aligned_size = ALIGN(size, sizeof(u64)); |
@@ -1119,18 +1102,18 @@ int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs, | |||
1119 | ev.tracing_data.header.size = sizeof(ev.tracing_data); | 1102 | ev.tracing_data.header.size = sizeof(ev.tracing_data); |
1120 | ev.tracing_data.size = aligned_size; | 1103 | ev.tracing_data.size = aligned_size; |
1121 | 1104 | ||
1122 | process(&ev, session); | 1105 | process(&ev, NULL, session); |
1123 | 1106 | ||
1124 | err = read_tracing_data(fd, pattrs, nb_events); | 1107 | err = read_tracing_data(fd, &evlist->entries); |
1125 | write_padded(fd, NULL, 0, padding); | 1108 | write_padded(fd, NULL, 0, padding); |
1126 | 1109 | ||
1127 | return aligned_size; | 1110 | return aligned_size; |
1128 | } | 1111 | } |
1129 | 1112 | ||
1130 | int event__process_tracing_data(event_t *self, | 1113 | int perf_event__process_tracing_data(union perf_event *event, |
1131 | struct perf_session *session) | 1114 | struct perf_session *session) |
1132 | { | 1115 | { |
1133 | ssize_t size_read, padding, size = self->tracing_data.size; | 1116 | ssize_t size_read, padding, size = event->tracing_data.size; |
1134 | off_t offset = lseek(session->fd, 0, SEEK_CUR); | 1117 | off_t offset = lseek(session->fd, 0, SEEK_CUR); |
1135 | char buf[BUFSIZ]; | 1118 | char buf[BUFSIZ]; |
1136 | 1119 | ||
@@ -1156,12 +1139,12 @@ int event__process_tracing_data(event_t *self, | |||
1156 | return size_read + padding; | 1139 | return size_read + padding; |
1157 | } | 1140 | } |
1158 | 1141 | ||
1159 | int event__synthesize_build_id(struct dso *pos, u16 misc, | 1142 | int perf_event__synthesize_build_id(struct dso *pos, u16 misc, |
1160 | event__handler_t process, | 1143 | perf_event__handler_t process, |
1161 | struct machine *machine, | 1144 | struct machine *machine, |
1162 | struct perf_session *session) | 1145 | struct perf_session *session) |
1163 | { | 1146 | { |
1164 | event_t ev; | 1147 | union perf_event ev; |
1165 | size_t len; | 1148 | size_t len; |
1166 | int err = 0; | 1149 | int err = 0; |
1167 | 1150 | ||
@@ -1179,16 +1162,16 @@ int event__synthesize_build_id(struct dso *pos, u16 misc, | |||
1179 | ev.build_id.header.size = sizeof(ev.build_id) + len; | 1162 | ev.build_id.header.size = sizeof(ev.build_id) + len; |
1180 | memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); | 1163 | memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); |
1181 | 1164 | ||
1182 | err = process(&ev, session); | 1165 | err = process(&ev, NULL, session); |
1183 | 1166 | ||
1184 | return err; | 1167 | return err; |
1185 | } | 1168 | } |
1186 | 1169 | ||
1187 | int event__process_build_id(event_t *self, | 1170 | int perf_event__process_build_id(union perf_event *event, |
1188 | struct perf_session *session) | 1171 | struct perf_session *session) |
1189 | { | 1172 | { |
1190 | __event_process_build_id(&self->build_id, | 1173 | __event_process_build_id(&event->build_id, |
1191 | self->build_id.filename, | 1174 | event->build_id.filename, |
1192 | session); | 1175 | session); |
1193 | return 0; | 1176 | return 0; |
1194 | } | 1177 | } |