Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf tools: Bring linear set of section headers for features

Build a set of section headers for features right after the
datas. Each implemented feature will have one of such section
header that provides the offset and the size of the data
manipulated by the feature.

The trace informations have moved after the data and are
recorded on exit time.

The new layout is as follows:

-----------------------
___
[ magic ] |
[ header size ] |
[ attr size ] |
[ attr content offset ] |
[ attr content size ] |
[ data offset ] File Headers
[ data size ] |
[ event_types offset ] |
[ event_types size ] |
[ feature bitmap ] v

[ attr section ]
[ events section ]

___
[ X ] |
[ X ] |
[ X ] Datas
[ X ] |
[ X ] v

___
[ Feature 1 offset ] |
[ Feature 1 size ] Features headers
[ Feature 2 offset ] |
[ Feature 2 size ] v

[ Feature 1 content ]
[ Feature 2 content ]
-----------------------

We have as many feature's section headers as we have features in
use for the current file.

Say Feat 1 and Feat 3 are used by the file, but not Feat 2. Then
the feature headers will be like follows:

[ Feature 1 offset ] |
[ Feature 1 size ] Features headers
[ Feature 3 offset ] |
[ Feature 3 size ] v

There is no hole to cover Feature 2 that is not in use here. We
only need to cover the needed headers in order, from the lowest
feature bit to the highest.

Currently we have two features: HEADER_TRACE_INFO and
HEADER_BUILD_ID. Both have their contents that follow the
feature headers. Putting the contents right after the feature
headers is not mandatory though. While we keep the feature
headers right after the data and in order, their offsets can
point everywhere. We have just put the two above feature
contents in the end of the file for convenience.

The purpose of this layout change is to have a file format that
scales while keeping it simple: having such linear feature
headers is less error prone wrt forward/backward compatibility
as the content of a feature can be put anywhere, its location
can even change by the time, it's fine because its headers will
tell where it is. And we know how to find these headers,
following the above rules.

Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
LKML-Reference: <1257911467-28276-6-git-send-email-fweisbec@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>

authored by

Frederic Weisbecker and committed by
Ingo Molnar
9e827dd0 3e13ab2d

