diff options
author | Stephane Eranian <eranian@google.com> | 2012-02-09 17:21:06 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2012-03-09 02:26:06 -0500 |
commit | 69996df486fc3921bbaaa17fca0d68f537f9eabf (patch) | |
tree | 4d41484700db59dbf769af11b5e3f70ba34e222d /tools/perf/util/header.c | |
parent | cb5d76999029ae7a517cb07dfa732c1b5a934fc2 (diff) |
perf tools: Enable reading of perf.data files from different ABI rev
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>
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r-- | tools/perf/util/header.c | 53 |
1 files changed, 48 insertions, 5 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 9f867d96c6a5..666f18972fa3 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -1973,6 +1973,51 @@ static int perf_header__read_pipe(struct perf_session *session, int fd) | |||
1973 | return 0; | 1973 | return 0; |
1974 | } | 1974 | } |
1975 | 1975 | ||
1976 | static int read_attr(int fd, struct perf_header *ph, | ||
1977 | struct perf_file_attr *f_attr) | ||
1978 | { | ||
1979 | struct perf_event_attr *attr = &f_attr->attr; | ||
1980 | size_t sz, left; | ||
1981 | size_t our_sz = sizeof(f_attr->attr); | ||
1982 | int ret; | ||
1983 | |||
1984 | memset(f_attr, 0, sizeof(*f_attr)); | ||
1985 | |||
1986 | /* read minimal guaranteed structure */ | ||
1987 | ret = readn(fd, attr, PERF_ATTR_SIZE_VER0); | ||
1988 | if (ret <= 0) { | ||
1989 | pr_debug("cannot read %d bytes of header attr\n", | ||
1990 | PERF_ATTR_SIZE_VER0); | ||
1991 | return -1; | ||
1992 | } | ||
1993 | |||
1994 | /* on file perf_event_attr size */ | ||
1995 | sz = attr->size; | ||
1996 | if (ph->needs_swap) | ||
1997 | sz = bswap_32(sz); | ||
1998 | |||
1999 | if (sz == 0) { | ||
2000 | /* assume ABI0 */ | ||
2001 | sz = PERF_ATTR_SIZE_VER0; | ||
2002 | } else if (sz > our_sz) { | ||
2003 | pr_debug("file uses a more recent and unsupported ABI" | ||
2004 | " (%zu bytes extra)\n", sz - our_sz); | ||
2005 | return -1; | ||
2006 | } | ||
2007 | /* what we have not yet read and that we know about */ | ||
2008 | left = sz - PERF_ATTR_SIZE_VER0; | ||
2009 | if (left) { | ||
2010 | void *ptr = attr; | ||
2011 | ptr += PERF_ATTR_SIZE_VER0; | ||
2012 | |||
2013 | ret = readn(fd, ptr, left); | ||
2014 | } | ||
2015 | /* read perf_file_section, ids are read in caller */ | ||
2016 | ret = readn(fd, &f_attr->ids, sizeof(f_attr->ids)); | ||
2017 | |||
2018 | return ret <= 0 ? -1 : 0; | ||
2019 | } | ||
2020 | |||
1976 | int perf_session__read_header(struct perf_session *session, int fd) | 2021 | int perf_session__read_header(struct perf_session *session, int fd) |
1977 | { | 2022 | { |
1978 | struct perf_header *header = &session->header; | 2023 | struct perf_header *header = &session->header; |
@@ -1988,19 +2033,17 @@ int perf_session__read_header(struct perf_session *session, int fd) | |||
1988 | if (session->fd_pipe) | 2033 | if (session->fd_pipe) |
1989 | return perf_header__read_pipe(session, fd); | 2034 | return perf_header__read_pipe(session, fd); |
1990 | 2035 | ||
1991 | if (perf_file_header__read(&f_header, header, fd) < 0) { | 2036 | if (perf_file_header__read(&f_header, header, fd) < 0) |
1992 | pr_debug("incompatible file format\n"); | ||
1993 | return -EINVAL; | 2037 | return -EINVAL; |
1994 | } | ||
1995 | 2038 | ||
1996 | nr_attrs = f_header.attrs.size / sizeof(f_attr); | 2039 | nr_attrs = f_header.attrs.size / f_header.attr_size; |
1997 | lseek(fd, f_header.attrs.offset, SEEK_SET); | 2040 | lseek(fd, f_header.attrs.offset, SEEK_SET); |
1998 | 2041 | ||
1999 | for (i = 0; i < nr_attrs; i++) { | 2042 | for (i = 0; i < nr_attrs; i++) { |
2000 | struct perf_evsel *evsel; | 2043 | struct perf_evsel *evsel; |
2001 | off_t tmp; | 2044 | off_t tmp; |
2002 | 2045 | ||
2003 | if (readn(fd, &f_attr, sizeof(f_attr)) <= 0) | 2046 | if (read_attr(fd, header, &f_attr) < 0) |
2004 | goto out_errno; | 2047 | goto out_errno; |
2005 | 2048 | ||
2006 | if (header->needs_swap) | 2049 | if (header->needs_swap) |