From 03456a158d9067d2f657bec170506009db81756d Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Tue, 6 Oct 2009 23:36:47 +0200 Subject: perf tools: Merge trace.info content into perf.data This drops the trace.info file and move its contents into the common perf.data file. This is done by creating a new trace_info section into this file. A user of perf headers needs to call perf_header__set_trace_info() to save the trace meta informations into the perf.data file. A file created by perf after his patch is unsupported by previous version because the size of the headers have increased. That said, it's two new fields that have been added in the end of the headers, and those could be ignored by previous versions if they just handled the dynamic header size and then ignore the unknow part. The offsets guarantee the compatibility. We'll do a -stable fix for that. But current previous versions handle the header size using its static size, not dynamic, then it's not backward compatible with trace records. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Paul Mackerras Cc: Mike Galbraith Cc: Paul Mackerras LKML-Reference: <20091006213643.GA5343@nowhere> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index e306857b2c2b..212fade7ee74 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -5,6 +5,8 @@ #include "util.h" #include "header.h" +#include "../perf.h" +#include "trace-event.h" /* * Create new perf.data header attribute: @@ -62,6 +64,8 @@ struct perf_header *perf_header__new(void) self->data_offset = 0; self->data_size = 0; + self->trace_info_offset = 0; + self->trace_info_size = 0; return self; } @@ -145,8 +149,16 @@ struct perf_file_header { struct perf_file_section attrs; struct perf_file_section data; struct perf_file_section event_types; + struct perf_file_section trace_info; }; +static int trace_info; + +void perf_header__set_trace_info(void) +{ + trace_info = 1; +} + static void do_write(int fd, void *buf, size_t size) { while (size) { @@ -198,6 +210,23 @@ void perf_header__write(struct perf_header *self, int fd) if (events) do_write(fd, events, self->event_size); + if (trace_info) { + static int trace_info_written; + + /* + * Write it only once + */ + if (!trace_info_written) { + self->trace_info_offset = lseek(fd, 0, SEEK_CUR); + read_tracing_data(fd, attrs, nr_counters); + self->trace_info_size = lseek(fd, 0, SEEK_CUR) - + self->trace_info_offset; + trace_info_written = 1; + } else { + lseek(fd, self->trace_info_offset + + self->trace_info_size, SEEK_SET); + } + } self->data_offset = lseek(fd, 0, SEEK_CUR); @@ -217,6 +246,10 @@ void perf_header__write(struct perf_header *self, int fd) .offset = self->event_offset, .size = self->event_size, }, + .trace_info = { + .offset = self->trace_info_offset, + .size = self->trace_info_size, + }, }; lseek(fd, 0, SEEK_SET); @@ -290,6 +323,15 @@ struct perf_header *perf_header__read(int fd) do_read(fd, events, f_header.event_types.size); event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); } + + self->trace_info_offset = f_header.trace_info.offset; + self->trace_info_size = f_header.trace_info.size; + + if (self->trace_info_size) { + lseek(fd, self->trace_info_offset, SEEK_SET); + trace_report(fd); + } + self->event_offset = f_header.event_types.offset; self->event_size = f_header.event_types.size; -- cgit v1.2.3 From 26dd2cb074d9dc41c9e3cddd7bf175fd0a41febc Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 8 Oct 2009 22:07:29 +0200 Subject: perf tools: Provide backward compatibility with previous perf.data version We have merged the trace.info file into perf.data by adding one section in the perf headers. This makes it incompatible with previous version: the new perf tools can't read the older perf.data. To support the previous format, we check the headers size. If they have the same size than in the previous format, then ignore the trace info section that doesn't exist. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras LKML-Reference: <1255032449-12022-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 212fade7ee74..9aae360c0f28 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -287,10 +287,16 @@ struct perf_header *perf_header__read(int fd) do_read(fd, &f_header, sizeof(f_header)); if (f_header.magic != PERF_MAGIC || - f_header.size != sizeof(f_header) || f_header.attr_size != sizeof(f_attr)) die("incompatible file format"); + if (f_header.size != sizeof(f_header)) { + /* Support the previous format */ + if (f_header.size == offsetof(typeof(f_header), trace_info)) + f_header.trace_info.size = 0; + else + die("incompatible file format"); + } nr_attrs = f_header.attrs.size / sizeof(f_attr); lseek(fd, f_header.attrs.offset, SEEK_SET); -- cgit v1.2.3 From 2ba0825075e76236d22a20decd8e2346a99faabe Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 17 Oct 2009 17:12:34 +0200 Subject: perf tools: Introduce bitmask'ed additional headers This provides a new set of bitmasked headers. A new field is added in the perf headers that implements a bitmap storing optional features present in the perf.data file. The layout can be pictured like this: (Usual perf headers)(Features bitmap)[Feature 0][Feature n][Feature 255] If the bit n is set, then the feature n is used in this file. They are all set in order. This brings a backward and forward compatibility. The trace_info section has moved into such optional features, this is the first and only one for now. This is backward compatible with the .32 file version although it doesn't support the previous separate trace.info file. And finally it doesn't support the current interim development version. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras Cc: Steven Rostedt LKML-Reference: <1255792354-11304-2-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 100 ++++++++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 44 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 9aae360c0f28..171d51b6f359 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -8,6 +8,8 @@ #include "../perf.h" #include "trace-event.h" +#include + /* * Create new perf.data header attribute: */ @@ -48,25 +50,17 @@ void perf_header_attr__add_id(struct perf_header_attr *self, u64 id) */ struct perf_header *perf_header__new(void) { - struct perf_header *self = malloc(sizeof(*self)); + struct perf_header *self = calloc(sizeof(*self), 1); if (!self) die("nomem"); - self->frozen = 0; - - self->attrs = 0; self->size = 1; self->attr = malloc(sizeof(void *)); if (!self->attr) die("nomem"); - self->data_offset = 0; - self->data_size = 0; - self->trace_info_offset = 0; - self->trace_info_size = 0; - return self; } @@ -149,14 +143,12 @@ struct perf_file_header { struct perf_file_section attrs; struct perf_file_section data; struct perf_file_section event_types; - struct perf_file_section trace_info; + feat_mask_t adds_features; }; -static int trace_info; - -void perf_header__set_trace_info(void) +void perf_header__feat_trace_info(struct perf_header *header) { - trace_info = 1; + set_bit(HEADER_TRACE_INFO, perf_header__adds_mask(header)); } static void do_write(int fd, void *buf, size_t size) @@ -172,6 +164,32 @@ static void do_write(int fd, void *buf, size_t size) } } +static void perf_header__adds_write(struct perf_header *self, int fd) +{ + struct perf_file_section trace_sec; + u64 cur_offset = lseek(fd, 0, SEEK_CUR); + unsigned long *feat_mask = perf_header__adds_mask(self); + + if (test_bit(HEADER_TRACE_INFO, feat_mask)) { + /* Write trace info */ + trace_sec.offset = lseek(fd, sizeof(trace_sec), SEEK_CUR); + read_tracing_data(fd, attrs, nr_counters); + trace_sec.size = lseek(fd, 0, SEEK_CUR) - trace_sec.offset; + + /* Write trace info headers */ + lseek(fd, cur_offset, SEEK_SET); + do_write(fd, &trace_sec, sizeof(trace_sec)); + + /* + * Update cur_offset. So that other (future) + * features can set their own infos in this place. But if we are + * the only feature, at least that seeks to the place the data + * should begin. + */ + cur_offset = lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); + } +}; + void perf_header__write(struct perf_header *self, int fd) { struct perf_file_header f_header; @@ -210,23 +228,7 @@ void perf_header__write(struct perf_header *self, int fd) if (events) do_write(fd, events, self->event_size); - if (trace_info) { - static int trace_info_written; - - /* - * Write it only once - */ - if (!trace_info_written) { - self->trace_info_offset = lseek(fd, 0, SEEK_CUR); - read_tracing_data(fd, attrs, nr_counters); - self->trace_info_size = lseek(fd, 0, SEEK_CUR) - - self->trace_info_offset; - trace_info_written = 1; - } else { - lseek(fd, self->trace_info_offset + - self->trace_info_size, SEEK_SET); - } - } + perf_header__adds_write(self, fd); self->data_offset = lseek(fd, 0, SEEK_CUR); @@ -246,12 +248,10 @@ void perf_header__write(struct perf_header *self, int fd) .offset = self->event_offset, .size = self->event_size, }, - .trace_info = { - .offset = self->trace_info_offset, - .size = self->trace_info_size, - }, }; + memcpy(&f_header.adds_features, &self->adds_features, sizeof(feat_mask_t)); + lseek(fd, 0, SEEK_SET); do_write(fd, &f_header, sizeof(f_header)); lseek(fd, self->data_offset + self->data_size, SEEK_SET); @@ -274,6 +274,20 @@ static void do_read(int fd, void *buf, size_t size) } } +static void perf_header__adds_read(struct perf_header *self, int fd) +{ + const unsigned long *feat_mask = perf_header__adds_mask(self); + + if (test_bit(HEADER_TRACE_INFO, feat_mask)) { + struct perf_file_section trace_sec; + + do_read(fd, &trace_sec, sizeof(trace_sec)); + lseek(fd, trace_sec.offset, SEEK_SET); + trace_report(fd); + lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); + } +}; + struct perf_header *perf_header__read(int fd) { struct perf_header *self = perf_header__new(); @@ -292,9 +306,11 @@ struct perf_header *perf_header__read(int fd) if (f_header.size != sizeof(f_header)) { /* Support the previous format */ - if (f_header.size == offsetof(typeof(f_header), trace_info)) - f_header.trace_info.size = 0; - else + if (f_header.size == offsetof(typeof(f_header), adds_features)) { + unsigned long *mask = (unsigned long *)(void *) + &f_header.adds_features; + bitmap_zero(mask, HEADER_FEAT_BITS); + } else die("incompatible file format"); } nr_attrs = f_header.attrs.size / sizeof(f_attr); @@ -330,13 +346,9 @@ struct perf_header *perf_header__read(int fd) event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); } - self->trace_info_offset = f_header.trace_info.offset; - self->trace_info_size = f_header.trace_info.size; + memcpy(&self->adds_features, &f_header.adds_features, sizeof(feat_mask_t)); - if (self->trace_info_size) { - lseek(fd, self->trace_info_offset, SEEK_SET); - trace_report(fd); - } + perf_header__adds_read(self, fd); self->event_offset = f_header.event_types.offset; self->event_size = f_header.event_types.size; -- cgit v1.2.3 From db9f11e36d0125a5e3e595ea9ef2e4b89f7e8737 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 17 Oct 2009 17:57:18 +0200 Subject: perf tools: Use DECLARE_BITMAP instead of an open-coded array Use DECLARE_BITMAP instead of an open coded array for our bitmap of featured sections. This makes the array an unsigned long instead of a u64 but since we use a 256 bits bitmap, the array size shouldn't vary between different boxes. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras Cc: Steven Rostedt LKML-Reference: <1255795038-13751-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 171d51b6f359..622c60e45254 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -8,8 +8,6 @@ #include "../perf.h" #include "trace-event.h" -#include - /* * Create new perf.data header attribute: */ @@ -143,12 +141,12 @@ struct perf_file_header { struct perf_file_section attrs; struct perf_file_section data; struct perf_file_section event_types; - feat_mask_t adds_features; + DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); }; void perf_header__feat_trace_info(struct perf_header *header) { - set_bit(HEADER_TRACE_INFO, perf_header__adds_mask(header)); + set_bit(HEADER_TRACE_INFO, header->adds_features); } static void do_write(int fd, void *buf, size_t size) @@ -168,7 +166,7 @@ static void perf_header__adds_write(struct perf_header *self, int fd) { struct perf_file_section trace_sec; u64 cur_offset = lseek(fd, 0, SEEK_CUR); - unsigned long *feat_mask = perf_header__adds_mask(self); + unsigned long *feat_mask = self->adds_features; if (test_bit(HEADER_TRACE_INFO, feat_mask)) { /* Write trace info */ @@ -250,7 +248,7 @@ void perf_header__write(struct perf_header *self, int fd) }, }; - memcpy(&f_header.adds_features, &self->adds_features, sizeof(feat_mask_t)); + memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features)); lseek(fd, 0, SEEK_SET); do_write(fd, &f_header, sizeof(f_header)); @@ -276,7 +274,7 @@ static void do_read(int fd, void *buf, size_t size) static void perf_header__adds_read(struct perf_header *self, int fd) { - const unsigned long *feat_mask = perf_header__adds_mask(self); + const unsigned long *feat_mask = self->adds_features; if (test_bit(HEADER_TRACE_INFO, feat_mask)) { struct perf_file_section trace_sec; @@ -306,11 +304,9 @@ struct perf_header *perf_header__read(int fd) if (f_header.size != sizeof(f_header)) { /* Support the previous format */ - if (f_header.size == offsetof(typeof(f_header), adds_features)) { - unsigned long *mask = (unsigned long *)(void *) - &f_header.adds_features; - bitmap_zero(mask, HEADER_FEAT_BITS); - } else + if (f_header.size == offsetof(typeof(f_header), adds_features)) + bitmap_zero(f_header.adds_features, HEADER_FEAT_BITS); + else die("incompatible file format"); } nr_attrs = f_header.attrs.size / sizeof(f_attr); @@ -346,7 +342,7 @@ struct perf_header *perf_header__read(int fd) event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); } - memcpy(&self->adds_features, &f_header.adds_features, sizeof(feat_mask_t)); + memcpy(&self->adds_features, &f_header.adds_features, sizeof(f_header.adds_features)); perf_header__adds_read(self, fd); -- cgit v1.2.3 From 6beba7adbe092e63dfe8d09fbd1e3ec140474a13 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 21 Oct 2009 17:34:06 -0200 Subject: perf tools: Unify debug messages mechanisms We were using eprintf in some places, that looks at a global 'verbose' level, and at other places passing a 'v' parameter to specify the verbosity level, unify it by introducing pr_{err,warning,debug,etc}, just like in the kernel. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Mike Galbraith LKML-Reference: <1256153646-10097-1-git-send-email-acme@redhat.com> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 622c60e45254..7d26659b806c 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -93,7 +93,7 @@ static struct perf_trace_event_type *events; void perf_header__push_event(u64 id, const char *name) { if (strlen(name) > MAX_EVENT_NAME) - printf("Event %s will be truncated\n", name); + pr_warning("Event %s will be truncated\n", name); if (!events) { events = malloc(sizeof(struct perf_trace_event_type)); -- cgit v1.2.3 From 8d06367fa79c053a4a56a2ce0bb9e840f5da1236 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 4 Nov 2009 18:50:43 -0200 Subject: perf symbols: Use the buildids if present With this change 'perf record' will intercept PERF_RECORD_MMAP calls, creating a linked list of DSOs, then when the session finishes, it will traverse this list and read the buildids, stashing them at the end of the file and will set up a new feature bit in the header bitmask. 'perf report' will then notice this feature and populate the 'dsos' list and set the build ids. When reading the symtabs it will refuse to load from a file that doesn't have the same build id. This improves the reliability of the profiler output, as symbols and profiling data is more guaranteed to match. Example: [root@doppio ~]# perf report | head /home/acme/bin/perf with build id b1ea544ac3746e7538972548a09aadecc5753868 not found, continuing without symbols # Samples: 2621434559 # # Overhead Command Shared Object Symbol # ........ ............... ............................. ...... # 7.91% init [kernel] [k] read_hpet 7.64% init [kernel] [k] mwait_idle_with_hints 7.60% swapper [kernel] [k] read_hpet 7.60% swapper [kernel] [k] mwait_idle_with_hints 3.65% init [kernel] [k] 0xffffffffa02339d9 [root@doppio ~]# In this case the 'perf' binary was an older one, vanished, so its symbols probably wouldn't match or would cause subtly different (and misleading) output. Next patches will support the kernel as well, reading the build id notes for it and the modules from /sys. Another patch should also introduce a new plumbing command: 'perf list-buildids' that will then be used in porcelain that is distro specific to fetch -debuginfo packages where such buildids are present. This will in turn allow for one to run 'perf record' in one machine and 'perf report' in another. Future work on having the buildid sent directly from the kernel in the PERF_RECORD_MMAP event is needed to close races, as the DSO can be changed during a 'perf record' session, but this patch at least helps with non-corner cases and current/older kernels. Signed-off-by: Arnaldo Carvalho de Melo Cc: Ananth N Mavinakayanahalli Cc: Christoph Hellwig Cc: Frank Ch. Eigler Cc: Frederic Weisbecker Cc: Jason Baron Cc: Jim Keniston Cc: K. Prasad Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Roland McGrath Cc: Srikar Dronamraju Cc: Steven Rostedt LKML-Reference: <1257367843-26224-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 7d26659b806c..050f543fd965 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -149,6 +149,16 @@ void perf_header__feat_trace_info(struct perf_header *header) set_bit(HEADER_TRACE_INFO, header->adds_features); } +void perf_header__set_feat(struct perf_header *self, int feat) +{ + set_bit(feat, self->adds_features); +} + +bool perf_header__has_feat(const struct perf_header *self, int feat) +{ + return test_bit(feat, self->adds_features); +} + static void do_write(int fd, void *buf, size_t size) { while (size) { -- cgit v1.2.3 From 8671dab9d5b2f0b444b8d09792384dccbfd43d14 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 11 Nov 2009 04:51:03 +0100 Subject: perf tools: Move the build-id storage operations to headers So that it makes easier to control it. Especially because we plan to give it a feature section. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras Cc: Hitoshi Mitake LKML-Reference: <1257911467-28276-2-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 050f543fd965..a4d0bbef9a43 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2,11 +2,13 @@ #include #include #include +#include #include "util.h" #include "header.h" #include "../perf.h" #include "trace-event.h" +#include "symbol.h" /* * Create new perf.data header attribute: @@ -172,7 +174,33 @@ static void do_write(int fd, void *buf, size_t size) } } -static void perf_header__adds_write(struct perf_header *self, int fd) +static bool write_buildid_table(int fd) +{ + struct dso *pos; + bool have_buildid = false; + + list_for_each_entry(pos, &dsos, node) { + struct build_id_event b; + size_t len; + + if (filename__read_build_id(pos->long_name, + &b.build_id, + sizeof(b.build_id)) < 0) + continue; + have_buildid = true; + memset(&b.header, 0, sizeof(b.header)); + len = strlen(pos->long_name) + 1; + len = ALIGN(len, 64); + b.header.size = sizeof(b) + len; + do_write(fd, &b, sizeof(b)); + do_write(fd, pos->long_name, len); + } + + return have_buildid; +} + +static void +perf_header__adds_write(struct perf_header *self, int fd, bool at_exit) { struct perf_file_section trace_sec; u64 cur_offset = lseek(fd, 0, SEEK_CUR); @@ -196,9 +224,16 @@ static void perf_header__adds_write(struct perf_header *self, int fd) */ cur_offset = lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); } + + if (at_exit) { + lseek(fd, self->data_offset + self->data_size, SEEK_SET); + if (write_buildid_table(fd)) + perf_header__set_feat(self, HEADER_BUILD_ID); + lseek(fd, cur_offset, SEEK_SET); + } }; -void perf_header__write(struct perf_header *self, int fd) +void perf_header__write(struct perf_header *self, int fd, bool at_exit) { struct perf_file_header f_header; struct perf_file_attr f_attr; @@ -236,7 +271,7 @@ void perf_header__write(struct perf_header *self, int fd) if (events) do_write(fd, events, self->event_size); - perf_header__adds_write(self, fd); + perf_header__adds_write(self, fd, at_exit); self->data_offset = lseek(fd, 0, SEEK_CUR); -- cgit v1.2.3 From 57f395a7eabb913d3605d7392be5bdb0837c9f3d Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 11 Nov 2009 04:51:04 +0100 Subject: perf tools: Split up build id saving into fetch and write We are saving the build id once we stop the profiling. And only after doing that we know if we need to set that feature in the header through the feature bitmap. But if we want a proper feature support in the headers, using a rule of offset/size pairs in sections, we need to know in advance how many features we need to set in the headers, so that we can reserve rooms for their section headers. The current state doesn't allow that, as it forces us to first save the build-ids to the file right after the datas instead of planning any structured layout. That's why this splits up the build-ids processing in two parts: one that fetches the build-ids from the Dso objects, and one that saves them into the file. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras Cc: Hitoshi Mitake LKML-Reference: <1257911467-28276-3-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 41 +++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 24 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index a4d0bbef9a43..2f702c23f71a 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -174,29 +174,18 @@ static void do_write(int fd, void *buf, size_t size) } } -static bool write_buildid_table(int fd) +static void write_buildid_table(int fd, struct list_head *id_head) { - struct dso *pos; - bool have_buildid = false; - - list_for_each_entry(pos, &dsos, node) { - struct build_id_event b; - size_t len; - - if (filename__read_build_id(pos->long_name, - &b.build_id, - sizeof(b.build_id)) < 0) - continue; - have_buildid = true; - memset(&b.header, 0, sizeof(b.header)); - len = strlen(pos->long_name) + 1; - len = ALIGN(len, 64); - b.header.size = sizeof(b) + len; - do_write(fd, &b, sizeof(b)); - do_write(fd, pos->long_name, len); - } + struct build_id_list *iter, *next; + + list_for_each_entry_safe(iter, next, id_head, list) { + struct build_id_event *b = &iter->event; - return have_buildid; + do_write(fd, b, sizeof(*b)); + do_write(fd, (void *)iter->dso_name, iter->len); + list_del(&iter->list); + free(iter); + } } static void @@ -226,10 +215,14 @@ perf_header__adds_write(struct perf_header *self, int fd, bool at_exit) } if (at_exit) { - lseek(fd, self->data_offset + self->data_size, SEEK_SET); - if (write_buildid_table(fd)) + LIST_HEAD(id_list); + + if (fetch_build_id_table(&id_list)) { + lseek(fd, self->data_offset + self->data_size, SEEK_SET); perf_header__set_feat(self, HEADER_BUILD_ID); - lseek(fd, cur_offset, SEEK_SET); + write_buildid_table(fd, &id_list); + lseek(fd, cur_offset, SEEK_SET); + } } }; -- cgit v1.2.3 From 4778d2e4f410c6eea32f594cb2be9590bcb28b84 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 11 Nov 2009 04:51:05 +0100 Subject: perf tools: Read the build-ids from the header layer Keep the build-ids reading implementation in the data mapping but move its call to the headers so that we have a better control on it (offset seeking, size passing, etc..). Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras Cc: Hitoshi Mitake LKML-Reference: <1257911467-28276-4-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 2f702c23f71a..915b56edbf02 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -9,6 +9,8 @@ #include "../perf.h" #include "trace-event.h" #include "symbol.h" +#include "data_map.h" +#include "debug.h" /* * Create new perf.data header attribute: @@ -322,6 +324,14 @@ static void perf_header__adds_read(struct perf_header *self, int fd) trace_report(fd); lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); } + + if (perf_header__has_feat(self, HEADER_BUILD_ID)) { + struct stat input_stat; + + fstat(fd, &input_stat); + if (perf_header__read_build_ids(self, fd, input_stat.st_size)) + pr_debug("failed to read buildids, continuing...\n"); + } }; struct perf_header *perf_header__read(int fd) @@ -382,14 +392,14 @@ struct perf_header *perf_header__read(int fd) memcpy(&self->adds_features, &f_header.adds_features, sizeof(f_header.adds_features)); - perf_header__adds_read(self, fd); - self->event_offset = f_header.event_types.offset; self->event_size = f_header.event_types.size; self->data_offset = f_header.data.offset; self->data_size = f_header.data.size; + perf_header__adds_read(self, fd); + lseek(fd, self->data_offset, SEEK_SET); self->frozen = 1; -- cgit v1.2.3 From 3e13ab2d83b6867a20663c73c184f29c2fde1558 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 11 Nov 2009 04:51:06 +0100 Subject: perf tools: Use perf_header__set/has_feat whenever possible And drop the alternate checks/sets using set_bit or other kind of helpers. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras Cc: Hitoshi Mitake LKML-Reference: <1257911467-28276-5-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 915b56edbf02..9709d38113b1 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -148,11 +148,6 @@ struct perf_file_header { DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); }; -void perf_header__feat_trace_info(struct perf_header *header) -{ - set_bit(HEADER_TRACE_INFO, header->adds_features); -} - void perf_header__set_feat(struct perf_header *self, int feat) { set_bit(feat, self->adds_features); @@ -195,9 +190,8 @@ perf_header__adds_write(struct perf_header *self, int fd, bool at_exit) { struct perf_file_section trace_sec; u64 cur_offset = lseek(fd, 0, SEEK_CUR); - unsigned long *feat_mask = self->adds_features; - if (test_bit(HEADER_TRACE_INFO, feat_mask)) { + if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { /* Write trace info */ trace_sec.offset = lseek(fd, sizeof(trace_sec), SEEK_CUR); read_tracing_data(fd, attrs, nr_counters); @@ -314,9 +308,7 @@ static void do_read(int fd, void *buf, size_t size) static void perf_header__adds_read(struct perf_header *self, int fd) { - const unsigned long *feat_mask = self->adds_features; - - if (test_bit(HEADER_TRACE_INFO, feat_mask)) { + if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { struct perf_file_section trace_sec; do_read(fd, &trace_sec, sizeof(trace_sec)); -- cgit v1.2.3 From 9e827dd00a94136b944a538bede67c944d0b740a Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 11 Nov 2009 04:51:07 +0100 Subject: 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 Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras Cc: Hitoshi Mitake LKML-Reference: <1257911467-28276-6-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 110 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 75 insertions(+), 35 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 9709d38113b1..ebed4f44ed36 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -186,41 +186,58 @@ static void write_buildid_table(int fd, struct list_head *id_head) } static void -perf_header__adds_write(struct perf_header *self, int fd, bool at_exit) +perf_header__adds_write(struct perf_header *self, int fd) { - struct perf_file_section trace_sec; - u64 cur_offset = lseek(fd, 0, SEEK_CUR); + LIST_HEAD(id_list); + int nr_sections; + struct perf_file_section *feat_sec; + int sec_size; + u64 sec_start; + int idx = 0; + + if (fetch_build_id_table(&id_list)) + perf_header__set_feat(self, HEADER_BUILD_ID); + + nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); + if (!nr_sections) + return; + + feat_sec = calloc(sizeof(*feat_sec), nr_sections); + if (!feat_sec) + die("No memory"); + + sec_size = sizeof(*feat_sec) * nr_sections; + + sec_start = self->data_offset + self->data_size; + lseek(fd, sec_start + sec_size, SEEK_SET); if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { + struct perf_file_section *trace_sec; + + trace_sec = &feat_sec[idx++]; + /* Write trace info */ - trace_sec.offset = lseek(fd, sizeof(trace_sec), SEEK_CUR); + trace_sec->offset = lseek(fd, 0, SEEK_CUR); read_tracing_data(fd, attrs, nr_counters); - trace_sec.size = lseek(fd, 0, SEEK_CUR) - trace_sec.offset; - - /* Write trace info headers */ - lseek(fd, cur_offset, SEEK_SET); - do_write(fd, &trace_sec, sizeof(trace_sec)); - - /* - * Update cur_offset. So that other (future) - * features can set their own infos in this place. But if we are - * the only feature, at least that seeks to the place the data - * should begin. - */ - cur_offset = lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); + trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; } - if (at_exit) { - LIST_HEAD(id_list); - if (fetch_build_id_table(&id_list)) { - lseek(fd, self->data_offset + self->data_size, SEEK_SET); - perf_header__set_feat(self, HEADER_BUILD_ID); - write_buildid_table(fd, &id_list); - lseek(fd, cur_offset, SEEK_SET); - } + if (perf_header__has_feat(self, HEADER_BUILD_ID)) { + struct perf_file_section *buildid_sec; + + buildid_sec = &feat_sec[idx++]; + + /* Write build-ids */ + buildid_sec->offset = lseek(fd, 0, SEEK_CUR); + write_buildid_table(fd, &id_list); + buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; } -}; + + lseek(fd, sec_start, SEEK_SET); + do_write(fd, feat_sec, sec_size); + free(feat_sec); +} void perf_header__write(struct perf_header *self, int fd, bool at_exit) { @@ -260,10 +277,11 @@ void perf_header__write(struct perf_header *self, int fd, bool at_exit) if (events) do_write(fd, events, self->event_size); - perf_header__adds_write(self, fd, at_exit); - self->data_offset = lseek(fd, 0, SEEK_CUR); + if (at_exit) + perf_header__adds_write(self, fd); + f_header = (struct perf_file_header){ .magic = PERF_MAGIC, .size = sizeof(f_header), @@ -308,22 +326,44 @@ static void do_read(int fd, void *buf, size_t size) static void perf_header__adds_read(struct perf_header *self, int fd) { + struct perf_file_section *feat_sec; + int nr_sections; + int sec_size; + int idx = 0; + + + nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); + if (!nr_sections) + return; + + feat_sec = calloc(sizeof(*feat_sec), nr_sections); + if (!feat_sec) + die("No memory"); + + sec_size = sizeof(*feat_sec) * nr_sections; + + lseek(fd, self->data_offset + self->data_size, SEEK_SET); + + do_read(fd, feat_sec, sec_size); + if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { - struct perf_file_section trace_sec; + struct perf_file_section *trace_sec; - do_read(fd, &trace_sec, sizeof(trace_sec)); - lseek(fd, trace_sec.offset, SEEK_SET); + trace_sec = &feat_sec[idx++]; + lseek(fd, trace_sec->offset, SEEK_SET); trace_report(fd); - lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); } if (perf_header__has_feat(self, HEADER_BUILD_ID)) { - struct stat input_stat; + struct perf_file_section *buildid_sec; - fstat(fd, &input_stat); - if (perf_header__read_build_ids(self, fd, input_stat.st_size)) + buildid_sec = &feat_sec[idx++]; + lseek(fd, buildid_sec->offset, SEEK_SET); + if (perf_header__read_build_ids(fd, buildid_sec->size)) pr_debug("failed to read buildids, continuing...\n"); } + + free(feat_sec); }; struct perf_header *perf_header__read(int fd) -- cgit v1.2.3 From 84fe8488ade7922afa9f3aa77c22d2d92beb9660 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 16 Nov 2009 16:32:41 -0200 Subject: perf symbols: Pass the offset to perf_header__read_build_ids() Signed-off-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra LKML-Reference: <1258396365-29217-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index ebed4f44ed36..ca0d657eefad 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -359,7 +359,7 @@ static void perf_header__adds_read(struct perf_header *self, int fd) buildid_sec = &feat_sec[idx++]; lseek(fd, buildid_sec->offset, SEEK_SET); - if (perf_header__read_build_ids(fd, buildid_sec->size)) + if (perf_header__read_build_ids(fd, buildid_sec->offset, buildid_sec->size)) pr_debug("failed to read buildids, continuing...\n"); } -- cgit v1.2.3 From 37562eac3767c7f07bb1a1329708ff6453e47570 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 16 Nov 2009 16:32:43 -0200 Subject: perf tools: Generalize perf_header__adds_read() Renaming it to perf_header__process_sections() and passing a callback to handle each feature. The next changesets will introduce 'perf buildid-list' that will handle just the HEADER_BUILD_ID table, ignoring all the other features. Signed-off-by: Arnaldo Carvalho de Melo Acked-by: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra LKML-Reference: <1258396365-29217-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 123 ++++++++++++++++++++++++++--------------------- 1 file changed, 69 insertions(+), 54 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index ca0d657eefad..d8416f011179 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -128,26 +128,11 @@ static const char *__perf_magic = "PERFFILE"; #define PERF_MAGIC (*(u64 *)__perf_magic) -struct perf_file_section { - u64 offset; - u64 size; -}; - struct perf_file_attr { struct perf_event_attr attr; struct perf_file_section ids; }; -struct perf_file_header { - u64 magic; - u64 size; - u64 attr_size; - struct perf_file_section attrs; - struct perf_file_section data; - struct perf_file_section event_types; - DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); -}; - void perf_header__set_feat(struct perf_header *self, int feat) { set_bit(feat, self->adds_features); @@ -324,21 +309,23 @@ static void do_read(int fd, void *buf, size_t size) } } -static void perf_header__adds_read(struct perf_header *self, int fd) +int perf_header__process_sections(struct perf_header *self, int fd, + int (*process)(struct perf_file_section *self, + int feat, int fd)) { struct perf_file_section *feat_sec; int nr_sections; int sec_size; int idx = 0; - + int err = 0, feat = 1; nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); if (!nr_sections) - return; + return 0; feat_sec = calloc(sizeof(*feat_sec), nr_sections); if (!feat_sec) - die("No memory"); + return -1; sec_size = sizeof(*feat_sec) * nr_sections; @@ -346,25 +333,73 @@ static void perf_header__adds_read(struct perf_header *self, int fd) do_read(fd, feat_sec, sec_size); - if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { - struct perf_file_section *trace_sec; + while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { + if (perf_header__has_feat(self, feat)) { + struct perf_file_section *sec = &feat_sec[idx++]; - trace_sec = &feat_sec[idx++]; - lseek(fd, trace_sec->offset, SEEK_SET); - trace_report(fd); + err = process(sec, feat, fd); + if (err < 0) + break; + } + ++feat; } - if (perf_header__has_feat(self, HEADER_BUILD_ID)) { - struct perf_file_section *buildid_sec; + free(feat_sec); + return err; +}; - buildid_sec = &feat_sec[idx++]; - lseek(fd, buildid_sec->offset, SEEK_SET); - if (perf_header__read_build_ids(fd, buildid_sec->offset, buildid_sec->size)) - pr_debug("failed to read buildids, continuing...\n"); +int perf_file_header__read(struct perf_file_header *self, + struct perf_header *ph, int fd) +{ + lseek(fd, 0, SEEK_SET); + do_read(fd, self, sizeof(*self)); + + if (self->magic != PERF_MAGIC || + self->attr_size != sizeof(struct perf_file_attr)) + return -1; + + if (self->size != sizeof(*self)) { + /* Support the previous format */ + if (self->size == offsetof(typeof(*self), adds_features)) + bitmap_zero(self->adds_features, HEADER_FEAT_BITS); + else + return -1; } - free(feat_sec); -}; + memcpy(&ph->adds_features, &self->adds_features, + sizeof(self->adds_features)); + + ph->event_offset = self->event_types.offset; + ph->event_size = self->event_types.size; + ph->data_offset = self->data.offset; + ph->data_size = self->data.size; + return 0; +} + +static int perf_file_section__process(struct perf_file_section *self, + int feat, int fd) +{ + if (lseek(fd, self->offset, SEEK_SET) < 0) { + pr_debug("Failed to lseek to %Ld offset for feature %d, " + "continuing...\n", self->offset, feat); + return 0; + } + + switch (feat) { + case HEADER_TRACE_INFO: + trace_report(fd); + break; + + case HEADER_BUILD_ID: + if (perf_header__read_build_ids(fd, self->offset, self->size)) + pr_debug("Failed to read buildids, continuing...\n"); + break; + default: + pr_debug("unknown feature %d, continuing...\n", feat); + } + + return 0; +} struct perf_header *perf_header__read(int fd) { @@ -372,23 +407,11 @@ struct perf_header *perf_header__read(int fd) struct perf_file_header f_header; struct perf_file_attr f_attr; u64 f_id; - int nr_attrs, nr_ids, i, j; - lseek(fd, 0, SEEK_SET); - do_read(fd, &f_header, sizeof(f_header)); - - if (f_header.magic != PERF_MAGIC || - f_header.attr_size != sizeof(f_attr)) + if (perf_file_header__read(&f_header, self, fd) < 0) die("incompatible file format"); - if (f_header.size != sizeof(f_header)) { - /* Support the previous format */ - if (f_header.size == offsetof(typeof(f_header), adds_features)) - bitmap_zero(f_header.adds_features, HEADER_FEAT_BITS); - else - die("incompatible file format"); - } nr_attrs = f_header.attrs.size / sizeof(f_attr); lseek(fd, f_header.attrs.offset, SEEK_SET); @@ -422,15 +445,7 @@ struct perf_header *perf_header__read(int fd) event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); } - memcpy(&self->adds_features, &f_header.adds_features, sizeof(f_header.adds_features)); - - self->event_offset = f_header.event_types.offset; - self->event_size = f_header.event_types.size; - - self->data_offset = f_header.data.offset; - self->data_size = f_header.data.size; - - perf_header__adds_read(self, fd); + perf_header__process_sections(self, fd, perf_file_section__process); lseek(fd, self->data_offset, SEEK_SET); -- cgit v1.2.3 From dc79c0fc08a94b857aed446bfb47cdfde529400c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 16 Nov 2009 19:30:26 -0200 Subject: perf tools: Don't die in perf_header_attr__new() We really should propagate such kinds of errors so that users of these library functions decide what to do in such cases instead of exiting in random places like now. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra LKML-Reference: <1258407027-384-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index d8416f011179..2f07a238ffdf 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -19,16 +19,16 @@ struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr) { struct perf_header_attr *self = malloc(sizeof(*self)); - if (!self) - die("nomem"); - - self->attr = *attr; - self->ids = 0; - self->size = 1; - self->id = malloc(sizeof(u64)); - - if (!self->id) - die("nomem"); + if (self != NULL) { + self->attr = *attr; + self->ids = 0; + self->size = 1; + self->id = malloc(sizeof(u64)); + if (self->id == NULL) { + free(self); + self = NULL; + } + } return self; } @@ -423,6 +423,8 @@ struct perf_header *perf_header__read(int fd) tmp = lseek(fd, 0, SEEK_CUR); attr = perf_header_attr__new(&f_attr.attr); + if (attr == NULL) + die("nomem"); nr_ids = f_attr.ids.size / sizeof(u64); lseek(fd, f_attr.ids.offset, SEEK_SET); -- cgit v1.2.3 From 11deb1f9f6ca6318fa9470e024b9f0634df48b4c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 17 Nov 2009 01:18:09 -0200 Subject: perf tools: Don't die() in perf_header__add_attr() Propagate the errors instead, the users are the ones to decide what to do if a library call fails. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra LKML-Reference: <1258427892-16312-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 2f07a238ffdf..23ccddae0b06 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -33,6 +33,12 @@ struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr) return self; } +void perf_header_attr__delete(struct perf_header_attr *self) +{ + free(self->id); + free(self); +} + void perf_header_attr__add_id(struct perf_header_attr *self, u64 id) { int pos = self->ids; @@ -66,22 +72,28 @@ struct perf_header *perf_header__new(void) return self; } -void perf_header__add_attr(struct perf_header *self, - struct perf_header_attr *attr) +int perf_header__add_attr(struct perf_header *self, + struct perf_header_attr *attr) { int pos = self->attrs; if (self->frozen) - die("frozen"); + return -1; self->attrs++; if (self->attrs > self->size) { - self->size *= 2; - self->attr = realloc(self->attr, self->size * sizeof(void *)); - if (!self->attr) - die("nomem"); + int nsize = self->size * 2; + struct perf_header_attr **nattr; + + nattr = realloc(self->attr, nsize * sizeof(void *)); + if (nattr == NULL) + return -1; + + self->size = nsize; + self->attr = nattr; } self->attr[pos] = attr; + return 0; } #define MAX_EVENT_NAME 64 @@ -434,7 +446,9 @@ struct perf_header *perf_header__read(int fd) perf_header_attr__add_id(attr, f_id); } - perf_header__add_attr(self, attr); + if (perf_header__add_attr(self, attr) < 0) + die("nomem"); + lseek(fd, tmp, SEEK_SET); } -- cgit v1.2.3 From 5875412152ce67fb5087157b86ab6597f91d23e8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 17 Nov 2009 01:18:10 -0200 Subject: perf tools: Don't die() in perf_header_attr__add_id() Propagate the errors instead, the users are the ones to decide what to do if a library call fails. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra LKML-Reference: <1258427892-16312-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 23ccddae0b06..dee1ed2f0d1b 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -39,18 +39,23 @@ void perf_header_attr__delete(struct perf_header_attr *self) free(self); } -void perf_header_attr__add_id(struct perf_header_attr *self, u64 id) +int perf_header_attr__add_id(struct perf_header_attr *self, u64 id) { int pos = self->ids; self->ids++; if (self->ids > self->size) { - self->size *= 2; - self->id = realloc(self->id, self->size * sizeof(u64)); - if (!self->id) - die("nomem"); + int nsize = self->size * 2; + u64 *nid = realloc(self->id, nsize * sizeof(u64)); + + if (nid == NULL) + return -1; + + self->size = nsize; + self->id = nid; } self->id[pos] = id; + return 0; } /* @@ -444,7 +449,8 @@ struct perf_header *perf_header__read(int fd) for (j = 0; j < nr_ids; j++) { do_read(fd, &f_id, sizeof(f_id)); - perf_header_attr__add_id(attr, f_id); + if (perf_header_attr__add_id(attr, f_id) < 0) + die("nomem"); } if (perf_header__add_attr(self, attr) < 0) die("nomem"); -- cgit v1.2.3 From a9a70bbce7ab0bf3b1cba3ac662c4d502da6305c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 17 Nov 2009 01:18:11 -0200 Subject: perf tools: Don't die() in perf_header__new() Propagate the errors instead, the users are the ones to decide what to do if a library call fails. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra LKML-Reference: <1258427892-16312-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index dee1ed2f0d1b..726a0eb5f197 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -65,14 +65,15 @@ struct perf_header *perf_header__new(void) { struct perf_header *self = calloc(sizeof(*self), 1); - if (!self) - die("nomem"); - - self->size = 1; - self->attr = malloc(sizeof(void *)); + if (self != NULL) { + self->size = 1; + self->attr = malloc(sizeof(void *)); - if (!self->attr) - die("nomem"); + if (self->attr == NULL) { + free(self); + self = NULL; + } + } return self; } @@ -426,6 +427,9 @@ struct perf_header *perf_header__read(int fd) u64 f_id; int nr_attrs, nr_ids, i, j; + if (self == NULL) + die("nomem"); + if (perf_file_header__read(&f_header, self, fd) < 0) die("incompatible file format"); -- cgit v1.2.3 From 3726cc75e581c157202da93bb2333cce25c15c98 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 17 Nov 2009 01:18:12 -0200 Subject: perf tools: Don't die() in do_write() Propagate the errors instead, the users are the ones to decide what to do if a library call fails. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra LKML-Reference: <1258427892-16312-4-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 726a0eb5f197..b01a9537977f 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -161,31 +161,36 @@ bool perf_header__has_feat(const struct perf_header *self, int feat) return test_bit(feat, self->adds_features); } -static void do_write(int fd, void *buf, size_t size) +static int do_write(int fd, const void *buf, size_t size) { while (size) { int ret = write(fd, buf, size); if (ret < 0) - die("failed to write"); + return -1; size -= ret; buf += ret; } + + return 0; } -static void write_buildid_table(int fd, struct list_head *id_head) +static int write_buildid_table(int fd, struct list_head *id_head) { struct build_id_list *iter, *next; list_for_each_entry_safe(iter, next, id_head, list) { struct build_id_event *b = &iter->event; - do_write(fd, b, sizeof(*b)); - do_write(fd, (void *)iter->dso_name, iter->len); + if (do_write(fd, b, sizeof(*b)) < 0 || + do_write(fd, iter->dso_name, iter->len) < 0) + return -1; list_del(&iter->list); free(iter); } + + return 0; } static void @@ -233,12 +238,14 @@ perf_header__adds_write(struct perf_header *self, int fd) /* Write build-ids */ buildid_sec->offset = lseek(fd, 0, SEEK_CUR); - write_buildid_table(fd, &id_list); + if (write_buildid_table(fd, &id_list) < 0) + die("failed to write buildid table"); buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; } lseek(fd, sec_start, SEEK_SET); - do_write(fd, feat_sec, sec_size); + if (do_write(fd, feat_sec, sec_size) < 0) + die("failed to write feature section"); free(feat_sec); } @@ -256,7 +263,8 @@ void perf_header__write(struct perf_header *self, int fd, bool at_exit) attr = self->attr[i]; attr->id_offset = lseek(fd, 0, SEEK_CUR); - do_write(fd, attr->id, attr->ids * sizeof(u64)); + if (do_write(fd, attr->id, attr->ids * sizeof(u64)) < 0) + die("failed to write perf header"); } @@ -272,13 +280,15 @@ void perf_header__write(struct perf_header *self, int fd, bool at_exit) .size = attr->ids * sizeof(u64), } }; - do_write(fd, &f_attr, sizeof(f_attr)); + if (do_write(fd, &f_attr, sizeof(f_attr)) < 0) + die("failed to write perf header attribute"); } self->event_offset = lseek(fd, 0, SEEK_CUR); self->event_size = event_count * sizeof(struct perf_trace_event_type); if (events) - do_write(fd, events, self->event_size); + if (do_write(fd, events, self->event_size) < 0) + die("failed to write perf header events"); self->data_offset = lseek(fd, 0, SEEK_CUR); @@ -306,7 +316,8 @@ void perf_header__write(struct perf_header *self, int fd, bool at_exit) memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features)); lseek(fd, 0, SEEK_SET); - do_write(fd, &f_header, sizeof(f_header)); + if (do_write(fd, &f_header, sizeof(f_header)) < 0) + die("failed to write perf header"); lseek(fd, self->data_offset + self->data_size, SEEK_SET); self->frozen = 1; -- cgit v1.2.3 From e30a3d12ddf04add3268bfceb0e57ffe47f254c6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 18 Nov 2009 20:20:51 -0200 Subject: perf symbols: Kill struct build_id_list and die() another day MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need for this struct and its allocations, we can just use the ->build_id member we already have in struct dso, then ask for it to be read, and later traverse the dsos list, writing the buildid table to the perf.data file. As a bonus, one more die() function got killed. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1258582853-8579-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index b01a9537977f..31731f1606b2 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -176,18 +176,24 @@ static int do_write(int fd, const void *buf, size_t size) return 0; } -static int write_buildid_table(int fd, struct list_head *id_head) +static int dsos__write_buildid_table(int fd) { - struct build_id_list *iter, *next; - - list_for_each_entry_safe(iter, next, id_head, list) { - struct build_id_event *b = &iter->event; - - if (do_write(fd, b, sizeof(*b)) < 0 || - do_write(fd, iter->dso_name, iter->len) < 0) + struct dso *pos; + + list_for_each_entry(pos, &dsos, node) { + struct build_id_event b; + size_t len; + + if (!pos->has_build_id) + continue; + len = pos->long_name_len + 1; + len = ALIGN(len, 64); + memset(&b, 0, sizeof(b)); + memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); + b.header.size = sizeof(b) + len; + if (do_write(fd, &b, sizeof(b)) < 0 || + do_write(fd, pos->long_name, len) < 0) return -1; - list_del(&iter->list); - free(iter); } return 0; @@ -196,14 +202,13 @@ static int write_buildid_table(int fd, struct list_head *id_head) static void perf_header__adds_write(struct perf_header *self, int fd) { - LIST_HEAD(id_list); int nr_sections; struct perf_file_section *feat_sec; int sec_size; u64 sec_start; int idx = 0; - if (fetch_build_id_table(&id_list)) + if (dsos__read_build_ids()) perf_header__set_feat(self, HEADER_BUILD_ID); nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); @@ -238,7 +243,7 @@ perf_header__adds_write(struct perf_header *self, int fd) /* Write build-ids */ buildid_sec->offset = lseek(fd, 0, SEEK_CUR); - if (write_buildid_table(fd, &id_list) < 0) + if (dsos__write_buildid_table(fd) < 0) die("failed to write buildid table"); buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; } -- cgit v1.2.3 From f1617b40596cb341ee6602a9d969c5e4cebe9260 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 18 Nov 2009 20:20:52 -0200 Subject: perf symbols: Record the build_ids of kernel modules too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [root@doppio linux-2.6-tip]# perf record -a sleep 2s;perf buildid-list|tail [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.162 MB perf.data (~7078 samples) ] 881588fa57b3c1696bc91e5e804a11304f093535 [cfg80211] 4d47ce1da9d16bad00c962c072451b7c681e82df [snd_page_alloc] 5146377e89a7caac617f9782f1a02e46263d3a31 [rfkill] 2153b937bff0d345fea83b63a2e1d3138569f83d [i915] 4e6fb1bb97362e3ee4d306988b9ad6912d5fb9ae [drm_kms_helper] f56ef2bf853e3a798f0d8d51f797622e5dc4420e [drm] b0d157a3b5c4e017329ffc07c64623cd6ad65e95 [i2c_algo_bit] 8125374b905ef9fa8b65d98e166b008ad952f198 [i2c_core] fc875c6e5a90e7b915e9d445d0efc859e1b2678c [video] 4b43c5006589f977e9762fdfc7ac1a92b72fca52 [output] [root@doppio linux-2.6-tip]# elfutils libdwfl/linux-kernel-modules.c was used as reference, as suggested by Roland McGrath. Signed-off-by: Arnaldo Carvalho de Melo Cc: Roland McGrath Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1258582853-8579-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 31731f1606b2..d3d656f9a621 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -241,6 +241,11 @@ perf_header__adds_write(struct perf_header *self, int fd) buildid_sec = &feat_sec[idx++]; + /* + * Read the list of loaded modules with its build_ids + */ + dsos__load_modules(); + /* Write build-ids */ buildid_sec->offset = lseek(fd, 0, SEEK_CUR); if (dsos__write_buildid_table(fd) < 0) -- cgit v1.2.3 From 2446042c93bfc6eeebfc89e88fdef2435d2bb5c4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 18 Nov 2009 20:20:53 -0200 Subject: perf symbols: Capture the running kernel buildid too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [root@doppio linux-2.6-tip]# perf record -a -f sleep 3s ; perf buildid-list | grep vmlinux [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.171 MB perf.data (~7489 samples) ] 18e7cc53db62a7d35e9d6f6c9ddc23017d38ee9a vmlinux [root@doppio linux-2.6-tip]# Several refactorings were needed so that we can have symmetry between dsos__load_modules() and dsos__load_kernel(), i.e. those functions will respectively create and add to the dsos list the loaded modules and kernel, with its buildids, but not load its symbols. That is something the subcomands that need will have to call dso__load_kernel_sym(), just like we do with modules with dsos__load_module_sym()/dso__load_module_sym(). Next csets will actually use this info to stop producing bogus results using mismatched vmlinux and .ko files. Signed-off-by: Arnaldo Carvalho de Melo Cc: Roland McGrath Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1258582853-8579-4-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index d3d656f9a621..425a29ba01a9 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -241,6 +241,7 @@ perf_header__adds_write(struct perf_header *self, int fd) buildid_sec = &feat_sec[idx++]; + dsos__load_kernel(); /* * Read the list of loaded modules with its build_ids */ -- cgit v1.2.3 From 4dc0a04bb18fe9b80cefa08694f46a3a19ebfe50 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Nov 2009 14:55:55 -0200 Subject: perf tools: perf_header__read() shouldn't die() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And also don't call the constructor in it, this way it adheres to the model the other methods follow. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1258649757-17554-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 52 +++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 21 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 425a29ba01a9..e66c7bd4cc88 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -78,16 +78,24 @@ struct perf_header *perf_header__new(void) return self; } +void perf_header__delete(struct perf_header *self) +{ + int i; + + for (i = 0; i < self->attrs; ++i) + perf_header_attr__delete(self->attr[i]); + + free(self->attr); + free(self); +} + int perf_header__add_attr(struct perf_header *self, struct perf_header_attr *attr) { - int pos = self->attrs; - if (self->frozen) return -1; - self->attrs++; - if (self->attrs > self->size) { + if (self->attrs == self->size) { int nsize = self->size * 2; struct perf_header_attr **nattr; @@ -98,7 +106,8 @@ int perf_header__add_attr(struct perf_header *self, self->size = nsize; self->attr = nattr; } - self->attr[pos] = attr; + + self->attr[self->attrs++] = attr; return 0; } @@ -441,19 +450,17 @@ static int perf_file_section__process(struct perf_file_section *self, return 0; } -struct perf_header *perf_header__read(int fd) +int perf_header__read(struct perf_header *self, int fd) { - struct perf_header *self = perf_header__new(); struct perf_file_header f_header; struct perf_file_attr f_attr; u64 f_id; int nr_attrs, nr_ids, i, j; - if (self == NULL) - die("nomem"); - - if (perf_file_header__read(&f_header, self, fd) < 0) - die("incompatible file format"); + if (perf_file_header__read(&f_header, self, fd) < 0) { + pr_debug("incompatible file format\n"); + return -EINVAL; + } nr_attrs = f_header.attrs.size / sizeof(f_attr); lseek(fd, f_header.attrs.offset, SEEK_SET); @@ -467,7 +474,7 @@ struct perf_header *perf_header__read(int fd) attr = perf_header_attr__new(&f_attr.attr); if (attr == NULL) - die("nomem"); + return -ENOMEM; nr_ids = f_attr.ids.size / sizeof(u64); lseek(fd, f_attr.ids.offset, SEEK_SET); @@ -475,11 +482,15 @@ struct perf_header *perf_header__read(int fd) for (j = 0; j < nr_ids; j++) { do_read(fd, &f_id, sizeof(f_id)); - if (perf_header_attr__add_id(attr, f_id) < 0) - die("nomem"); + if (perf_header_attr__add_id(attr, f_id) < 0) { + perf_header_attr__delete(attr); + return -ENOMEM; + } + } + if (perf_header__add_attr(self, attr) < 0) { + perf_header_attr__delete(attr); + return -ENOMEM; } - if (perf_header__add_attr(self, attr) < 0) - die("nomem"); lseek(fd, tmp, SEEK_SET); } @@ -487,8 +498,8 @@ struct perf_header *perf_header__read(int fd) if (f_header.event_types.size) { lseek(fd, f_header.event_types.offset, SEEK_SET); events = malloc(f_header.event_types.size); - if (!events) - die("nomem"); + if (events == NULL) + return -ENOMEM; do_read(fd, events, f_header.event_types.size); event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); } @@ -498,8 +509,7 @@ struct perf_header *perf_header__read(int fd) lseek(fd, self->data_offset, SEEK_SET); self->frozen = 1; - - return self; + return 0; } u64 perf_header__sample_type(struct perf_header *header) -- cgit v1.2.3 From d5eed904bb6010b429b82c47e7cdb6a32f0c1343 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Nov 2009 14:55:56 -0200 Subject: perf tools: Eliminate some more die() uses in library functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This time in perf_header__adds_write, propagating the do_write error returns. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1258649757-17554-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 80 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 27 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index e66c7bd4cc88..d5c81ebc0a84 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -176,7 +176,7 @@ static int do_write(int fd, const void *buf, size_t size) int ret = write(fd, buf, size); if (ret < 0) - return -1; + return -errno; size -= ret; buf += ret; @@ -190,6 +190,7 @@ static int dsos__write_buildid_table(int fd) struct dso *pos; list_for_each_entry(pos, &dsos, node) { + int err; struct build_id_event b; size_t len; @@ -200,33 +201,35 @@ static int dsos__write_buildid_table(int fd) memset(&b, 0, sizeof(b)); memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); b.header.size = sizeof(b) + len; - if (do_write(fd, &b, sizeof(b)) < 0 || - do_write(fd, pos->long_name, len) < 0) - return -1; + err = do_write(fd, &b, sizeof(b)); + if (err < 0) + return err; + err = do_write(fd, pos->long_name, len); + if (err < 0) + return err; } return 0; } -static void -perf_header__adds_write(struct perf_header *self, int fd) +static int perf_header__adds_write(struct perf_header *self, int fd) { int nr_sections; struct perf_file_section *feat_sec; int sec_size; u64 sec_start; - int idx = 0; + int idx = 0, err; if (dsos__read_build_ids()) perf_header__set_feat(self, HEADER_BUILD_ID); nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); if (!nr_sections) - return; + return 0; feat_sec = calloc(sizeof(*feat_sec), nr_sections); - if (!feat_sec) - die("No memory"); + if (feat_sec == NULL) + return -ENOMEM; sec_size = sizeof(*feat_sec) * nr_sections; @@ -258,23 +261,29 @@ perf_header__adds_write(struct perf_header *self, int fd) /* Write build-ids */ buildid_sec->offset = lseek(fd, 0, SEEK_CUR); - if (dsos__write_buildid_table(fd) < 0) - die("failed to write buildid table"); + err = dsos__write_buildid_table(fd); + if (err < 0) { + pr_debug("failed to write buildid table\n"); + goto out_free; + } buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; } lseek(fd, sec_start, SEEK_SET); - if (do_write(fd, feat_sec, sec_size) < 0) - die("failed to write feature section"); + err = do_write(fd, feat_sec, sec_size); + if (err < 0) + pr_debug("failed to write feature section\n"); +out_free: free(feat_sec); + return err; } -void perf_header__write(struct perf_header *self, int fd, bool at_exit) +int perf_header__write(struct perf_header *self, int fd, bool at_exit) { struct perf_file_header f_header; struct perf_file_attr f_attr; struct perf_header_attr *attr; - int i; + int i, err; lseek(fd, sizeof(f_header), SEEK_SET); @@ -283,8 +292,11 @@ void perf_header__write(struct perf_header *self, int fd, bool at_exit) attr = self->attr[i]; attr->id_offset = lseek(fd, 0, SEEK_CUR); - if (do_write(fd, attr->id, attr->ids * sizeof(u64)) < 0) - die("failed to write perf header"); + err = do_write(fd, attr->id, attr->ids * sizeof(u64)); + if (err < 0) { + pr_debug("failed to write perf header\n"); + return err; + } } @@ -300,20 +312,30 @@ void perf_header__write(struct perf_header *self, int fd, bool at_exit) .size = attr->ids * sizeof(u64), } }; - if (do_write(fd, &f_attr, sizeof(f_attr)) < 0) - die("failed to write perf header attribute"); + err = do_write(fd, &f_attr, sizeof(f_attr)); + if (err < 0) { + pr_debug("failed to write perf header attribute\n"); + return err; + } } self->event_offset = lseek(fd, 0, SEEK_CUR); self->event_size = event_count * sizeof(struct perf_trace_event_type); - if (events) - if (do_write(fd, events, self->event_size) < 0) - die("failed to write perf header events"); + if (events) { + err = do_write(fd, events, self->event_size); + if (err < 0) { + pr_debug("failed to write perf header events\n"); + return err; + } + } self->data_offset = lseek(fd, 0, SEEK_CUR); - if (at_exit) - perf_header__adds_write(self, fd); + if (at_exit) { + err = perf_header__adds_write(self, fd); + if (err < 0) + return err; + } f_header = (struct perf_file_header){ .magic = PERF_MAGIC, @@ -336,11 +358,15 @@ void perf_header__write(struct perf_header *self, int fd, bool at_exit) memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features)); lseek(fd, 0, SEEK_SET); - if (do_write(fd, &f_header, sizeof(f_header)) < 0) - die("failed to write perf header"); + err = do_write(fd, &f_header, sizeof(f_header)); + if (err < 0) { + pr_debug("failed to write perf header\n"); + return err; + } lseek(fd, self->data_offset + self->data_size, SEEK_SET); self->frozen = 1; + return 0; } static void do_read(int fd, void *buf, size_t size) -- cgit v1.2.3 From c338aee853db197e1855b393e6d6cc667784537f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 20 Nov 2009 20:51:27 -0200 Subject: perf symbols: Do lazy symtab loading for the kernel & modules too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just like we do with the other DSOs. This also simplifies the kernel_maps setup process, now all that the tools need to do is to call kernel_maps__init and the maps for the modules and kernel will be created, then, later, when kernel_maps__find_symbol() is used, it will also call maps__find_symbol that already checks if the symtab was loaded, loading it if needed. Now if one does 'perf top --hide_kernel_symbols' we won't pay the price of loading the (many) symbols in /proc/kallsyms or vmlinux. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1258757489-5978-4-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index d5c81ebc0a84..ac3410b8e9e3 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -253,11 +253,11 @@ static int perf_header__adds_write(struct perf_header *self, int fd) buildid_sec = &feat_sec[idx++]; - dsos__load_kernel(); /* - * Read the list of loaded modules with its build_ids + * Read the kernel buildid nad the list of loaded modules with + * its build_ids: */ - dsos__load_modules(); + kernel_maps__init(true); /* Write build-ids */ buildid_sec->offset = lseek(fd, 0, SEEK_CUR); -- cgit v1.2.3 From cc612d8199089413719397c9d92e5823da578eac Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 23 Nov 2009 16:39:10 -0200 Subject: perf symbols: Look for vmlinux in more places MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we can check the buildid to see if it really matches, this can be done safely: vmlinux /boot/vmlinux /boot/vmlinux- /lib/modules//build/vmlinux /usr/lib/debug/lib/modules/%s/vmlinux More can be added - if you know about distros that put the vmlinux somewhere else please let us know. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1259001550-8194-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index ac3410b8e9e3..1332f8ec04aa 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -257,7 +257,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd) * Read the kernel buildid nad the list of loaded modules with * its build_ids: */ - kernel_maps__init(true); + kernel_maps__init(NULL, false, true); /* Write build-ids */ buildid_sec->offset = lseek(fd, 0, SEEK_CUR); -- cgit v1.2.3 From b32d133aec5dc882cf783a293f393bfb3f4379e1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 24 Nov 2009 12:05:15 -0200 Subject: perf symbols: Simplify symbol machinery setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And also express its configuration toggles via a struct. Now all one has to do is to call symbol__init(NULL) if the defaults are OK, or pass a struct symbol_conf pointer with the desired configuration. If a tool uses kernel_maps__find_symbol() to look at the kernel and modules mappings for a symbol but didn't call symbol__init() first, that will generate a one time warning too, alerting the subcommand developer that symbol__init() must be called. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1259071517-3242-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 1332f8ec04aa..271a1600e6f7 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -253,12 +253,6 @@ static int perf_header__adds_write(struct perf_header *self, int fd) buildid_sec = &feat_sec[idx++]; - /* - * Read the kernel buildid nad the list of loaded modules with - * its build_ids: - */ - kernel_maps__init(NULL, false, true); - /* Write build-ids */ buildid_sec->offset = lseek(fd, 0, SEEK_CUR); err = dsos__write_buildid_table(fd); -- cgit v1.2.3 From 364794845cbc49e638b83d7ef739524291e1e961 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 24 Nov 2009 12:05:16 -0200 Subject: perf tools: Introduce zalloc() for the common calloc(1, N) case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way we type less characters and it looks more like the kzalloc kernel counterpart. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1259071517-3242-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 271a1600e6f7..4b586569bb02 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -63,7 +63,7 @@ int perf_header_attr__add_id(struct perf_header_attr *self, u64 id) */ struct perf_header *perf_header__new(void) { - struct perf_header *self = calloc(sizeof(*self), 1); + struct perf_header *self = zalloc(sizeof(*self)); if (self != NULL) { self->size = 1; -- cgit v1.2.3 From b0da954a4759ac19fb80a959e53b613fe376bc12 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 27 Nov 2009 16:29:14 -0200 Subject: perf symbols: Split the dsos list into kernel and user parts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't need to look at modules in dsos__findnew because the kernel events come only with user DSOs. Also we need a way to list just the module DSOs so that we can create multiple sets of maps, now that we will support maps for the variables in a symtab. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1259346563-12568-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'tools/perf/util/header.c') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 4b586569bb02..4805e6dfd23c 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -185,11 +185,11 @@ static int do_write(int fd, const void *buf, size_t size) return 0; } -static int dsos__write_buildid_table(int fd) +static int __dsos__write_buildid_table(struct list_head *head, int fd) { struct dso *pos; - list_for_each_entry(pos, &dsos, node) { + list_for_each_entry(pos, head, node) { int err; struct build_id_event b; size_t len; @@ -212,6 +212,14 @@ static int dsos__write_buildid_table(int fd) return 0; } +static int dsos__write_buildid_table(int fd) +{ + int err = __dsos__write_buildid_table(&dsos__kernel, fd); + if (err == 0) + err = __dsos__write_buildid_table(&dsos__user, fd); + return err; +} + static int perf_header__adds_write(struct perf_header *self, int fd) { int nr_sections; -- cgit v1.2.3