aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/header.c
diff options
context:
space:
mode:
authorStephane Eranian <eranian@google.com>2012-02-09 17:21:08 -0500
committerIngo Molnar <mingo@elte.hu>2012-03-09 02:26:07 -0500
commit114382a0aea97974803c942f106d462cbca5c64d (patch)
treeb7557e44097fc13e6ebdec51ba8d14e5c63a61d9 /tools/perf/util/header.c
parent62db90681c0db8c76e5db006b929a2edd5d12ae6 (diff)
perf tools: Make perf able to read files from older ABIs
This patches provides a way to handle legacy perf.data files. Legacy files are those using the older PERFFILE signature. For those, it is still necessary to detect endianness but without comparing their header->attr_size with the tool's own version as it may be different. Instead, we use a reference table for all known sizes from the legacy era. We try all the combinations for sizes and endianness. If we find a match, we proceed, otherwise we return: "incompatible file format". This is also done for the pipe-mode file format. 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-19-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.c122
1 files changed, 94 insertions, 28 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 6d580267d043..c851495b9b48 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1803,35 +1803,101 @@ out_free:
1803 return err; 1803 return err;
1804} 1804}
1805 1805
1806static int check_magic_endian(u64 *magic, struct perf_file_header *header, 1806static const int attr_file_abi_sizes[] = {
1807 struct perf_header *ph) 1807 [0] = PERF_ATTR_SIZE_VER0,
1808 [1] = PERF_ATTR_SIZE_VER1,
1809 0,
1810};
1811
1812/*
1813 * In the legacy file format, the magic number is not used to encode endianness.
1814 * hdr_sz was used to encode endianness. But given that hdr_sz can vary based
1815 * on ABI revisions, we need to try all combinations for all endianness to
1816 * detect the endianness.
1817 */
1818static int try_all_file_abis(uint64_t hdr_sz, struct perf_header *ph)
1808{ 1819{
1809 int ret; 1820 uint64_t ref_size, attr_size;
1821 int i;
1810 1822
1811 /* check for legacy format */ 1823 for (i = 0 ; attr_file_abi_sizes[i]; i++) {
1812 ret = memcmp(magic, __perf_magic1, sizeof(*magic)); 1824 ref_size = attr_file_abi_sizes[i]
1813 if (ret == 0) { 1825 + sizeof(struct perf_file_section);
1814 pr_debug("legacy perf.data format\n"); 1826 if (hdr_sz != ref_size) {
1815 if (!header) 1827 attr_size = bswap_64(hdr_sz);
1816 return -1; 1828 if (attr_size != ref_size)
1829 continue;
1817 1830
1818 if (header->attr_size != sizeof(struct perf_file_attr)) { 1831 ph->needs_swap = true;
1819 u64 attr_size = bswap_64(header->attr_size); 1832 }
1833 pr_debug("ABI%d perf.data file detected, need_swap=%d\n",
1834 i,
1835 ph->needs_swap);
1836 return 0;
1837 }
1838 /* could not determine endianness */
1839 return -1;
1840}
1820 1841
1821 if (attr_size != sizeof(struct perf_file_attr)) 1842#define PERF_PIPE_HDR_VER0 16
1822 return -1; 1843
1844static const size_t attr_pipe_abi_sizes[] = {
1845 [0] = PERF_PIPE_HDR_VER0,
1846 0,
1847};
1848
1849/*
1850 * In the legacy pipe format, there is an implicit assumption that endiannesss
1851 * between host recording the samples, and host parsing the samples is the
1852 * same. This is not always the case given that the pipe output may always be
1853 * redirected into a file and analyzed on a different machine with possibly a
1854 * different endianness and perf_event ABI revsions in the perf tool itself.
1855 */
1856static int try_all_pipe_abis(uint64_t hdr_sz, struct perf_header *ph)
1857{
1858 u64 attr_size;
1859 int i;
1860
1861 for (i = 0 ; attr_pipe_abi_sizes[i]; i++) {
1862 if (hdr_sz != attr_pipe_abi_sizes[i]) {
1863 attr_size = bswap_64(hdr_sz);
1864 if (attr_size != hdr_sz)
1865 continue;
1823 1866
1824 ph->needs_swap = true; 1867 ph->needs_swap = true;
1825 } 1868 }
1869 pr_debug("Pipe ABI%d perf.data file detected\n", i);
1826 return 0; 1870 return 0;
1827 } 1871 }
1872 return -1;
1873}
1874
1875static int check_magic_endian(u64 magic, uint64_t hdr_sz,
1876 bool is_pipe, struct perf_header *ph)
1877{
1878 int ret;
1879
1880 /* check for legacy format */
1881 ret = memcmp(&magic, __perf_magic1, sizeof(magic));
1882 if (ret == 0) {
1883 pr_debug("legacy perf.data format\n");
1884 if (is_pipe)
1885 return try_all_pipe_abis(hdr_sz, ph);
1886
1887 return try_all_file_abis(hdr_sz, ph);
1888 }
1889 /*
1890 * the new magic number serves two purposes:
1891 * - unique number to identify actual perf.data files
1892 * - encode endianness of file
1893 */
1828 1894
1829 /* check magic number with same endianness */ 1895 /* check magic number with one endianness */
1830 if (*magic == __perf_magic2) 1896 if (magic == __perf_magic2)
1831 return 0; 1897 return 0;
1832 1898
1833 /* check magic number but opposite endianness */ 1899 /* check magic number with opposite endianness */
1834 if (*magic != __perf_magic2_sw) 1900 if (magic != __perf_magic2_sw)
1835 return -1; 1901 return -1;
1836 1902
1837 ph->needs_swap = true; 1903 ph->needs_swap = true;
@@ -1850,8 +1916,11 @@ int perf_file_header__read(struct perf_file_header *header,
1850 if (ret <= 0) 1916 if (ret <= 0)
1851 return -1; 1917 return -1;
1852 1918
1853 if (check_magic_endian(&header->magic, header, ph) < 0) 1919 if (check_magic_endian(header->magic,
1920 header->attr_size, false, ph) < 0) {
1921 pr_debug("magic/endian check failed\n");
1854 return -1; 1922 return -1;
1923 }
1855 1924
1856 if (ph->needs_swap) { 1925 if (ph->needs_swap) {
1857 mem_bswap_64(header, offsetof(struct perf_file_header, 1926 mem_bswap_64(header, offsetof(struct perf_file_header,
@@ -1938,21 +2007,17 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
1938 if (ret <= 0) 2007 if (ret <= 0)
1939 return -1; 2008 return -1;
1940 2009
1941 if (check_magic_endian(&header->magic, NULL, ph) < 0) 2010 if (check_magic_endian(header->magic, header->size, true, ph) < 0) {
2011 pr_debug("endian/magic failed\n");
1942 return -1; 2012 return -1;
2013 }
2014
2015 if (ph->needs_swap)
2016 header->size = bswap_64(header->size);
1943 2017
1944 if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0) 2018 if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0)
1945 return -1; 2019 return -1;
1946 2020
1947 if (header->size != sizeof(*header)) {
1948 u64 size = bswap_64(header->size);
1949
1950 if (size != sizeof(*header))
1951 return -1;
1952
1953 ph->needs_swap = true;
1954 }
1955
1956 return 0; 2021 return 0;
1957} 2022}
1958 2023
@@ -1992,6 +2057,7 @@ static int read_attr(int fd, struct perf_header *ph,
1992 2057
1993 /* on file perf_event_attr size */ 2058 /* on file perf_event_attr size */
1994 sz = attr->size; 2059 sz = attr->size;
2060
1995 if (ph->needs_swap) 2061 if (ph->needs_swap)
1996 sz = bswap_32(sz); 2062 sz = bswap_32(sz);
1997 2063