diff options
author | Stephane Eranian <eranian@google.com> | 2012-02-09 17:21:08 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2012-03-09 02:26:07 -0500 |
commit | 114382a0aea97974803c942f106d462cbca5c64d (patch) | |
tree | b7557e44097fc13e6ebdec51ba8d14e5c63a61d9 /tools | |
parent | 62db90681c0db8c76e5db006b929a2edd5d12ae6 (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')
-rw-r--r-- | tools/perf/util/header.c | 122 |
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 | ||
1806 | static int check_magic_endian(u64 *magic, struct perf_file_header *header, | 1806 | static 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 | */ | ||
1818 | static 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 | |
1844 | static 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 | */ | ||
1856 | static 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 | |||
1875 | static 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 | ||