+86 -46
+4 -7
tools/perf/util/data_map.c
··· 70 70 } 71 71 } 72 72 73 - int perf_header__read_build_ids(const struct perf_header *self, 74 - int input, off_t file_size) 73 + int perf_header__read_build_ids(int input, off_t size) 75 74 { 76 - off_t offset = self->data_offset + self->data_size; 77 75 struct build_id_event bev; 78 76 char filename[PATH_MAX]; 77 + off_t offset = lseek(input, 0, SEEK_CUR); 78 + off_t limit = offset + size; 79 79 int err = -1; 80 80 81 - if (lseek(input, offset, SEEK_SET) < 0) 82 - return -1; 83 - 84 - while (offset < file_size) { 81 + while (offset < limit) { 85 82 struct dso *dso; 86 83 ssize_t len; 87 84
+1 -2
tools/perf/util/data_map.h
··· 27 27 int full_paths, 28 28 int *cwdlen, 29 29 char **cwd); 30 - int perf_header__read_build_ids(const struct perf_header *self, 31 - int input, off_t file_size); 30 + int perf_header__read_build_ids(int input, off_t file_size); 32 31 33 32 #endif
+76 -36
tools/perf/util/header.c
··· 186 186 } 187 187 188 188 static void 189 - perf_header__adds_write(struct perf_header *self, int fd, bool at_exit) 189 + perf_header__adds_write(struct perf_header *self, int fd) 190 190 { 191 - struct perf_file_section trace_sec; 192 - u64 cur_offset = lseek(fd, 0, SEEK_CUR); 191 + LIST_HEAD(id_list); 192 + int nr_sections; 193 + struct perf_file_section *feat_sec; 194 + int sec_size; 195 + u64 sec_start; 196 + int idx = 0; 197 + 198 + if (fetch_build_id_table(&id_list)) 199 + perf_header__set_feat(self, HEADER_BUILD_ID); 200 + 201 + nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 202 + if (!nr_sections) 203 + return; 204 + 205 + feat_sec = calloc(sizeof(*feat_sec), nr_sections); 206 + if (!feat_sec) 207 + die("No memory"); 208 + 209 + sec_size = sizeof(*feat_sec) * nr_sections; 210 + 211 + sec_start = self->data_offset + self->data_size; 212 + lseek(fd, sec_start + sec_size, SEEK_SET); 193 213 194 214 if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { 215 + struct perf_file_section *trace_sec; 216 + 217 + trace_sec = &feat_sec[idx++]; 218 + 195 219 /* Write trace info */ 196 - trace_sec.offset = lseek(fd, sizeof(trace_sec), SEEK_CUR); 220 + trace_sec->offset = lseek(fd, 0, SEEK_CUR); 197 221 read_tracing_data(fd, attrs, nr_counters); 198 - trace_sec.size = lseek(fd, 0, SEEK_CUR) - trace_sec.offset; 199 - 200 - /* Write trace info headers */ 201 - lseek(fd, cur_offset, SEEK_SET); 202 - do_write(fd, &trace_sec, sizeof(trace_sec)); 203 - 204 - /* 205 - * Update cur_offset. So that other (future) 206 - * features can set their own infos in this place. But if we are 207 - * the only feature, at least that seeks to the place the data 208 - * should begin. 209 - */ 210 - cur_offset = lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); 222 + trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; 211 223 } 212 224 213 - if (at_exit) { 214 - LIST_HEAD(id_list); 215 225 216 - if (fetch_build_id_table(&id_list)) { 217 - lseek(fd, self->data_offset + self->data_size, SEEK_SET); 218 - perf_header__set_feat(self, HEADER_BUILD_ID); 219 - write_buildid_table(fd, &id_list); 220 - lseek(fd, cur_offset, SEEK_SET); 221 - } 226 + if (perf_header__has_feat(self, HEADER_BUILD_ID)) { 227 + struct perf_file_section *buildid_sec; 228 + 229 + buildid_sec = &feat_sec[idx++]; 230 + 231 + /* Write build-ids */ 232 + buildid_sec->offset = lseek(fd, 0, SEEK_CUR); 233 + write_buildid_table(fd, &id_list); 234 + buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; 222 235 } 223 - }; 236 + 237 + lseek(fd, sec_start, SEEK_SET); 238 + do_write(fd, feat_sec, sec_size); 239 + free(feat_sec); 240 + } 224 241 225 242 void perf_header__write(struct perf_header *self, int fd, bool at_exit) 226 243 { ··· 277 260 if (events) 278 261 do_write(fd, events, self->event_size); 279 262 280 - perf_header__adds_write(self, fd, at_exit); 281 - 282 263 self->data_offset = lseek(fd, 0, SEEK_CUR); 264 + 265 + if (at_exit) 266 + perf_header__adds_write(self, fd); 283 267 284 268 f_header = (struct perf_file_header){ 285 269 .magic = PERF_MAGIC, ··· 326 308 327 309 static void perf_header__adds_read(struct perf_header *self, int fd) 328 310 { 329 - if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { 330 - struct perf_file_section trace_sec; 311 + struct perf_file_section *feat_sec; 312 + int nr_sections; 313 + int sec_size; 314 + int idx = 0; 331 315 332 - do_read(fd, &trace_sec, sizeof(trace_sec)); 333 - lseek(fd, trace_sec.offset, SEEK_SET); 316 + 317 + nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 318 + if (!nr_sections) 319 + return; 320 + 321 + feat_sec = calloc(sizeof(*feat_sec), nr_sections); 322 + if (!feat_sec) 323 + die("No memory"); 324 + 325 + sec_size = sizeof(*feat_sec) * nr_sections; 326 + 327 + lseek(fd, self->data_offset + self->data_size, SEEK_SET); 328 + 329 + do_read(fd, feat_sec, sec_size); 330 + 331 + if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { 332 + struct perf_file_section *trace_sec; 333 + 334 + trace_sec = &feat_sec[idx++]; 335 + lseek(fd, trace_sec->offset, SEEK_SET); 334 336 trace_report(fd); 335 - lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); 336 337 } 337 338 338 339 if (perf_header__has_feat(self, HEADER_BUILD_ID)) { 339 - struct stat input_stat; 340 + struct perf_file_section *buildid_sec; 340 341 341 - fstat(fd, &input_stat); 342 - if (perf_header__read_build_ids(self, fd, input_stat.st_size)) 342 + buildid_sec = &feat_sec[idx++]; 343 + lseek(fd, buildid_sec->offset, SEEK_SET); 344 + if (perf_header__read_build_ids(fd, buildid_sec->size)) 343 345 pr_debug("failed to read buildids, continuing...\n"); 344 346 } 347 + 348 + free(feat_sec); 345 349 }; 346 350 347 351 struct perf_header *perf_header__read(int fd)
+1
tools/perf/util/include/linux/bitmap.h
··· 1 1 #include "../../../../include/linux/bitmap.h" 2 2 #include "../../../../include/asm-generic/bitops/find.h" 3 + #include <linux/errno.h>
+1 -1
tools/perf/util/include/linux/ctype.h
··· 1 - #include "../../../../include/linux/ctype.h" 1 + #include "../util.h"
+3
tools/perf/util/util.h
··· 306 306 #undef isascii 307 307 #undef isspace 308 308 #undef isdigit 309 + #undef isxdigit 309 310 #undef isalpha 310 311 #undef isprint 311 312 #undef isalnum ··· 324 323 #define isascii(x) (((x) & ~0x7f) == 0) 325 324 #define isspace(x) sane_istest(x,GIT_SPACE) 326 325 #define isdigit(x) sane_istest(x,GIT_DIGIT) 326 + #define isxdigit(x) \ 327 + (sane_istest(toupper(x), GIT_ALPHA | GIT_DIGIT) && toupper(x) < 'G') 327 328 #define isalpha(x) sane_istest(x,GIT_ALPHA) 328 329 #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) 329 330 #define isprint(x) sane_istest(x,GIT_PRINT)