Skip to content

Commit

Permalink
perf tools: Enable reading of perf.data files from different ABI rev
Browse files Browse the repository at this point in the history
This patch allows perf to process perf.data files generated
using an ABI that has a different perf_event_attr struct size,
i.e., a different ABI version.

The perf_event_attr can be extended, yet perf needs to cope with
older perf.data files. Similarly, perf must be able to cope with
a perf.data file which is using a newer version of the ABI than
what it knows about.

This patch adds read_attr(), a routine that reads a
perf_event_attr struct from a file incrementally based on its
advertised size. If the on-file struct is smaller than what perf
knows, then the extra fields are zeroed. If the on-file struct
is bigger, then perf only uses what it knows about, the rest is
skipped.

Signed-off-by: Stephane Eranian <eranian@google.com>
Cc: peterz@infradead.org
Cc: acme@redhat.com
Cc: robert.richter@amd.com
Cc: ming.m.lin@intel.com
Cc: andi@firstfloor.org
Cc: asharma@fb.com
Cc: ravitillo@lbl.gov
Cc: vweaver1@eecs.utk.edu
Cc: khandual@linux.vnet.ibm.com
Cc: dsahern@gmail.com
Link: http://lkml.kernel.org/r/1328826068-11713-17-git-send-email-eranian@google.com
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Stephane Eranian authored and Ingo Molnar committed Mar 9, 2012
1 parent cb5d769 commit 69996df
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 7 deletions.
53 changes: 48 additions & 5 deletions tools/perf/util/header.c
Original file line number Diff line number Diff line change
Expand Up @@ -1973,6 +1973,51 @@ static int perf_header__read_pipe(struct perf_session *session, int fd)
return 0;
}

static int read_attr(int fd, struct perf_header *ph,
struct perf_file_attr *f_attr)
{
struct perf_event_attr *attr = &f_attr->attr;
size_t sz, left;
size_t our_sz = sizeof(f_attr->attr);
int ret;

memset(f_attr, 0, sizeof(*f_attr));

/* read minimal guaranteed structure */
ret = readn(fd, attr, PERF_ATTR_SIZE_VER0);
if (ret <= 0) {
pr_debug("cannot read %d bytes of header attr\n",
PERF_ATTR_SIZE_VER0);
return -1;
}

/* on file perf_event_attr size */
sz = attr->size;
if (ph->needs_swap)
sz = bswap_32(sz);

if (sz == 0) {
/* assume ABI0 */
sz = PERF_ATTR_SIZE_VER0;
} else if (sz > our_sz) {
pr_debug("file uses a more recent and unsupported ABI"
" (%zu bytes extra)\n", sz - our_sz);
return -1;
}
/* what we have not yet read and that we know about */
left = sz - PERF_ATTR_SIZE_VER0;
if (left) {
void *ptr = attr;
ptr += PERF_ATTR_SIZE_VER0;

ret = readn(fd, ptr, left);
}
/* read perf_file_section, ids are read in caller */
ret = readn(fd, &f_attr->ids, sizeof(f_attr->ids));

return ret <= 0 ? -1 : 0;
}

int perf_session__read_header(struct perf_session *session, int fd)
{
struct perf_header *header = &session->header;
Expand All @@ -1988,19 +2033,17 @@ int perf_session__read_header(struct perf_session *session, int fd)
if (session->fd_pipe)
return perf_header__read_pipe(session, fd);

if (perf_file_header__read(&f_header, header, fd) < 0) {
pr_debug("incompatible file format\n");
if (perf_file_header__read(&f_header, header, fd) < 0)
return -EINVAL;
}

nr_attrs = f_header.attrs.size / sizeof(f_attr);
nr_attrs = f_header.attrs.size / f_header.attr_size;
lseek(fd, f_header.attrs.offset, SEEK_SET);

for (i = 0; i < nr_attrs; i++) {
struct perf_evsel *evsel;
off_t tmp;

if (readn(fd, &f_attr, sizeof(f_attr)) <= 0)
if (read_attr(fd, header, &f_attr) < 0)
goto out_errno;

if (header->needs_swap)
Expand Down
4 changes: 2 additions & 2 deletions tools/perf/util/session.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ static int perf_session__open(struct perf_session *self, bool force)
self->fd = STDIN_FILENO;

if (perf_session__read_header(self, self->fd) < 0)
pr_err("incompatible file format");
pr_err("incompatible file format (rerun with -v to learn more)");

return 0;
}
Expand Down Expand Up @@ -56,7 +56,7 @@ static int perf_session__open(struct perf_session *self, bool force)
}

if (perf_session__read_header(self, self->fd) < 0) {
pr_err("incompatible file format");
pr_err("incompatible file format (rerun with -v to learn more)");
goto out_close;
}

Expand Down

0 comments on commit 69996df

Please sign in to comment.