header.c (46557bef3f3834ac33031c7be27d39d90d507442) | header.c (e30a3d12ddf04add3268bfceb0e57ffe47f254c6) |
---|---|
1#include <sys/types.h> 2#include <unistd.h> 3#include <stdio.h> 4#include <stdlib.h> | 1#include <sys/types.h> 2#include <unistd.h> 3#include <stdio.h> 4#include <stdlib.h> |
5#include <linux/list.h> |
|
5 6#include "util.h" 7#include "header.h" | 6 7#include "util.h" 8#include "header.h" |
9#include "../perf.h" 10#include "trace-event.h" 11#include "symbol.h" 12#include "data_map.h" 13#include "debug.h" |
|
8 9/* 10 * Create new perf.data header attribute: 11 */ 12struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr) 13{ 14 struct perf_header_attr *self = malloc(sizeof(*self)); 15 | 14 15/* 16 * Create new perf.data header attribute: 17 */ 18struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr) 19{ 20 struct perf_header_attr *self = malloc(sizeof(*self)); 21 |
16 if (!self) 17 die("nomem"); | 22 if (self != NULL) { 23 self->attr = *attr; 24 self->ids = 0; 25 self->size = 1; 26 self->id = malloc(sizeof(u64)); 27 if (self->id == NULL) { 28 free(self); 29 self = NULL; 30 } 31 } |
18 | 32 |
19 self->attr = *attr; 20 self->ids = 0; 21 self->size = 1; 22 self->id = malloc(sizeof(u64)); 23 24 if (!self->id) 25 die("nomem"); 26 | |
27 return self; 28} 29 | 33 return self; 34} 35 |
30void perf_header_attr__add_id(struct perf_header_attr *self, u64 id) | 36void perf_header_attr__delete(struct perf_header_attr *self) |
31{ | 37{ |
38 free(self->id); 39 free(self); 40} 41 42int perf_header_attr__add_id(struct perf_header_attr *self, u64 id) 43{ |
|
32 int pos = self->ids; 33 34 self->ids++; 35 if (self->ids > self->size) { | 44 int pos = self->ids; 45 46 self->ids++; 47 if (self->ids > self->size) { |
36 self->size *= 2; 37 self->id = realloc(self->id, self->size * sizeof(u64)); 38 if (!self->id) 39 die("nomem"); | 48 int nsize = self->size * 2; 49 u64 *nid = realloc(self->id, nsize * sizeof(u64)); 50 51 if (nid == NULL) 52 return -1; 53 54 self->size = nsize; 55 self->id = nid; |
40 } 41 self->id[pos] = id; | 56 } 57 self->id[pos] = id; |
58 return 0; |
|
42} 43 44/* 45 * Create new perf.data header: 46 */ 47struct perf_header *perf_header__new(void) 48{ | 59} 60 61/* 62 * Create new perf.data header: 63 */ 64struct perf_header *perf_header__new(void) 65{ |
49 struct perf_header *self = malloc(sizeof(*self)); | 66 struct perf_header *self = calloc(sizeof(*self), 1); |
50 | 67 |
51 if (!self) 52 die("nomem"); | 68 if (self != NULL) { 69 self->size = 1; 70 self->attr = malloc(sizeof(void *)); |
53 | 71 |
54 self->frozen = 0; | 72 if (self->attr == NULL) { 73 free(self); 74 self = NULL; 75 } 76 } |
55 | 77 |
56 self->attrs = 0; 57 self->size = 1; 58 self->attr = malloc(sizeof(void *)); 59 60 if (!self->attr) 61 die("nomem"); 62 63 self->data_offset = 0; 64 self->data_size = 0; 65 | |
66 return self; 67} 68 | 78 return self; 79} 80 |
69void perf_header__add_attr(struct perf_header *self, 70 struct perf_header_attr *attr) | 81int perf_header__add_attr(struct perf_header *self, 82 struct perf_header_attr *attr) |
71{ 72 int pos = self->attrs; 73 74 if (self->frozen) | 83{ 84 int pos = self->attrs; 85 86 if (self->frozen) |
75 die("frozen"); | 87 return -1; |
76 77 self->attrs++; 78 if (self->attrs > self->size) { | 88 89 self->attrs++; 90 if (self->attrs > self->size) { |
79 self->size *= 2; 80 self->attr = realloc(self->attr, self->size * sizeof(void *)); 81 if (!self->attr) 82 die("nomem"); | 91 int nsize = self->size * 2; 92 struct perf_header_attr **nattr; 93 94 nattr = realloc(self->attr, nsize * sizeof(void *)); 95 if (nattr == NULL) 96 return -1; 97 98 self->size = nsize; 99 self->attr = nattr; |
83 } 84 self->attr[pos] = attr; | 100 } 101 self->attr[pos] = attr; |
102 return 0; |
|
85} 86 87#define MAX_EVENT_NAME 64 88 89struct perf_trace_event_type { 90 u64 event_id; 91 char name[MAX_EVENT_NAME]; 92}; 93 94static int event_count; 95static struct perf_trace_event_type *events; 96 97void perf_header__push_event(u64 id, const char *name) 98{ 99 if (strlen(name) > MAX_EVENT_NAME) | 103} 104 105#define MAX_EVENT_NAME 64 106 107struct perf_trace_event_type { 108 u64 event_id; 109 char name[MAX_EVENT_NAME]; 110}; 111 112static int event_count; 113static struct perf_trace_event_type *events; 114 115void perf_header__push_event(u64 id, const char *name) 116{ 117 if (strlen(name) > MAX_EVENT_NAME) |
100 printf("Event %s will be truncated\n", name); | 118 pr_warning("Event %s will be truncated\n", name); |
101 102 if (!events) { 103 events = malloc(sizeof(struct perf_trace_event_type)); 104 if (!events) 105 die("nomem"); 106 } else { 107 events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type)); 108 if (!events) --- 14 unchanged lines hidden (view full) --- 123 } 124 return NULL; 125} 126 127static const char *__perf_magic = "PERFFILE"; 128 129#define PERF_MAGIC (*(u64 *)__perf_magic) 130 | 119 120 if (!events) { 121 events = malloc(sizeof(struct perf_trace_event_type)); 122 if (!events) 123 die("nomem"); 124 } else { 125 events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type)); 126 if (!events) --- 14 unchanged lines hidden (view full) --- 141 } 142 return NULL; 143} 144 145static const char *__perf_magic = "PERFFILE"; 146 147#define PERF_MAGIC (*(u64 *)__perf_magic) 148 |
131struct perf_file_section { 132 u64 offset; 133 u64 size; 134}; 135 | |
136struct perf_file_attr { 137 struct perf_event_attr attr; 138 struct perf_file_section ids; 139}; 140 | 149struct perf_file_attr { 150 struct perf_event_attr attr; 151 struct perf_file_section ids; 152}; 153 |
141struct perf_file_header { 142 u64 magic; 143 u64 size; 144 u64 attr_size; 145 struct perf_file_section attrs; 146 struct perf_file_section data; 147 struct perf_file_section event_types; 148}; | 154void perf_header__set_feat(struct perf_header *self, int feat) 155{ 156 set_bit(feat, self->adds_features); 157} |
149 | 158 |
150static void do_write(int fd, void *buf, size_t size) | 159bool perf_header__has_feat(const struct perf_header *self, int feat) |
151{ | 160{ |
161 return test_bit(feat, self->adds_features); 162} 163 164static int do_write(int fd, const void *buf, size_t size) 165{ |
|
152 while (size) { 153 int ret = write(fd, buf, size); 154 155 if (ret < 0) | 166 while (size) { 167 int ret = write(fd, buf, size); 168 169 if (ret < 0) |
156 die("failed to write"); | 170 return -1; |
157 158 size -= ret; 159 buf += ret; 160 } | 171 172 size -= ret; 173 buf += ret; 174 } |
175 176 return 0; |
|
161} 162 | 177} 178 |
163void perf_header__write(struct perf_header *self, int fd) | 179static int dsos__write_buildid_table(int fd) |
164{ | 180{ |
181 struct dso *pos; 182 183 list_for_each_entry(pos, &dsos, node) { 184 struct build_id_event b; 185 size_t len; 186 187 if (!pos->has_build_id) 188 continue; 189 len = pos->long_name_len + 1; 190 len = ALIGN(len, 64); 191 memset(&b, 0, sizeof(b)); 192 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); 193 b.header.size = sizeof(b) + len; 194 if (do_write(fd, &b, sizeof(b)) < 0 || 195 do_write(fd, pos->long_name, len) < 0) 196 return -1; 197 } 198 199 return 0; 200} 201 202static void 203perf_header__adds_write(struct perf_header *self, int fd) 204{ 205 int nr_sections; 206 struct perf_file_section *feat_sec; 207 int sec_size; 208 u64 sec_start; 209 int idx = 0; 210 211 if (dsos__read_build_ids()) 212 perf_header__set_feat(self, HEADER_BUILD_ID); 213 214 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 215 if (!nr_sections) 216 return; 217 218 feat_sec = calloc(sizeof(*feat_sec), nr_sections); 219 if (!feat_sec) 220 die("No memory"); 221 222 sec_size = sizeof(*feat_sec) * nr_sections; 223 224 sec_start = self->data_offset + self->data_size; 225 lseek(fd, sec_start + sec_size, SEEK_SET); 226 227 if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { 228 struct perf_file_section *trace_sec; 229 230 trace_sec = &feat_sec[idx++]; 231 232 /* Write trace info */ 233 trace_sec->offset = lseek(fd, 0, SEEK_CUR); 234 read_tracing_data(fd, attrs, nr_counters); 235 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; 236 } 237 238 239 if (perf_header__has_feat(self, HEADER_BUILD_ID)) { 240 struct perf_file_section *buildid_sec; 241 242 buildid_sec = &feat_sec[idx++]; 243 244 /* Write build-ids */ 245 buildid_sec->offset = lseek(fd, 0, SEEK_CUR); 246 if (dsos__write_buildid_table(fd) < 0) 247 die("failed to write buildid table"); 248 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; 249 } 250 251 lseek(fd, sec_start, SEEK_SET); 252 if (do_write(fd, feat_sec, sec_size) < 0) 253 die("failed to write feature section"); 254 free(feat_sec); 255} 256 257void perf_header__write(struct perf_header *self, int fd, bool at_exit) 258{ |
|
165 struct perf_file_header f_header; 166 struct perf_file_attr f_attr; 167 struct perf_header_attr *attr; 168 int i; 169 170 lseek(fd, sizeof(f_header), SEEK_SET); 171 172 173 for (i = 0; i < self->attrs; i++) { 174 attr = self->attr[i]; 175 176 attr->id_offset = lseek(fd, 0, SEEK_CUR); | 259 struct perf_file_header f_header; 260 struct perf_file_attr f_attr; 261 struct perf_header_attr *attr; 262 int i; 263 264 lseek(fd, sizeof(f_header), SEEK_SET); 265 266 267 for (i = 0; i < self->attrs; i++) { 268 attr = self->attr[i]; 269 270 attr->id_offset = lseek(fd, 0, SEEK_CUR); |
177 do_write(fd, attr->id, attr->ids * sizeof(u64)); | 271 if (do_write(fd, attr->id, attr->ids * sizeof(u64)) < 0) 272 die("failed to write perf header"); |
178 } 179 180 181 self->attr_offset = lseek(fd, 0, SEEK_CUR); 182 183 for (i = 0; i < self->attrs; i++) { 184 attr = self->attr[i]; 185 186 f_attr = (struct perf_file_attr){ 187 .attr = attr->attr, 188 .ids = { 189 .offset = attr->id_offset, 190 .size = attr->ids * sizeof(u64), 191 } 192 }; | 273 } 274 275 276 self->attr_offset = lseek(fd, 0, SEEK_CUR); 277 278 for (i = 0; i < self->attrs; i++) { 279 attr = self->attr[i]; 280 281 f_attr = (struct perf_file_attr){ 282 .attr = attr->attr, 283 .ids = { 284 .offset = attr->id_offset, 285 .size = attr->ids * sizeof(u64), 286 } 287 }; |
193 do_write(fd, &f_attr, sizeof(f_attr)); | 288 if (do_write(fd, &f_attr, sizeof(f_attr)) < 0) 289 die("failed to write perf header attribute"); |
194 } 195 196 self->event_offset = lseek(fd, 0, SEEK_CUR); 197 self->event_size = event_count * sizeof(struct perf_trace_event_type); 198 if (events) | 290 } 291 292 self->event_offset = lseek(fd, 0, SEEK_CUR); 293 self->event_size = event_count * sizeof(struct perf_trace_event_type); 294 if (events) |
199 do_write(fd, events, self->event_size); | 295 if (do_write(fd, events, self->event_size) < 0) 296 die("failed to write perf header events"); |
200 | 297 |
201 | |
202 self->data_offset = lseek(fd, 0, SEEK_CUR); 203 | 298 self->data_offset = lseek(fd, 0, SEEK_CUR); 299 |
300 if (at_exit) 301 perf_header__adds_write(self, fd); 302 |
|
204 f_header = (struct perf_file_header){ 205 .magic = PERF_MAGIC, 206 .size = sizeof(f_header), 207 .attr_size = sizeof(f_attr), 208 .attrs = { 209 .offset = self->attr_offset, 210 .size = self->attrs * sizeof(f_attr), 211 }, 212 .data = { 213 .offset = self->data_offset, 214 .size = self->data_size, 215 }, 216 .event_types = { 217 .offset = self->event_offset, 218 .size = self->event_size, 219 }, 220 }; 221 | 303 f_header = (struct perf_file_header){ 304 .magic = PERF_MAGIC, 305 .size = sizeof(f_header), 306 .attr_size = sizeof(f_attr), 307 .attrs = { 308 .offset = self->attr_offset, 309 .size = self->attrs * sizeof(f_attr), 310 }, 311 .data = { 312 .offset = self->data_offset, 313 .size = self->data_size, 314 }, 315 .event_types = { 316 .offset = self->event_offset, 317 .size = self->event_size, 318 }, 319 }; 320 |
321 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features)); 322 |
|
222 lseek(fd, 0, SEEK_SET); | 323 lseek(fd, 0, SEEK_SET); |
223 do_write(fd, &f_header, sizeof(f_header)); | 324 if (do_write(fd, &f_header, sizeof(f_header)) < 0) 325 die("failed to write perf header"); |
224 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 225 226 self->frozen = 1; 227} 228 229static void do_read(int fd, void *buf, size_t size) 230{ 231 while (size) { --- 4 unchanged lines hidden (view full) --- 236 if (ret == 0) 237 die("failed to read: missing data"); 238 239 size -= ret; 240 buf += ret; 241 } 242} 243 | 326 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 327 328 self->frozen = 1; 329} 330 331static void do_read(int fd, void *buf, size_t size) 332{ 333 while (size) { --- 4 unchanged lines hidden (view full) --- 338 if (ret == 0) 339 die("failed to read: missing data"); 340 341 size -= ret; 342 buf += ret; 343 } 344} 345 |
346int perf_header__process_sections(struct perf_header *self, int fd, 347 int (*process)(struct perf_file_section *self, 348 int feat, int fd)) 349{ 350 struct perf_file_section *feat_sec; 351 int nr_sections; 352 int sec_size; 353 int idx = 0; 354 int err = 0, feat = 1; 355 356 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 357 if (!nr_sections) 358 return 0; 359 360 feat_sec = calloc(sizeof(*feat_sec), nr_sections); 361 if (!feat_sec) 362 return -1; 363 364 sec_size = sizeof(*feat_sec) * nr_sections; 365 366 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 367 368 do_read(fd, feat_sec, sec_size); 369 370 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { 371 if (perf_header__has_feat(self, feat)) { 372 struct perf_file_section *sec = &feat_sec[idx++]; 373 374 err = process(sec, feat, fd); 375 if (err < 0) 376 break; 377 } 378 ++feat; 379 } 380 381 free(feat_sec); 382 return err; 383}; 384 385int perf_file_header__read(struct perf_file_header *self, 386 struct perf_header *ph, int fd) 387{ 388 lseek(fd, 0, SEEK_SET); 389 do_read(fd, self, sizeof(*self)); 390 391 if (self->magic != PERF_MAGIC || 392 self->attr_size != sizeof(struct perf_file_attr)) 393 return -1; 394 395 if (self->size != sizeof(*self)) { 396 /* Support the previous format */ 397 if (self->size == offsetof(typeof(*self), adds_features)) 398 bitmap_zero(self->adds_features, HEADER_FEAT_BITS); 399 else 400 return -1; 401 } 402 403 memcpy(&ph->adds_features, &self->adds_features, 404 sizeof(self->adds_features)); 405 406 ph->event_offset = self->event_types.offset; 407 ph->event_size = self->event_types.size; 408 ph->data_offset = self->data.offset; 409 ph->data_size = self->data.size; 410 return 0; 411} 412 413static int perf_file_section__process(struct perf_file_section *self, 414 int feat, int fd) 415{ 416 if (lseek(fd, self->offset, SEEK_SET) < 0) { 417 pr_debug("Failed to lseek to %Ld offset for feature %d, " 418 "continuing...\n", self->offset, feat); 419 return 0; 420 } 421 422 switch (feat) { 423 case HEADER_TRACE_INFO: 424 trace_report(fd); 425 break; 426 427 case HEADER_BUILD_ID: 428 if (perf_header__read_build_ids(fd, self->offset, self->size)) 429 pr_debug("Failed to read buildids, continuing...\n"); 430 break; 431 default: 432 pr_debug("unknown feature %d, continuing...\n", feat); 433 } 434 435 return 0; 436} 437 |
|
244struct perf_header *perf_header__read(int fd) 245{ 246 struct perf_header *self = perf_header__new(); 247 struct perf_file_header f_header; 248 struct perf_file_attr f_attr; 249 u64 f_id; | 438struct perf_header *perf_header__read(int fd) 439{ 440 struct perf_header *self = perf_header__new(); 441 struct perf_file_header f_header; 442 struct perf_file_attr f_attr; 443 u64 f_id; |
250 | |
251 int nr_attrs, nr_ids, i, j; 252 | 444 int nr_attrs, nr_ids, i, j; 445 |
253 lseek(fd, 0, SEEK_SET); 254 do_read(fd, &f_header, sizeof(f_header)); | 446 if (self == NULL) 447 die("nomem"); |
255 | 448 |
256 if (f_header.magic != PERF_MAGIC || 257 f_header.size != sizeof(f_header) || 258 f_header.attr_size != sizeof(f_attr)) | 449 if (perf_file_header__read(&f_header, self, fd) < 0) |
259 die("incompatible file format"); 260 261 nr_attrs = f_header.attrs.size / sizeof(f_attr); 262 lseek(fd, f_header.attrs.offset, SEEK_SET); 263 264 for (i = 0; i < nr_attrs; i++) { 265 struct perf_header_attr *attr; 266 off_t tmp; 267 268 do_read(fd, &f_attr, sizeof(f_attr)); 269 tmp = lseek(fd, 0, SEEK_CUR); 270 271 attr = perf_header_attr__new(&f_attr.attr); | 450 die("incompatible file format"); 451 452 nr_attrs = f_header.attrs.size / sizeof(f_attr); 453 lseek(fd, f_header.attrs.offset, SEEK_SET); 454 455 for (i = 0; i < nr_attrs; i++) { 456 struct perf_header_attr *attr; 457 off_t tmp; 458 459 do_read(fd, &f_attr, sizeof(f_attr)); 460 tmp = lseek(fd, 0, SEEK_CUR); 461 462 attr = perf_header_attr__new(&f_attr.attr); |
463 if (attr == NULL) 464 die("nomem"); |
|
272 273 nr_ids = f_attr.ids.size / sizeof(u64); 274 lseek(fd, f_attr.ids.offset, SEEK_SET); 275 276 for (j = 0; j < nr_ids; j++) { 277 do_read(fd, &f_id, sizeof(f_id)); 278 | 465 466 nr_ids = f_attr.ids.size / sizeof(u64); 467 lseek(fd, f_attr.ids.offset, SEEK_SET); 468 469 for (j = 0; j < nr_ids; j++) { 470 do_read(fd, &f_id, sizeof(f_id)); 471 |
279 perf_header_attr__add_id(attr, f_id); | 472 if (perf_header_attr__add_id(attr, f_id) < 0) 473 die("nomem"); |
280 } | 474 } |
281 perf_header__add_attr(self, attr); | 475 if (perf_header__add_attr(self, attr) < 0) 476 die("nomem"); 477 |
282 lseek(fd, tmp, SEEK_SET); 283 } 284 285 if (f_header.event_types.size) { 286 lseek(fd, f_header.event_types.offset, SEEK_SET); 287 events = malloc(f_header.event_types.size); 288 if (!events) 289 die("nomem"); 290 do_read(fd, events, f_header.event_types.size); 291 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 292 } | 478 lseek(fd, tmp, SEEK_SET); 479 } 480 481 if (f_header.event_types.size) { 482 lseek(fd, f_header.event_types.offset, SEEK_SET); 483 events = malloc(f_header.event_types.size); 484 if (!events) 485 die("nomem"); 486 do_read(fd, events, f_header.event_types.size); 487 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 488 } |
293 self->event_offset = f_header.event_types.offset; 294 self->event_size = f_header.event_types.size; | |
295 | 489 |
296 self->data_offset = f_header.data.offset; 297 self->data_size = f_header.data.size; | 490 perf_header__process_sections(self, fd, perf_file_section__process); |
298 299 lseek(fd, self->data_offset, SEEK_SET); 300 301 self->frozen = 1; 302 303 return self; 304} 305 --- 34 unchanged lines hidden --- | 491 492 lseek(fd, self->data_offset, SEEK_SET); 493 494 self->frozen = 1; 495 496 return self; 497} 498 --- 34 unchanged lines hidden --- |