aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorStephane Eranian <eranian@google.com>2012-02-09 17:21:06 -0500
committerIngo Molnar <mingo@elte.hu>2012-03-09 02:26:06 -0500
commit69996df486fc3921bbaaa17fca0d68f537f9eabf (patch)
tree4d41484700db59dbf769af11b5e3f70ba34e222d /tools
parentcb5d76999029ae7a517cb07dfa732c1b5a934fc2 (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')
-rw-r--r--tools/perf/util/header.c53
-rw-r--r--tools/perf/util/session.c4
2 files changed, 50 insertions, 7 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
1976static 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
1976int perf_session__read_header(struct perf_session *session, int fd) 2021int 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)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index bec8a328b1b8..e650de8f4396 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -24,7 +24,7 @@ static int perf_session__open(struct perf_session *self, bool force)
24 self->fd = STDIN_FILENO; 24 self->fd = STDIN_FILENO;
25 25
26 if (perf_session__read_header(self, self->fd) < 0) 26 if (perf_session__read_header(self, self->fd) < 0)
27 pr_err("incompatible file format"); 27 pr_err("incompatible file format (rerun with -v to learn more)");
28 28
29 return 0; 29 return 0;
30 } 30 }
@@ -56,7 +56,7 @@ static int perf_session__open(struct perf_session *self, bool force)
56 } 56 }
57 57
58 if (perf_session__read_header(self, self->fd) < 0) { 58 if (perf_session__read_header(self, self->fd) < 0) {
59 pr_err("incompatible file format"); 59 pr_err("incompatible file format (rerun with -v to learn more)");
60 goto out_close; 60 goto out_close;
61 } 61 }
62 62