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 if (ret == 0) 189 die("failed to read: missing data"); 190 191 size -= ret; 192 buf += ret; 193 } 194 } 195 196 struct perf_header *perf_header__read(int fd) 197 { 198 struct perf_header *self = perf_header__new(); 199 struct perf_file_header f_header; 200 struct perf_file_attr f_attr; 201 u64 f_id; 202 203 int nr_attrs, nr_ids, i, j; 204 205 lseek(fd, 0, SEEK_SET); 206 do_read(fd, &f_header, sizeof(f_header)); 207 208 if (f_header.magic != PERF_MAGIC || 209 f_header.size != sizeof(f_header) || 210 f_header.attr_size != sizeof(f_attr)) 211 die("incompatible file format"); 212 213 nr_attrs = f_header.attrs.size / sizeof(f_attr); 214 lseek(fd, f_header.attrs.offset, SEEK_SET); 215 216 for (i = 0; i < nr_attrs; i++) { 217 struct perf_header_attr *attr; 218 off_t tmp; 219 220 do_read(fd, &f_attr, sizeof(f_attr)); 221 tmp = lseek(fd, 0, SEEK_CUR); 222 223 attr = perf_header_attr__new(&f_attr.attr); 224 225 nr_ids = f_attr.ids.size / sizeof(u64); 226 lseek(fd, f_attr.ids.offset, SEEK_SET); 227 228 for (j = 0; j < nr_ids; j++) { 229 do_read(fd, &f_id, sizeof(f_id)); 230 231 perf_header_attr__add_id(attr, f_id); 232 } 233 perf_header__add_attr(self, attr); 234 lseek(fd, tmp, SEEK_SET); 235 } 236 237 self->data_offset = f_header.data.offset; 238 self->data_size = f_header.data.size; 239 240 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 241 242 self->frozen = 1; 243 244 return self; 245 } 246