mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-20 06:17:11 +07:00
perf/core improvements and fixes:
perf trace: Arnaldo Carvalho de Melo: - Fix exclusion of not available syscall names from selector list. - Fixup pointer arithmetic when consuming augmented syscall args. Intel PT: Adrian Hunter: - Add support for decoding PEBS via PT packets. See: https://software.intel.com/en-us/articles/intel-sdm May 2019 version: Vol. 3B 18.5.5.2 PEBS output to Intel® Processor Trace for more details about it. ARM64: John Garry: - Fix uncore PMU alias list for ARM64 Raphael Gault: - Compile tests unconditionally. cs-etm: Mathieu Poirier: - Optimize option setup for CPU-wide sessions. build: Florian Fainelli: - Don't hardcode host include path for libslang, fixing up building with it in cross build environments. Arnaldo Carvalho de Melo: - Check if gettid() is available before providing helper, fixing the build when using the latest glibc version, where a helper for gettid() is finally present. - Fix building with libslang in systems where it is located in slang/slang.h. - Fix fast path test for zstd library. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQR2GiIUctdOfX2qHhGyPKLppCJ+JwUCXQ0TfwAKCRCyPKLppCJ+ J4JRAP4jtk8fPxAu1SIkhjjoApgKJoR9nQgoEXR67uG0TA/9JgD/e8KRAwmccdJO 0QBXO5+gqm9ESYds/goV7NdhwPULWg8= =f6FU -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo-5.3-20190621' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: perf trace: Arnaldo Carvalho de Melo: - Fix exclusion of not available syscall names from selector list. - Fixup pointer arithmetic when consuming augmented syscall args. Intel PT: Adrian Hunter: - Add support for decoding PEBS via PT packets. See: https://software.intel.com/en-us/articles/intel-sdm May 2019 version: Vol. 3B 18.5.5.2 PEBS output to Intel® Processor Trace for more details about it. ARM64: John Garry: - Fix uncore PMU alias list for ARM64 Raphael Gault: - Compile tests unconditionally. cs-etm: Mathieu Poirier: - Optimize option setup for CPU-wide sessions. build: Florian Fainelli: - Don't hardcode host include path for libslang, fixing up building with it in cross build environments. Arnaldo Carvalho de Melo: - Check if gettid() is available before providing helper, fixing the build when using the latest glibc version, where a helper for gettid() is finally present. - Fix building with libslang in systems where it is located in slang/slang.h. - Fix fast path test for zstd library. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
a3664a74a0
@ -36,6 +36,7 @@ FEATURE_TESTS_BASIC := \
|
||||
fortify-source \
|
||||
sync-compare-and-swap \
|
||||
get_current_dir_name \
|
||||
gettid \
|
||||
glibc \
|
||||
gtk2 \
|
||||
gtk2-infobar \
|
||||
@ -52,6 +53,7 @@ FEATURE_TESTS_BASIC := \
|
||||
libpython \
|
||||
libpython-version \
|
||||
libslang \
|
||||
libslang-include-subdir \
|
||||
libcrypto \
|
||||
libunwind \
|
||||
pthread-attr-setaffinity-np \
|
||||
@ -113,7 +115,6 @@ FEATURE_DISPLAY ?= \
|
||||
numa_num_possible_cpus \
|
||||
libperl \
|
||||
libpython \
|
||||
libslang \
|
||||
libcrypto \
|
||||
libunwind \
|
||||
libdw-dwarf-unwind \
|
||||
|
@ -31,6 +31,7 @@ FILES= \
|
||||
test-libpython.bin \
|
||||
test-libpython-version.bin \
|
||||
test-libslang.bin \
|
||||
test-libslang-include-subdir.bin \
|
||||
test-libcrypto.bin \
|
||||
test-libunwind.bin \
|
||||
test-libunwind-debug-frame.bin \
|
||||
@ -54,6 +55,7 @@ FILES= \
|
||||
test-get_cpuid.bin \
|
||||
test-sdt.bin \
|
||||
test-cxx.bin \
|
||||
test-gettid.bin \
|
||||
test-jvmti.bin \
|
||||
test-jvmti-cmlr.bin \
|
||||
test-sched_getcpu.bin \
|
||||
@ -181,7 +183,10 @@ $(OUTPUT)test-libaudit.bin:
|
||||
$(BUILD) -laudit
|
||||
|
||||
$(OUTPUT)test-libslang.bin:
|
||||
$(BUILD) -I/usr/include/slang -lslang
|
||||
$(BUILD) -lslang
|
||||
|
||||
$(OUTPUT)test-libslang-include-subdir.bin:
|
||||
$(BUILD) -lslang
|
||||
|
||||
$(OUTPUT)test-libcrypto.bin:
|
||||
$(BUILD) -lcrypto
|
||||
@ -267,6 +272,9 @@ $(OUTPUT)test-sdt.bin:
|
||||
$(OUTPUT)test-cxx.bin:
|
||||
$(BUILDXX) -std=gnu++11
|
||||
|
||||
$(OUTPUT)test-gettid.bin:
|
||||
$(BUILD)
|
||||
|
||||
$(OUTPUT)test-jvmti.bin:
|
||||
$(BUILD)
|
||||
|
||||
|
@ -38,6 +38,10 @@
|
||||
# include "test-get_current_dir_name.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_gettid
|
||||
# include "test-gettid.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_glibc
|
||||
# include "test-glibc.c"
|
||||
#undef main
|
||||
@ -182,7 +186,7 @@
|
||||
# include "test-disassembler-four-args.c"
|
||||
#undef main
|
||||
|
||||
#define main main_test_zstd
|
||||
#define main main_test_libzstd
|
||||
# include "test-libzstd.c"
|
||||
#undef main
|
||||
|
||||
@ -195,6 +199,7 @@ int main(int argc, char *argv[])
|
||||
main_test_libelf();
|
||||
main_test_libelf_mmap();
|
||||
main_test_get_current_dir_name();
|
||||
main_test_gettid();
|
||||
main_test_glibc();
|
||||
main_test_dwarf();
|
||||
main_test_dwarf_getlocations();
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
|
11
tools/build/feature/test-gettid.c
Normal file
11
tools/build/feature/test-gettid.c
Normal file
@ -0,0 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
|
||||
#define _GNU_SOURCE
|
||||
#include <unistd.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return gettid();
|
||||
}
|
||||
|
||||
#undef _GNU_SOURCE
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
|
7
tools/build/feature/test-libslang-include-subdir.c
Normal file
7
tools/build/feature/test-libslang-include-subdir.c
Normal file
@ -0,0 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <slang/slang.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return SLsmg_init_smg();
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#define _GNU_SOURCE
|
||||
#include <sched.h>
|
||||
|
||||
|
@ -332,6 +332,10 @@ ifeq ($(feature-get_current_dir_name), 1)
|
||||
CFLAGS += -DHAVE_GET_CURRENT_DIR_NAME
|
||||
endif
|
||||
|
||||
ifeq ($(feature-gettid), 1)
|
||||
CFLAGS += -DHAVE_GETTID
|
||||
endif
|
||||
|
||||
ifdef NO_LIBELF
|
||||
NO_DWARF := 1
|
||||
NO_DEMANGLE := 1
|
||||
@ -640,11 +644,15 @@ endif
|
||||
|
||||
ifndef NO_SLANG
|
||||
ifneq ($(feature-libslang), 1)
|
||||
msg := $(warning slang not found, disables TUI support. Please install slang-devel, libslang-dev or libslang2-dev);
|
||||
NO_SLANG := 1
|
||||
else
|
||||
ifneq ($(feature-libslang-include-subdir), 1)
|
||||
msg := $(warning slang not found, disables TUI support. Please install slang-devel, libslang-dev or libslang2-dev);
|
||||
NO_SLANG := 1
|
||||
else
|
||||
CFLAGS += -DHAVE_SLANG_INCLUDE_SUBDIR
|
||||
endif
|
||||
endif
|
||||
ifndef NO_SLANG
|
||||
# Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
|
||||
CFLAGS += -I/usr/include/slang
|
||||
CFLAGS += -DHAVE_SLANG_SUPPORT
|
||||
EXTLIBS += -lslang
|
||||
$(call detected,CONFIG_SLANG)
|
||||
|
@ -162,20 +162,19 @@ static int cs_etm_set_option(struct auxtrace_record *itr,
|
||||
!cpu_map__has(online_cpus, i))
|
||||
continue;
|
||||
|
||||
switch (option) {
|
||||
case ETM_OPT_CTXTID:
|
||||
if (option & ETM_OPT_CTXTID) {
|
||||
err = cs_etm_set_context_id(itr, evsel, i);
|
||||
if (err)
|
||||
goto out;
|
||||
break;
|
||||
case ETM_OPT_TS:
|
||||
}
|
||||
if (option & ETM_OPT_TS) {
|
||||
err = cs_etm_set_timestamp(itr, evsel, i);
|
||||
if (err)
|
||||
goto out;
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
if (option & ~(ETM_OPT_CTXTID | ETM_OPT_TS))
|
||||
/* Nothing else is currently supported */
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
@ -398,11 +397,8 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
|
||||
if (!cpu_map__empty(cpus)) {
|
||||
perf_evsel__set_sample_bit(cs_etm_evsel, CPU);
|
||||
|
||||
err = cs_etm_set_option(itr, cs_etm_evsel, ETM_OPT_CTXTID);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = cs_etm_set_option(itr, cs_etm_evsel, ETM_OPT_TS);
|
||||
err = cs_etm_set_option(itr, cs_etm_evsel,
|
||||
ETM_OPT_CTXTID | ETM_OPT_TS);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
perf-y += util/
|
||||
perf-$(CONFIG_DWARF_UNWIND) += tests/
|
||||
perf-y += tests/
|
||||
|
@ -1,4 +1,4 @@
|
||||
perf-y += regs_load.o
|
||||
perf-y += dwarf-unwind.o
|
||||
perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
|
||||
|
||||
perf-y += arch-tests.o
|
||||
|
@ -9,6 +9,7 @@ struct test;
|
||||
int test__rdpmc(struct test *test __maybe_unused, int subtest);
|
||||
int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest);
|
||||
int test__insn_x86(struct test *test __maybe_unused, int subtest);
|
||||
int test__intel_pt_pkt_decoder(struct test *test, int subtest);
|
||||
int test__bp_modify(struct test *test, int subtest);
|
||||
|
||||
#ifdef HAVE_DWARF_UNWIND_SUPPORT
|
||||
|
@ -4,5 +4,5 @@ perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
|
||||
perf-y += arch-tests.o
|
||||
perf-y += rdpmc.o
|
||||
perf-y += perf-time-to-tsc.o
|
||||
perf-$(CONFIG_AUXTRACE) += insn-x86.o
|
||||
perf-$(CONFIG_AUXTRACE) += insn-x86.o intel-pt-pkt-decoder-test.o
|
||||
perf-$(CONFIG_X86_64) += bp-modify.o
|
||||
|
@ -23,6 +23,10 @@ struct test arch_tests[] = {
|
||||
.desc = "x86 instruction decoder - new instructions",
|
||||
.func = test__insn_x86,
|
||||
},
|
||||
{
|
||||
.desc = "Intel PT packet decoder",
|
||||
.func = test__intel_pt_pkt_decoder,
|
||||
},
|
||||
#endif
|
||||
#if defined(__x86_64__)
|
||||
{
|
||||
|
304
tools/perf/arch/x86/tests/intel-pt-pkt-decoder-test.c
Normal file
304
tools/perf/arch/x86/tests/intel-pt-pkt-decoder-test.c
Normal file
@ -0,0 +1,304 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "intel-pt-decoder/intel-pt-pkt-decoder.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "tests/tests.h"
|
||||
#include "arch-tests.h"
|
||||
|
||||
/**
|
||||
* struct test_data - Test data.
|
||||
* @len: number of bytes to decode
|
||||
* @bytes: bytes to decode
|
||||
* @ctx: packet context to decode
|
||||
* @packet: expected packet
|
||||
* @new_ctx: expected new packet context
|
||||
* @ctx_unchanged: the packet context must not change
|
||||
*/
|
||||
struct test_data {
|
||||
int len;
|
||||
u8 bytes[INTEL_PT_PKT_MAX_SZ];
|
||||
enum intel_pt_pkt_ctx ctx;
|
||||
struct intel_pt_pkt packet;
|
||||
enum intel_pt_pkt_ctx new_ctx;
|
||||
int ctx_unchanged;
|
||||
} data[] = {
|
||||
/* Padding Packet */
|
||||
{1, {0}, 0, {INTEL_PT_PAD, 0, 0}, 0, 1 },
|
||||
/* Short Taken/Not Taken Packet */
|
||||
{1, {4}, 0, {INTEL_PT_TNT, 1, 0}, 0, 0 },
|
||||
{1, {6}, 0, {INTEL_PT_TNT, 1, 0x20ULL << 58}, 0, 0 },
|
||||
{1, {0x80}, 0, {INTEL_PT_TNT, 6, 0}, 0, 0 },
|
||||
{1, {0xfe}, 0, {INTEL_PT_TNT, 6, 0x3fULL << 58}, 0, 0 },
|
||||
/* Long Taken/Not Taken Packet */
|
||||
{8, {0x02, 0xa3, 2}, 0, {INTEL_PT_TNT, 1, 0xa302ULL << 47}, 0, 0 },
|
||||
{8, {0x02, 0xa3, 3}, 0, {INTEL_PT_TNT, 1, 0x1a302ULL << 47}, 0, 0 },
|
||||
{8, {0x02, 0xa3, 0, 0, 0, 0, 0, 0x80}, 0, {INTEL_PT_TNT, 47, 0xa302ULL << 1}, 0, 0 },
|
||||
{8, {0x02, 0xa3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 0, {INTEL_PT_TNT, 47, 0xffffffffffffa302ULL << 1}, 0, 0 },
|
||||
/* Target IP Packet */
|
||||
{1, {0x0d}, 0, {INTEL_PT_TIP, 0, 0}, 0, 0 },
|
||||
{3, {0x2d, 1, 2}, 0, {INTEL_PT_TIP, 1, 0x201}, 0, 0 },
|
||||
{5, {0x4d, 1, 2, 3, 4}, 0, {INTEL_PT_TIP, 2, 0x4030201}, 0, 0 },
|
||||
{7, {0x6d, 1, 2, 3, 4, 5, 6}, 0, {INTEL_PT_TIP, 3, 0x60504030201}, 0, 0 },
|
||||
{7, {0x8d, 1, 2, 3, 4, 5, 6}, 0, {INTEL_PT_TIP, 4, 0x60504030201}, 0, 0 },
|
||||
{9, {0xcd, 1, 2, 3, 4, 5, 6, 7, 8}, 0, {INTEL_PT_TIP, 6, 0x807060504030201}, 0, 0 },
|
||||
/* Packet Generation Enable */
|
||||
{1, {0x11}, 0, {INTEL_PT_TIP_PGE, 0, 0}, 0, 0 },
|
||||
{3, {0x31, 1, 2}, 0, {INTEL_PT_TIP_PGE, 1, 0x201}, 0, 0 },
|
||||
{5, {0x51, 1, 2, 3, 4}, 0, {INTEL_PT_TIP_PGE, 2, 0x4030201}, 0, 0 },
|
||||
{7, {0x71, 1, 2, 3, 4, 5, 6}, 0, {INTEL_PT_TIP_PGE, 3, 0x60504030201}, 0, 0 },
|
||||
{7, {0x91, 1, 2, 3, 4, 5, 6}, 0, {INTEL_PT_TIP_PGE, 4, 0x60504030201}, 0, 0 },
|
||||
{9, {0xd1, 1, 2, 3, 4, 5, 6, 7, 8}, 0, {INTEL_PT_TIP_PGE, 6, 0x807060504030201}, 0, 0 },
|
||||
/* Packet Generation Disable */
|
||||
{1, {0x01}, 0, {INTEL_PT_TIP_PGD, 0, 0}, 0, 0 },
|
||||
{3, {0x21, 1, 2}, 0, {INTEL_PT_TIP_PGD, 1, 0x201}, 0, 0 },
|
||||
{5, {0x41, 1, 2, 3, 4}, 0, {INTEL_PT_TIP_PGD, 2, 0x4030201}, 0, 0 },
|
||||
{7, {0x61, 1, 2, 3, 4, 5, 6}, 0, {INTEL_PT_TIP_PGD, 3, 0x60504030201}, 0, 0 },
|
||||
{7, {0x81, 1, 2, 3, 4, 5, 6}, 0, {INTEL_PT_TIP_PGD, 4, 0x60504030201}, 0, 0 },
|
||||
{9, {0xc1, 1, 2, 3, 4, 5, 6, 7, 8}, 0, {INTEL_PT_TIP_PGD, 6, 0x807060504030201}, 0, 0 },
|
||||
/* Flow Update Packet */
|
||||
{1, {0x1d}, 0, {INTEL_PT_FUP, 0, 0}, 0, 0 },
|
||||
{3, {0x3d, 1, 2}, 0, {INTEL_PT_FUP, 1, 0x201}, 0, 0 },
|
||||
{5, {0x5d, 1, 2, 3, 4}, 0, {INTEL_PT_FUP, 2, 0x4030201}, 0, 0 },
|
||||
{7, {0x7d, 1, 2, 3, 4, 5, 6}, 0, {INTEL_PT_FUP, 3, 0x60504030201}, 0, 0 },
|
||||
{7, {0x9d, 1, 2, 3, 4, 5, 6}, 0, {INTEL_PT_FUP, 4, 0x60504030201}, 0, 0 },
|
||||
{9, {0xdd, 1, 2, 3, 4, 5, 6, 7, 8}, 0, {INTEL_PT_FUP, 6, 0x807060504030201}, 0, 0 },
|
||||
/* Paging Information Packet */
|
||||
{8, {0x02, 0x43, 2, 4, 6, 8, 10, 12}, 0, {INTEL_PT_PIP, 0, 0x60504030201}, 0, 0 },
|
||||
{8, {0x02, 0x43, 3, 4, 6, 8, 10, 12}, 0, {INTEL_PT_PIP, 0, 0x60504030201 | (1ULL << 63)}, 0, 0 },
|
||||
/* Mode Exec Packet */
|
||||
{2, {0x99, 0x00}, 0, {INTEL_PT_MODE_EXEC, 0, 16}, 0, 0 },
|
||||
{2, {0x99, 0x01}, 0, {INTEL_PT_MODE_EXEC, 0, 64}, 0, 0 },
|
||||
{2, {0x99, 0x02}, 0, {INTEL_PT_MODE_EXEC, 0, 32}, 0, 0 },
|
||||
/* Mode TSX Packet */
|
||||
{2, {0x99, 0x20}, 0, {INTEL_PT_MODE_TSX, 0, 0}, 0, 0 },
|
||||
{2, {0x99, 0x21}, 0, {INTEL_PT_MODE_TSX, 0, 1}, 0, 0 },
|
||||
{2, {0x99, 0x22}, 0, {INTEL_PT_MODE_TSX, 0, 2}, 0, 0 },
|
||||
/* Trace Stop Packet */
|
||||
{2, {0x02, 0x83}, 0, {INTEL_PT_TRACESTOP, 0, 0}, 0, 0 },
|
||||
/* Core:Bus Ratio Packet */
|
||||
{4, {0x02, 0x03, 0x12, 0}, 0, {INTEL_PT_CBR, 0, 0x12}, 0, 1 },
|
||||
/* Timestamp Counter Packet */
|
||||
{8, {0x19, 1, 2, 3, 4, 5, 6, 7}, 0, {INTEL_PT_TSC, 0, 0x7060504030201}, 0, 1 },
|
||||
/* Mini Time Counter Packet */
|
||||
{2, {0x59, 0x12}, 0, {INTEL_PT_MTC, 0, 0x12}, 0, 1 },
|
||||
/* TSC / MTC Alignment Packet */
|
||||
{7, {0x02, 0x73}, 0, {INTEL_PT_TMA, 0, 0}, 0, 1 },
|
||||
{7, {0x02, 0x73, 1, 2}, 0, {INTEL_PT_TMA, 0, 0x201}, 0, 1 },
|
||||
{7, {0x02, 0x73, 0, 0, 0, 0xff, 1}, 0, {INTEL_PT_TMA, 0x1ff, 0}, 0, 1 },
|
||||
{7, {0x02, 0x73, 0x80, 0xc0, 0, 0xff, 1}, 0, {INTEL_PT_TMA, 0x1ff, 0xc080}, 0, 1 },
|
||||
/* Cycle Count Packet */
|
||||
{1, {0x03}, 0, {INTEL_PT_CYC, 0, 0}, 0, 1 },
|
||||
{1, {0x0b}, 0, {INTEL_PT_CYC, 0, 1}, 0, 1 },
|
||||
{1, {0xfb}, 0, {INTEL_PT_CYC, 0, 0x1f}, 0, 1 },
|
||||
{2, {0x07, 2}, 0, {INTEL_PT_CYC, 0, 0x20}, 0, 1 },
|
||||
{2, {0xff, 0xfe}, 0, {INTEL_PT_CYC, 0, 0xfff}, 0, 1 },
|
||||
{3, {0x07, 1, 2}, 0, {INTEL_PT_CYC, 0, 0x1000}, 0, 1 },
|
||||
{3, {0xff, 0xff, 0xfe}, 0, {INTEL_PT_CYC, 0, 0x7ffff}, 0, 1 },
|
||||
{4, {0x07, 1, 1, 2}, 0, {INTEL_PT_CYC, 0, 0x80000}, 0, 1 },
|
||||
{4, {0xff, 0xff, 0xff, 0xfe}, 0, {INTEL_PT_CYC, 0, 0x3ffffff}, 0, 1 },
|
||||
{5, {0x07, 1, 1, 1, 2}, 0, {INTEL_PT_CYC, 0, 0x4000000}, 0, 1 },
|
||||
{5, {0xff, 0xff, 0xff, 0xff, 0xfe}, 0, {INTEL_PT_CYC, 0, 0x1ffffffff}, 0, 1 },
|
||||
{6, {0x07, 1, 1, 1, 1, 2}, 0, {INTEL_PT_CYC, 0, 0x200000000}, 0, 1 },
|
||||
{6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}, 0, {INTEL_PT_CYC, 0, 0xffffffffff}, 0, 1 },
|
||||
{7, {0x07, 1, 1, 1, 1, 1, 2}, 0, {INTEL_PT_CYC, 0, 0x10000000000}, 0, 1 },
|
||||
{7, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}, 0, {INTEL_PT_CYC, 0, 0x7fffffffffff}, 0, 1 },
|
||||
{8, {0x07, 1, 1, 1, 1, 1, 1, 2}, 0, {INTEL_PT_CYC, 0, 0x800000000000}, 0, 1 },
|
||||
{8, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}, 0, {INTEL_PT_CYC, 0, 0x3fffffffffffff}, 0, 1 },
|
||||
{9, {0x07, 1, 1, 1, 1, 1, 1, 1, 2}, 0, {INTEL_PT_CYC, 0, 0x40000000000000}, 0, 1 },
|
||||
{9, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}, 0, {INTEL_PT_CYC, 0, 0x1fffffffffffffff}, 0, 1 },
|
||||
{10, {0x07, 1, 1, 1, 1, 1, 1, 1, 1, 2}, 0, {INTEL_PT_CYC, 0, 0x2000000000000000}, 0, 1 },
|
||||
{10, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe}, 0, {INTEL_PT_CYC, 0, 0xffffffffffffffff}, 0, 1 },
|
||||
/* Virtual-Machine Control Structure Packet */
|
||||
{7, {0x02, 0xc8, 1, 2, 3, 4, 5}, 0, {INTEL_PT_VMCS, 5, 0x504030201}, 0, 0 },
|
||||
/* Overflow Packet */
|
||||
{2, {0x02, 0xf3}, 0, {INTEL_PT_OVF, 0, 0}, 0, 0 },
|
||||
{2, {0x02, 0xf3}, INTEL_PT_BLK_4_CTX, {INTEL_PT_OVF, 0, 0}, 0, 0 },
|
||||
{2, {0x02, 0xf3}, INTEL_PT_BLK_8_CTX, {INTEL_PT_OVF, 0, 0}, 0, 0 },
|
||||
/* Packet Stream Boundary*/
|
||||
{16, {0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82}, 0, {INTEL_PT_PSB, 0, 0}, 0, 0 },
|
||||
{16, {0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82}, INTEL_PT_BLK_4_CTX, {INTEL_PT_PSB, 0, 0}, 0, 0 },
|
||||
{16, {0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82}, INTEL_PT_BLK_8_CTX, {INTEL_PT_PSB, 0, 0}, 0, 0 },
|
||||
/* PSB End Packet */
|
||||
{2, {0x02, 0x23}, 0, {INTEL_PT_PSBEND, 0, 0}, 0, 0 },
|
||||
/* Maintenance Packet */
|
||||
{11, {0x02, 0xc3, 0x88, 1, 2, 3, 4, 5, 6, 7}, 0, {INTEL_PT_MNT, 0, 0x7060504030201}, 0, 1 },
|
||||
/* Write Data to PT Packet */
|
||||
{6, {0x02, 0x12, 1, 2, 3, 4}, 0, {INTEL_PT_PTWRITE, 0, 0x4030201}, 0, 0 },
|
||||
{10, {0x02, 0x32, 1, 2, 3, 4, 5, 6, 7, 8}, 0, {INTEL_PT_PTWRITE, 1, 0x807060504030201}, 0, 0 },
|
||||
{6, {0x02, 0x92, 1, 2, 3, 4}, 0, {INTEL_PT_PTWRITE_IP, 0, 0x4030201}, 0, 0 },
|
||||
{10, {0x02, 0xb2, 1, 2, 3, 4, 5, 6, 7, 8}, 0, {INTEL_PT_PTWRITE_IP, 1, 0x807060504030201}, 0, 0 },
|
||||
/* Execution Stop Packet */
|
||||
{2, {0x02, 0x62}, 0, {INTEL_PT_EXSTOP, 0, 0}, 0, 1 },
|
||||
{2, {0x02, 0xe2}, 0, {INTEL_PT_EXSTOP_IP, 0, 0}, 0, 1 },
|
||||
/* Monitor Wait Packet */
|
||||
{10, {0x02, 0xc2}, 0, {INTEL_PT_MWAIT, 0, 0}, 0, 0 },
|
||||
{10, {0x02, 0xc2, 1, 2, 3, 4, 5, 6, 7, 8}, 0, {INTEL_PT_MWAIT, 0, 0x807060504030201}, 0, 0 },
|
||||
{10, {0x02, 0xc2, 0xff, 2, 3, 4, 7, 6, 7, 8}, 0, {INTEL_PT_MWAIT, 0, 0x8070607040302ff}, 0, 0 },
|
||||
/* Power Entry Packet */
|
||||
{4, {0x02, 0x22}, 0, {INTEL_PT_PWRE, 0, 0}, 0, 1 },
|
||||
{4, {0x02, 0x22, 1, 2}, 0, {INTEL_PT_PWRE, 0, 0x0201}, 0, 1 },
|
||||
{4, {0x02, 0x22, 0x80, 0x34}, 0, {INTEL_PT_PWRE, 0, 0x3480}, 0, 1 },
|
||||
{4, {0x02, 0x22, 0x00, 0x56}, 0, {INTEL_PT_PWRE, 0, 0x5600}, 0, 1 },
|
||||
/* Power Exit Packet */
|
||||
{7, {0x02, 0xa2}, 0, {INTEL_PT_PWRX, 0, 0}, 0, 1 },
|
||||
{7, {0x02, 0xa2, 1, 2, 3, 4, 5}, 0, {INTEL_PT_PWRX, 0, 0x504030201}, 0, 1 },
|
||||
{7, {0x02, 0xa2, 0xff, 0xff, 0xff, 0xff, 0xff}, 0, {INTEL_PT_PWRX, 0, 0xffffffffff}, 0, 1 },
|
||||
/* Block Begin Packet */
|
||||
{3, {0x02, 0x63, 0x00}, 0, {INTEL_PT_BBP, 0, 0}, INTEL_PT_BLK_8_CTX, 0 },
|
||||
{3, {0x02, 0x63, 0x80}, 0, {INTEL_PT_BBP, 1, 0}, INTEL_PT_BLK_4_CTX, 0 },
|
||||
{3, {0x02, 0x63, 0x1f}, 0, {INTEL_PT_BBP, 0, 0x1f}, INTEL_PT_BLK_8_CTX, 0 },
|
||||
{3, {0x02, 0x63, 0x9f}, 0, {INTEL_PT_BBP, 1, 0x1f}, INTEL_PT_BLK_4_CTX, 0 },
|
||||
/* 4-byte Block Item Packet */
|
||||
{5, {0x04}, INTEL_PT_BLK_4_CTX, {INTEL_PT_BIP, 0, 0}, INTEL_PT_BLK_4_CTX, 0 },
|
||||
{5, {0xfc}, INTEL_PT_BLK_4_CTX, {INTEL_PT_BIP, 0x1f, 0}, INTEL_PT_BLK_4_CTX, 0 },
|
||||
{5, {0x04, 1, 2, 3, 4}, INTEL_PT_BLK_4_CTX, {INTEL_PT_BIP, 0, 0x04030201}, INTEL_PT_BLK_4_CTX, 0 },
|
||||
{5, {0xfc, 1, 2, 3, 4}, INTEL_PT_BLK_4_CTX, {INTEL_PT_BIP, 0x1f, 0x04030201}, INTEL_PT_BLK_4_CTX, 0 },
|
||||
/* 8-byte Block Item Packet */
|
||||
{9, {0x04}, INTEL_PT_BLK_8_CTX, {INTEL_PT_BIP, 0, 0}, INTEL_PT_BLK_8_CTX, 0 },
|
||||
{9, {0xfc}, INTEL_PT_BLK_8_CTX, {INTEL_PT_BIP, 0x1f, 0}, INTEL_PT_BLK_8_CTX, 0 },
|
||||
{9, {0x04, 1, 2, 3, 4, 5, 6, 7, 8}, INTEL_PT_BLK_8_CTX, {INTEL_PT_BIP, 0, 0x0807060504030201}, INTEL_PT_BLK_8_CTX, 0 },
|
||||
{9, {0xfc, 1, 2, 3, 4, 5, 6, 7, 8}, INTEL_PT_BLK_8_CTX, {INTEL_PT_BIP, 0x1f, 0x0807060504030201}, INTEL_PT_BLK_8_CTX, 0 },
|
||||
/* Block End Packet */
|
||||
{2, {0x02, 0x33}, INTEL_PT_BLK_4_CTX, {INTEL_PT_BEP, 0, 0}, 0, 0 },
|
||||
{2, {0x02, 0xb3}, INTEL_PT_BLK_4_CTX, {INTEL_PT_BEP_IP, 0, 0}, 0, 0 },
|
||||
{2, {0x02, 0x33}, INTEL_PT_BLK_8_CTX, {INTEL_PT_BEP, 0, 0}, 0, 0 },
|
||||
{2, {0x02, 0xb3}, INTEL_PT_BLK_8_CTX, {INTEL_PT_BEP_IP, 0, 0}, 0, 0 },
|
||||
/* Terminator */
|
||||
{0, {0}, 0, {0, 0, 0}, 0, 0 },
|
||||
};
|
||||
|
||||
static int dump_packet(struct intel_pt_pkt *packet, u8 *bytes, int len)
|
||||
{
|
||||
char desc[INTEL_PT_PKT_DESC_MAX];
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
pr_debug(" %02x", bytes[i]);
|
||||
for (; i < INTEL_PT_PKT_MAX_SZ; i++)
|
||||
pr_debug(" ");
|
||||
pr_debug(" ");
|
||||
ret = intel_pt_pkt_desc(packet, desc, INTEL_PT_PKT_DESC_MAX);
|
||||
if (ret < 0) {
|
||||
pr_debug("intel_pt_pkt_desc failed!\n");
|
||||
return TEST_FAIL;
|
||||
}
|
||||
pr_debug("%s\n", desc);
|
||||
|
||||
return TEST_OK;
|
||||
}
|
||||
|
||||
static void decoding_failed(struct test_data *d)
|
||||
{
|
||||
pr_debug("Decoding failed!\n");
|
||||
pr_debug("Decoding: ");
|
||||
dump_packet(&d->packet, d->bytes, d->len);
|
||||
}
|
||||
|
||||
static int fail(struct test_data *d, struct intel_pt_pkt *packet, int len,
|
||||
enum intel_pt_pkt_ctx new_ctx)
|
||||
{
|
||||
decoding_failed(d);
|
||||
|
||||
if (len != d->len)
|
||||
pr_debug("Expected length: %d Decoded length %d\n",
|
||||
d->len, len);
|
||||
|
||||
if (packet->type != d->packet.type)
|
||||
pr_debug("Expected type: %d Decoded type %d\n",
|
||||
d->packet.type, packet->type);
|
||||
|
||||
if (packet->count != d->packet.count)
|
||||
pr_debug("Expected count: %d Decoded count %d\n",
|
||||
d->packet.count, packet->count);
|
||||
|
||||
if (packet->payload != d->packet.payload)
|
||||
pr_debug("Expected payload: 0x%llx Decoded payload 0x%llx\n",
|
||||
(unsigned long long)d->packet.payload,
|
||||
(unsigned long long)packet->payload);
|
||||
|
||||
if (new_ctx != d->new_ctx)
|
||||
pr_debug("Expected packet context: %d Decoded packet context %d\n",
|
||||
d->new_ctx, new_ctx);
|
||||
|
||||
return TEST_FAIL;
|
||||
}
|
||||
|
||||
static int test_ctx_unchanged(struct test_data *d, struct intel_pt_pkt *packet,
|
||||
enum intel_pt_pkt_ctx ctx)
|
||||
{
|
||||
enum intel_pt_pkt_ctx old_ctx = ctx;
|
||||
|
||||
intel_pt_upd_pkt_ctx(packet, &ctx);
|
||||
|
||||
if (ctx != old_ctx) {
|
||||
decoding_failed(d);
|
||||
pr_debug("Packet context changed!\n");
|
||||
return TEST_FAIL;
|
||||
}
|
||||
|
||||
return TEST_OK;
|
||||
}
|
||||
|
||||
static int test_one(struct test_data *d)
|
||||
{
|
||||
struct intel_pt_pkt packet;
|
||||
enum intel_pt_pkt_ctx ctx = d->ctx;
|
||||
int ret;
|
||||
|
||||
memset(&packet, 0xff, sizeof(packet));
|
||||
|
||||
/* Decode a packet */
|
||||
ret = intel_pt_get_packet(d->bytes, d->len, &packet, &ctx);
|
||||
if (ret < 0 || ret > INTEL_PT_PKT_MAX_SZ) {
|
||||
decoding_failed(d);
|
||||
pr_debug("intel_pt_get_packet returned %d\n", ret);
|
||||
return TEST_FAIL;
|
||||
}
|
||||
|
||||
/* Some packets must always leave the packet context unchanged */
|
||||
if (d->ctx_unchanged) {
|
||||
int err;
|
||||
|
||||
err = test_ctx_unchanged(d, &packet, INTEL_PT_NO_CTX);
|
||||
if (err)
|
||||
return err;
|
||||
err = test_ctx_unchanged(d, &packet, INTEL_PT_BLK_4_CTX);
|
||||
if (err)
|
||||
return err;
|
||||
err = test_ctx_unchanged(d, &packet, INTEL_PT_BLK_8_CTX);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Compare to the expected values */
|
||||
if (ret != d->len || packet.type != d->packet.type ||
|
||||
packet.count != d->packet.count ||
|
||||
packet.payload != d->packet.payload || ctx != d->new_ctx)
|
||||
return fail(d, &packet, ret, ctx);
|
||||
|
||||
pr_debug("Decoded ok:");
|
||||
ret = dump_packet(&d->packet, d->bytes, d->len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This test feeds byte sequences to the Intel PT packet decoder and checks the
|
||||
* results. Changes to the packet context are also checked.
|
||||
*/
|
||||
int test__intel_pt_pkt_decoder(struct test *test __maybe_unused, int subtest __maybe_unused)
|
||||
{
|
||||
struct test_data *d = data;
|
||||
int ret;
|
||||
|
||||
for (d = data; d->len; d++) {
|
||||
ret = test_one(d);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return TEST_OK;
|
||||
}
|
@ -1239,7 +1239,7 @@ static size_t syscall_arg__scnprintf_augmented_string(struct syscall_arg *arg, c
|
||||
*/
|
||||
int consumed = sizeof(*augmented_arg) + augmented_arg->size;
|
||||
|
||||
arg->augmented.args += consumed;
|
||||
arg->augmented.args = ((void *)arg->augmented.args) + consumed;
|
||||
arg->augmented.size -= consumed;
|
||||
|
||||
return printed;
|
||||
@ -1527,13 +1527,12 @@ static int trace__read_syscall_info(struct trace *trace, int id)
|
||||
|
||||
static int trace__validate_ev_qualifier(struct trace *trace)
|
||||
{
|
||||
int err = 0, i;
|
||||
int err = 0;
|
||||
bool printed_invalid_prefix = false;
|
||||
size_t nr_allocated;
|
||||
struct str_node *pos;
|
||||
size_t nr_used = 0, nr_allocated = strlist__nr_entries(trace->ev_qualifier);
|
||||
|
||||
trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
|
||||
trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
|
||||
trace->ev_qualifier_ids.entries = malloc(nr_allocated *
|
||||
sizeof(trace->ev_qualifier_ids.entries[0]));
|
||||
|
||||
if (trace->ev_qualifier_ids.entries == NULL) {
|
||||
@ -1543,9 +1542,6 @@ static int trace__validate_ev_qualifier(struct trace *trace)
|
||||
goto out;
|
||||
}
|
||||
|
||||
nr_allocated = trace->ev_qualifier_ids.nr;
|
||||
i = 0;
|
||||
|
||||
strlist__for_each_entry(pos, trace->ev_qualifier) {
|
||||
const char *sc = pos->s;
|
||||
int id = syscalltbl__id(trace->sctbl, sc), match_next = -1;
|
||||
@ -1566,7 +1562,7 @@ static int trace__validate_ev_qualifier(struct trace *trace)
|
||||
continue;
|
||||
}
|
||||
matches:
|
||||
trace->ev_qualifier_ids.entries[i++] = id;
|
||||
trace->ev_qualifier_ids.entries[nr_used++] = id;
|
||||
if (match_next == -1)
|
||||
continue;
|
||||
|
||||
@ -1574,7 +1570,7 @@ static int trace__validate_ev_qualifier(struct trace *trace)
|
||||
id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next);
|
||||
if (id < 0)
|
||||
break;
|
||||
if (nr_allocated == trace->ev_qualifier_ids.nr) {
|
||||
if (nr_allocated == nr_used) {
|
||||
void *entries;
|
||||
|
||||
nr_allocated += 8;
|
||||
@ -1587,11 +1583,11 @@ static int trace__validate_ev_qualifier(struct trace *trace)
|
||||
}
|
||||
trace->ev_qualifier_ids.entries = entries;
|
||||
}
|
||||
trace->ev_qualifier_ids.nr++;
|
||||
trace->ev_qualifier_ids.entries[i++] = id;
|
||||
trace->ev_qualifier_ids.entries[nr_used++] = id;
|
||||
}
|
||||
}
|
||||
|
||||
trace->ev_qualifier_ids.nr = nr_used;
|
||||
out:
|
||||
if (printed_invalid_prefix)
|
||||
pr_debug("\n");
|
||||
|
@ -45,10 +45,12 @@
|
||||
static char jit_path[PATH_MAX];
|
||||
static void *marker_addr;
|
||||
|
||||
#ifndef HAVE_GETTID
|
||||
static inline pid_t gettid(void)
|
||||
{
|
||||
return (pid_t)syscall(__NR_gettid);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int get_e_machine(struct jitheader *hdr)
|
||||
{
|
||||
|
@ -1,3 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
perf-y += builtin-test.o
|
||||
perf-y += parse-events.o
|
||||
perf-y += dso-data.o
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
|
||||
* 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* bpf-script-example.c
|
||||
* Test basic LLVM building
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* bpf-script-test-kbuild.c
|
||||
* Test include from kernel header
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* bpf-script-test-prologue.c
|
||||
* Test BPF prologue
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* bpf-script-test-relocation.c
|
||||
* Test BPF loader checking relocation
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/epoll.h>
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/kernel.h>
|
||||
#include "tests.h"
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include "util/mem-events.h"
|
||||
#include "util/symbol.h"
|
||||
#include "linux/perf_event.h"
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include "cpumap.h"
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Arnaldo Carvalho de Melo <acme@kernel.org>, 2017
|
||||
|
||||
skip_if_no_perf_probe() {
|
||||
|
@ -1,6 +1,7 @@
|
||||
#!/bin/sh
|
||||
# Add vfs_getname probe to get syscall args filenames
|
||||
#
|
||||
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Arnaldo Carvalho de Melo <acme@kernel.org>, 2017
|
||||
|
||||
. $(dirname $0)/lib/probe.sh
|
||||
|
@ -7,6 +7,7 @@
|
||||
# This needs no debuginfo package, all is done using the libc ELF symtab
|
||||
# and the CFI info in the binaries.
|
||||
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Arnaldo Carvalho de Melo <acme@kernel.org>, 2017
|
||||
|
||||
. $(dirname $0)/lib/probe.sh
|
||||
|
@ -6,6 +6,7 @@
|
||||
# checks that that was captured by the vfs_getname probe in the generated
|
||||
# perf.data file, with the temp file name as the pathname argument.
|
||||
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Arnaldo Carvalho de Melo <acme@kernel.org>, 2017
|
||||
|
||||
. $(dirname $0)/lib/probe.sh
|
||||
|
@ -1,6 +1,8 @@
|
||||
#!/bin/sh
|
||||
# Zstd perf.data compression/decompression
|
||||
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
trace_file=$(mktemp /tmp/perf.data.XXX)
|
||||
perf_tool=perf
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
# that already handles "probe:vfs_getname" if present, and used in the
|
||||
# "open" syscall "filename" argument beautifier.
|
||||
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Arnaldo Carvalho de Melo <acme@kernel.org>, 2017
|
||||
|
||||
. $(dirname $0)/lib/probe.sh
|
||||
|
@ -10,7 +10,12 @@
|
||||
#ifndef HAVE_LONG_LONG
|
||||
#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SLANG_INCLUDE_SUBDIR
|
||||
#include <slang/slang.h>
|
||||
#else
|
||||
#include <slang.h>
|
||||
#endif
|
||||
|
||||
#if SLANG_VERSION < 20104
|
||||
#define slsmg_printf(msg, args...) \
|
||||
|
@ -589,6 +589,9 @@ const char *perf_evsel__name(struct perf_evsel *evsel)
|
||||
{
|
||||
char bf[128];
|
||||
|
||||
if (!evsel)
|
||||
goto out_unknown;
|
||||
|
||||
if (evsel->name)
|
||||
return evsel->name;
|
||||
|
||||
@ -628,7 +631,10 @@ const char *perf_evsel__name(struct perf_evsel *evsel)
|
||||
|
||||
evsel->name = strdup(bf);
|
||||
|
||||
return evsel->name ?: "unknown";
|
||||
if (evsel->name)
|
||||
return evsel->name;
|
||||
out_unknown:
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
const char *perf_evsel__group_name(struct perf_evsel *evsel)
|
||||
|
@ -133,6 +133,10 @@ struct intel_pt_decoder {
|
||||
int mtc_shift;
|
||||
struct intel_pt_stack stack;
|
||||
enum intel_pt_pkt_state pkt_state;
|
||||
enum intel_pt_pkt_ctx pkt_ctx;
|
||||
enum intel_pt_pkt_ctx prev_pkt_ctx;
|
||||
enum intel_pt_blk_type blk_type;
|
||||
int blk_type_pos;
|
||||
struct intel_pt_pkt packet;
|
||||
struct intel_pt_pkt tnt;
|
||||
int pkt_step;
|
||||
@ -166,6 +170,7 @@ struct intel_pt_decoder {
|
||||
bool set_fup_mwait;
|
||||
bool set_fup_pwre;
|
||||
bool set_fup_exstop;
|
||||
bool set_fup_bep;
|
||||
bool sample_cyc;
|
||||
unsigned int fup_tx_flags;
|
||||
unsigned int tx_flags;
|
||||
@ -559,7 +564,8 @@ static int intel_pt_get_split_packet(struct intel_pt_decoder *decoder)
|
||||
memcpy(buf + len, decoder->buf, n);
|
||||
len += n;
|
||||
|
||||
ret = intel_pt_get_packet(buf, len, &decoder->packet);
|
||||
decoder->prev_pkt_ctx = decoder->pkt_ctx;
|
||||
ret = intel_pt_get_packet(buf, len, &decoder->packet, &decoder->pkt_ctx);
|
||||
if (ret < (int)old_len) {
|
||||
decoder->next_buf = decoder->buf;
|
||||
decoder->next_len = decoder->len;
|
||||
@ -594,6 +600,7 @@ static int intel_pt_pkt_lookahead(struct intel_pt_decoder *decoder,
|
||||
{
|
||||
struct intel_pt_pkt_info pkt_info;
|
||||
const unsigned char *buf = decoder->buf;
|
||||
enum intel_pt_pkt_ctx pkt_ctx = decoder->pkt_ctx;
|
||||
size_t len = decoder->len;
|
||||
int ret;
|
||||
|
||||
@ -612,7 +619,8 @@ static int intel_pt_pkt_lookahead(struct intel_pt_decoder *decoder,
|
||||
if (!len)
|
||||
return INTEL_PT_NEED_MORE_BYTES;
|
||||
|
||||
ret = intel_pt_get_packet(buf, len, &pkt_info.packet);
|
||||
ret = intel_pt_get_packet(buf, len, &pkt_info.packet,
|
||||
&pkt_ctx);
|
||||
if (!ret)
|
||||
return INTEL_PT_NEED_MORE_BYTES;
|
||||
if (ret < 0)
|
||||
@ -687,6 +695,10 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info)
|
||||
case INTEL_PT_MNT:
|
||||
case INTEL_PT_PTWRITE:
|
||||
case INTEL_PT_PTWRITE_IP:
|
||||
case INTEL_PT_BBP:
|
||||
case INTEL_PT_BIP:
|
||||
case INTEL_PT_BEP:
|
||||
case INTEL_PT_BEP_IP:
|
||||
return 0;
|
||||
|
||||
case INTEL_PT_MTC:
|
||||
@ -878,8 +890,9 @@ static int intel_pt_get_next_packet(struct intel_pt_decoder *decoder)
|
||||
return ret;
|
||||
}
|
||||
|
||||
decoder->prev_pkt_ctx = decoder->pkt_ctx;
|
||||
ret = intel_pt_get_packet(decoder->buf, decoder->len,
|
||||
&decoder->packet);
|
||||
&decoder->packet, &decoder->pkt_ctx);
|
||||
if (ret == INTEL_PT_NEED_MORE_BYTES && BITS_PER_LONG == 32 &&
|
||||
decoder->len < INTEL_PT_PKT_MAX_SZ && !decoder->next_buf) {
|
||||
ret = intel_pt_get_split_packet(decoder);
|
||||
@ -1117,6 +1130,14 @@ static bool intel_pt_fup_event(struct intel_pt_decoder *decoder)
|
||||
decoder->state.to_ip = 0;
|
||||
ret = true;
|
||||
}
|
||||
if (decoder->set_fup_bep) {
|
||||
decoder->set_fup_bep = false;
|
||||
decoder->state.type |= INTEL_PT_BLK_ITEMS;
|
||||
decoder->state.type &= ~INTEL_PT_BRANCH;
|
||||
decoder->state.from_ip = decoder->ip;
|
||||
decoder->state.to_ip = 0;
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1602,6 +1623,46 @@ static void intel_pt_calc_cyc_timestamp(struct intel_pt_decoder *decoder)
|
||||
intel_pt_log_to("Setting timestamp", decoder->timestamp);
|
||||
}
|
||||
|
||||
static void intel_pt_bbp(struct intel_pt_decoder *decoder)
|
||||
{
|
||||
if (decoder->prev_pkt_ctx == INTEL_PT_NO_CTX) {
|
||||
memset(decoder->state.items.mask, 0, sizeof(decoder->state.items.mask));
|
||||
decoder->state.items.is_32_bit = false;
|
||||
}
|
||||
decoder->blk_type = decoder->packet.payload;
|
||||
decoder->blk_type_pos = intel_pt_blk_type_pos(decoder->blk_type);
|
||||
if (decoder->blk_type == INTEL_PT_GP_REGS)
|
||||
decoder->state.items.is_32_bit = decoder->packet.count;
|
||||
if (decoder->blk_type_pos < 0) {
|
||||
intel_pt_log("WARNING: Unknown block type %u\n",
|
||||
decoder->blk_type);
|
||||
} else if (decoder->state.items.mask[decoder->blk_type_pos]) {
|
||||
intel_pt_log("WARNING: Duplicate block type %u\n",
|
||||
decoder->blk_type);
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_pt_bip(struct intel_pt_decoder *decoder)
|
||||
{
|
||||
uint32_t id = decoder->packet.count;
|
||||
uint32_t bit = 1 << id;
|
||||
int pos = decoder->blk_type_pos;
|
||||
|
||||
if (pos < 0 || id >= INTEL_PT_BLK_ITEM_ID_CNT) {
|
||||
intel_pt_log("WARNING: Unknown block item %u type %d\n",
|
||||
id, decoder->blk_type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (decoder->state.items.mask[pos] & bit) {
|
||||
intel_pt_log("WARNING: Duplicate block item %u type %d\n",
|
||||
id, decoder->blk_type);
|
||||
}
|
||||
|
||||
decoder->state.items.mask[pos] |= bit;
|
||||
decoder->state.items.val[pos][id] = decoder->packet.payload;
|
||||
}
|
||||
|
||||
/* Walk PSB+ packets when already in sync. */
|
||||
static int intel_pt_walk_psbend(struct intel_pt_decoder *decoder)
|
||||
{
|
||||
@ -1633,6 +1694,10 @@ static int intel_pt_walk_psbend(struct intel_pt_decoder *decoder)
|
||||
case INTEL_PT_MWAIT:
|
||||
case INTEL_PT_PWRE:
|
||||
case INTEL_PT_PWRX:
|
||||
case INTEL_PT_BBP:
|
||||
case INTEL_PT_BIP:
|
||||
case INTEL_PT_BEP:
|
||||
case INTEL_PT_BEP_IP:
|
||||
decoder->have_tma = false;
|
||||
intel_pt_log("ERROR: Unexpected packet\n");
|
||||
err = -EAGAIN;
|
||||
@ -1726,6 +1791,10 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder)
|
||||
case INTEL_PT_MWAIT:
|
||||
case INTEL_PT_PWRE:
|
||||
case INTEL_PT_PWRX:
|
||||
case INTEL_PT_BBP:
|
||||
case INTEL_PT_BIP:
|
||||
case INTEL_PT_BEP:
|
||||
case INTEL_PT_BEP_IP:
|
||||
intel_pt_log("ERROR: Missing TIP after FUP\n");
|
||||
decoder->pkt_state = INTEL_PT_STATE_ERR3;
|
||||
decoder->pkt_step = 0;
|
||||
@ -2047,6 +2116,33 @@ static int intel_pt_walk_trace(struct intel_pt_decoder *decoder)
|
||||
decoder->state.pwrx_payload = decoder->packet.payload;
|
||||
return 0;
|
||||
|
||||
case INTEL_PT_BBP:
|
||||
intel_pt_bbp(decoder);
|
||||
break;
|
||||
|
||||
case INTEL_PT_BIP:
|
||||
intel_pt_bip(decoder);
|
||||
break;
|
||||
|
||||
case INTEL_PT_BEP:
|
||||
decoder->state.type = INTEL_PT_BLK_ITEMS;
|
||||
decoder->state.from_ip = decoder->ip;
|
||||
decoder->state.to_ip = 0;
|
||||
return 0;
|
||||
|
||||
case INTEL_PT_BEP_IP:
|
||||
err = intel_pt_get_next_packet(decoder);
|
||||
if (err)
|
||||
return err;
|
||||
if (decoder->packet.type == INTEL_PT_FUP) {
|
||||
decoder->set_fup_bep = true;
|
||||
no_tip = true;
|
||||
} else {
|
||||
intel_pt_log_at("ERROR: Missing FUP after BEP",
|
||||
decoder->pos);
|
||||
}
|
||||
goto next;
|
||||
|
||||
default:
|
||||
return intel_pt_bug(decoder);
|
||||
}
|
||||
@ -2085,6 +2181,10 @@ static int intel_pt_walk_psb(struct intel_pt_decoder *decoder)
|
||||
case INTEL_PT_MWAIT:
|
||||
case INTEL_PT_PWRE:
|
||||
case INTEL_PT_PWRX:
|
||||
case INTEL_PT_BBP:
|
||||
case INTEL_PT_BIP:
|
||||
case INTEL_PT_BEP:
|
||||
case INTEL_PT_BEP_IP:
|
||||
intel_pt_log("ERROR: Unexpected packet\n");
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
@ -2291,6 +2391,10 @@ static int intel_pt_walk_to_ip(struct intel_pt_decoder *decoder)
|
||||
case INTEL_PT_MWAIT:
|
||||
case INTEL_PT_PWRE:
|
||||
case INTEL_PT_PWRX:
|
||||
case INTEL_PT_BBP:
|
||||
case INTEL_PT_BIP:
|
||||
case INTEL_PT_BEP:
|
||||
case INTEL_PT_BEP_IP:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -2306,6 +2410,7 @@ static int intel_pt_sync_ip(struct intel_pt_decoder *decoder)
|
||||
decoder->set_fup_mwait = false;
|
||||
decoder->set_fup_pwre = false;
|
||||
decoder->set_fup_exstop = false;
|
||||
decoder->set_fup_bep = false;
|
||||
|
||||
if (!decoder->branch_enable) {
|
||||
decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
|
||||
@ -2641,11 +2746,12 @@ static unsigned char *intel_pt_last_psb(unsigned char *buf, size_t len)
|
||||
static bool intel_pt_next_tsc(unsigned char *buf, size_t len, uint64_t *tsc,
|
||||
size_t *rem)
|
||||
{
|
||||
enum intel_pt_pkt_ctx ctx = INTEL_PT_NO_CTX;
|
||||
struct intel_pt_pkt packet;
|
||||
int ret;
|
||||
|
||||
while (len) {
|
||||
ret = intel_pt_get_packet(buf, len, &packet);
|
||||
ret = intel_pt_get_packet(buf, len, &packet, &ctx);
|
||||
if (ret <= 0)
|
||||
return false;
|
||||
if (packet.type == INTEL_PT_TSC) {
|
||||
|
@ -30,6 +30,7 @@ enum intel_pt_sample_type {
|
||||
INTEL_PT_CBR_CHG = 1 << 8,
|
||||
INTEL_PT_TRACE_BEGIN = 1 << 9,
|
||||
INTEL_PT_TRACE_END = 1 << 10,
|
||||
INTEL_PT_BLK_ITEMS = 1 << 11,
|
||||
};
|
||||
|
||||
enum intel_pt_period_type {
|
||||
@ -61,6 +62,141 @@ enum intel_pt_param_flags {
|
||||
INTEL_PT_FUP_WITH_NLIP = 1 << 0,
|
||||
};
|
||||
|
||||
enum intel_pt_blk_type {
|
||||
INTEL_PT_GP_REGS = 1,
|
||||
INTEL_PT_PEBS_BASIC = 4,
|
||||
INTEL_PT_PEBS_MEM = 5,
|
||||
INTEL_PT_LBR_0 = 8,
|
||||
INTEL_PT_LBR_1 = 9,
|
||||
INTEL_PT_LBR_2 = 10,
|
||||
INTEL_PT_XMM = 16,
|
||||
INTEL_PT_BLK_TYPE_MAX
|
||||
};
|
||||
|
||||
/*
|
||||
* The block type numbers are not sequential but here they are given sequential
|
||||
* positions to avoid wasting space for array placement.
|
||||
*/
|
||||
enum intel_pt_blk_type_pos {
|
||||
INTEL_PT_GP_REGS_POS,
|
||||
INTEL_PT_PEBS_BASIC_POS,
|
||||
INTEL_PT_PEBS_MEM_POS,
|
||||
INTEL_PT_LBR_0_POS,
|
||||
INTEL_PT_LBR_1_POS,
|
||||
INTEL_PT_LBR_2_POS,
|
||||
INTEL_PT_XMM_POS,
|
||||
INTEL_PT_BLK_TYPE_CNT
|
||||
};
|
||||
|
||||
/* Get the array position for a block type */
|
||||
static inline int intel_pt_blk_type_pos(enum intel_pt_blk_type blk_type)
|
||||
{
|
||||
#define BLK_TYPE(bt) [INTEL_PT_##bt] = INTEL_PT_##bt##_POS + 1
|
||||
const int map[INTEL_PT_BLK_TYPE_MAX] = {
|
||||
BLK_TYPE(GP_REGS),
|
||||
BLK_TYPE(PEBS_BASIC),
|
||||
BLK_TYPE(PEBS_MEM),
|
||||
BLK_TYPE(LBR_0),
|
||||
BLK_TYPE(LBR_1),
|
||||
BLK_TYPE(LBR_2),
|
||||
BLK_TYPE(XMM),
|
||||
};
|
||||
#undef BLK_TYPE
|
||||
|
||||
return blk_type < INTEL_PT_BLK_TYPE_MAX ? map[blk_type] - 1 : -1;
|
||||
}
|
||||
|
||||
#define INTEL_PT_BLK_ITEM_ID_CNT 32
|
||||
|
||||
/*
|
||||
* Use unions so that the block items can be accessed by name or by array index.
|
||||
* There is an array of 32-bit masks for each block type, which indicate which
|
||||
* values are present. Then arrays of 32 64-bit values for each block type.
|
||||
*/
|
||||
struct intel_pt_blk_items {
|
||||
union {
|
||||
uint32_t mask[INTEL_PT_BLK_TYPE_CNT];
|
||||
struct {
|
||||
uint32_t has_rflags:1;
|
||||
uint32_t has_rip:1;
|
||||
uint32_t has_rax:1;
|
||||
uint32_t has_rcx:1;
|
||||
uint32_t has_rdx:1;
|
||||
uint32_t has_rbx:1;
|
||||
uint32_t has_rsp:1;
|
||||
uint32_t has_rbp:1;
|
||||
uint32_t has_rsi:1;
|
||||
uint32_t has_rdi:1;
|
||||
uint32_t has_r8:1;
|
||||
uint32_t has_r9:1;
|
||||
uint32_t has_r10:1;
|
||||
uint32_t has_r11:1;
|
||||
uint32_t has_r12:1;
|
||||
uint32_t has_r13:1;
|
||||
uint32_t has_r14:1;
|
||||
uint32_t has_r15:1;
|
||||
uint32_t has_unused_0:14;
|
||||
uint32_t has_ip:1;
|
||||
uint32_t has_applicable_counters:1;
|
||||
uint32_t has_timestamp:1;
|
||||
uint32_t has_unused_1:29;
|
||||
uint32_t has_mem_access_address:1;
|
||||
uint32_t has_mem_aux_info:1;
|
||||
uint32_t has_mem_access_latency:1;
|
||||
uint32_t has_tsx_aux_info:1;
|
||||
uint32_t has_unused_2:28;
|
||||
uint32_t has_lbr_0;
|
||||
uint32_t has_lbr_1;
|
||||
uint32_t has_lbr_2;
|
||||
uint32_t has_xmm;
|
||||
};
|
||||
};
|
||||
union {
|
||||
uint64_t val[INTEL_PT_BLK_TYPE_CNT][INTEL_PT_BLK_ITEM_ID_CNT];
|
||||
struct {
|
||||
struct {
|
||||
uint64_t rflags;
|
||||
uint64_t rip;
|
||||
uint64_t rax;
|
||||
uint64_t rcx;
|
||||
uint64_t rdx;
|
||||
uint64_t rbx;
|
||||
uint64_t rsp;
|
||||
uint64_t rbp;
|
||||
uint64_t rsi;
|
||||
uint64_t rdi;
|
||||
uint64_t r8;
|
||||
uint64_t r9;
|
||||
uint64_t r10;
|
||||
uint64_t r11;
|
||||
uint64_t r12;
|
||||
uint64_t r13;
|
||||
uint64_t r14;
|
||||
uint64_t r15;
|
||||
uint64_t unused_0[INTEL_PT_BLK_ITEM_ID_CNT - 18];
|
||||
};
|
||||
struct {
|
||||
uint64_t ip;
|
||||
uint64_t applicable_counters;
|
||||
uint64_t timestamp;
|
||||
uint64_t unused_1[INTEL_PT_BLK_ITEM_ID_CNT - 3];
|
||||
};
|
||||
struct {
|
||||
uint64_t mem_access_address;
|
||||
uint64_t mem_aux_info;
|
||||
uint64_t mem_access_latency;
|
||||
uint64_t tsx_aux_info;
|
||||
uint64_t unused_2[INTEL_PT_BLK_ITEM_ID_CNT - 4];
|
||||
};
|
||||
uint64_t lbr_0[INTEL_PT_BLK_ITEM_ID_CNT];
|
||||
uint64_t lbr_1[INTEL_PT_BLK_ITEM_ID_CNT];
|
||||
uint64_t lbr_2[INTEL_PT_BLK_ITEM_ID_CNT];
|
||||
uint64_t xmm[INTEL_PT_BLK_ITEM_ID_CNT];
|
||||
};
|
||||
};
|
||||
bool is_32_bit;
|
||||
};
|
||||
|
||||
struct intel_pt_state {
|
||||
enum intel_pt_sample_type type;
|
||||
int err;
|
||||
@ -81,6 +217,7 @@ struct intel_pt_state {
|
||||
enum intel_pt_insn_op insn_op;
|
||||
int insn_len;
|
||||
char insn[INTEL_PT_INSN_BUF_SZ];
|
||||
struct intel_pt_blk_items items;
|
||||
};
|
||||
|
||||
struct intel_pt_insn;
|
||||
|
@ -62,6 +62,10 @@ static const char * const packet_name[] = {
|
||||
[INTEL_PT_MWAIT] = "MWAIT",
|
||||
[INTEL_PT_PWRE] = "PWRE",
|
||||
[INTEL_PT_PWRX] = "PWRX",
|
||||
[INTEL_PT_BBP] = "BBP",
|
||||
[INTEL_PT_BIP] = "BIP",
|
||||
[INTEL_PT_BEP] = "BEP",
|
||||
[INTEL_PT_BEP_IP] = "BEP",
|
||||
};
|
||||
|
||||
const char *intel_pt_pkt_name(enum intel_pt_pkt_type type)
|
||||
@ -280,6 +284,55 @@ static int intel_pt_get_pwrx(const unsigned char *buf, size_t len,
|
||||
return 7;
|
||||
}
|
||||
|
||||
static int intel_pt_get_bbp(const unsigned char *buf, size_t len,
|
||||
struct intel_pt_pkt *packet)
|
||||
{
|
||||
if (len < 3)
|
||||
return INTEL_PT_NEED_MORE_BYTES;
|
||||
packet->type = INTEL_PT_BBP;
|
||||
packet->count = buf[2] >> 7;
|
||||
packet->payload = buf[2] & 0x1f;
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int intel_pt_get_bip_4(const unsigned char *buf, size_t len,
|
||||
struct intel_pt_pkt *packet)
|
||||
{
|
||||
if (len < 5)
|
||||
return INTEL_PT_NEED_MORE_BYTES;
|
||||
packet->type = INTEL_PT_BIP;
|
||||
packet->count = buf[0] >> 3;
|
||||
memcpy_le64(&packet->payload, buf + 1, 4);
|
||||
return 5;
|
||||
}
|
||||
|
||||
static int intel_pt_get_bip_8(const unsigned char *buf, size_t len,
|
||||
struct intel_pt_pkt *packet)
|
||||
{
|
||||
if (len < 9)
|
||||
return INTEL_PT_NEED_MORE_BYTES;
|
||||
packet->type = INTEL_PT_BIP;
|
||||
packet->count = buf[0] >> 3;
|
||||
memcpy_le64(&packet->payload, buf + 1, 8);
|
||||
return 9;
|
||||
}
|
||||
|
||||
static int intel_pt_get_bep(size_t len, struct intel_pt_pkt *packet)
|
||||
{
|
||||
if (len < 2)
|
||||
return INTEL_PT_NEED_MORE_BYTES;
|
||||
packet->type = INTEL_PT_BEP;
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int intel_pt_get_bep_ip(size_t len, struct intel_pt_pkt *packet)
|
||||
{
|
||||
if (len < 2)
|
||||
return INTEL_PT_NEED_MORE_BYTES;
|
||||
packet->type = INTEL_PT_BEP_IP;
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int intel_pt_get_ext(const unsigned char *buf, size_t len,
|
||||
struct intel_pt_pkt *packet)
|
||||
{
|
||||
@ -320,6 +373,12 @@ static int intel_pt_get_ext(const unsigned char *buf, size_t len,
|
||||
return intel_pt_get_pwre(buf, len, packet);
|
||||
case 0xA2: /* PWRX */
|
||||
return intel_pt_get_pwrx(buf, len, packet);
|
||||
case 0x63: /* BBP */
|
||||
return intel_pt_get_bbp(buf, len, packet);
|
||||
case 0x33: /* BEP no IP */
|
||||
return intel_pt_get_bep(len, packet);
|
||||
case 0xb3: /* BEP with IP */
|
||||
return intel_pt_get_bep_ip(len, packet);
|
||||
default:
|
||||
return INTEL_PT_BAD_PACKET;
|
||||
}
|
||||
@ -468,7 +527,8 @@ static int intel_pt_get_mtc(const unsigned char *buf, size_t len,
|
||||
}
|
||||
|
||||
static int intel_pt_do_get_packet(const unsigned char *buf, size_t len,
|
||||
struct intel_pt_pkt *packet)
|
||||
struct intel_pt_pkt *packet,
|
||||
enum intel_pt_pkt_ctx ctx)
|
||||
{
|
||||
unsigned int byte;
|
||||
|
||||
@ -478,6 +538,22 @@ static int intel_pt_do_get_packet(const unsigned char *buf, size_t len,
|
||||
return INTEL_PT_NEED_MORE_BYTES;
|
||||
|
||||
byte = buf[0];
|
||||
|
||||
switch (ctx) {
|
||||
case INTEL_PT_NO_CTX:
|
||||
break;
|
||||
case INTEL_PT_BLK_4_CTX:
|
||||
if ((byte & 0x7) == 4)
|
||||
return intel_pt_get_bip_4(buf, len, packet);
|
||||
break;
|
||||
case INTEL_PT_BLK_8_CTX:
|
||||
if ((byte & 0x7) == 4)
|
||||
return intel_pt_get_bip_8(buf, len, packet);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
if (!(byte & BIT(0))) {
|
||||
if (byte == 0)
|
||||
return intel_pt_get_pad(packet);
|
||||
@ -516,15 +592,65 @@ static int intel_pt_do_get_packet(const unsigned char *buf, size_t len,
|
||||
}
|
||||
}
|
||||
|
||||
void intel_pt_upd_pkt_ctx(const struct intel_pt_pkt *packet,
|
||||
enum intel_pt_pkt_ctx *ctx)
|
||||
{
|
||||
switch (packet->type) {
|
||||
case INTEL_PT_BAD:
|
||||
case INTEL_PT_PAD:
|
||||
case INTEL_PT_TSC:
|
||||
case INTEL_PT_TMA:
|
||||
case INTEL_PT_MTC:
|
||||
case INTEL_PT_FUP:
|
||||
case INTEL_PT_CYC:
|
||||
case INTEL_PT_CBR:
|
||||
case INTEL_PT_MNT:
|
||||
case INTEL_PT_EXSTOP:
|
||||
case INTEL_PT_EXSTOP_IP:
|
||||
case INTEL_PT_PWRE:
|
||||
case INTEL_PT_PWRX:
|
||||
case INTEL_PT_BIP:
|
||||
break;
|
||||
case INTEL_PT_TNT:
|
||||
case INTEL_PT_TIP:
|
||||
case INTEL_PT_TIP_PGD:
|
||||
case INTEL_PT_TIP_PGE:
|
||||
case INTEL_PT_MODE_EXEC:
|
||||
case INTEL_PT_MODE_TSX:
|
||||
case INTEL_PT_PIP:
|
||||
case INTEL_PT_OVF:
|
||||
case INTEL_PT_VMCS:
|
||||
case INTEL_PT_TRACESTOP:
|
||||
case INTEL_PT_PSB:
|
||||
case INTEL_PT_PSBEND:
|
||||
case INTEL_PT_PTWRITE:
|
||||
case INTEL_PT_PTWRITE_IP:
|
||||
case INTEL_PT_MWAIT:
|
||||
case INTEL_PT_BEP:
|
||||
case INTEL_PT_BEP_IP:
|
||||
*ctx = INTEL_PT_NO_CTX;
|
||||
break;
|
||||
case INTEL_PT_BBP:
|
||||
if (packet->count)
|
||||
*ctx = INTEL_PT_BLK_4_CTX;
|
||||
else
|
||||
*ctx = INTEL_PT_BLK_8_CTX;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int intel_pt_get_packet(const unsigned char *buf, size_t len,
|
||||
struct intel_pt_pkt *packet)
|
||||
struct intel_pt_pkt *packet, enum intel_pt_pkt_ctx *ctx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = intel_pt_do_get_packet(buf, len, packet);
|
||||
ret = intel_pt_do_get_packet(buf, len, packet, *ctx);
|
||||
if (ret > 0) {
|
||||
while (ret < 8 && len > (size_t)ret && !buf[ret])
|
||||
ret += 1;
|
||||
intel_pt_upd_pkt_ctx(packet, ctx);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -602,8 +728,10 @@ int intel_pt_pkt_desc(const struct intel_pt_pkt *packet, char *buf,
|
||||
return snprintf(buf, buf_len, "%s 0x%llx IP:0", name, payload);
|
||||
case INTEL_PT_PTWRITE_IP:
|
||||
return snprintf(buf, buf_len, "%s 0x%llx IP:1", name, payload);
|
||||
case INTEL_PT_BEP:
|
||||
case INTEL_PT_EXSTOP:
|
||||
return snprintf(buf, buf_len, "%s IP:0", name);
|
||||
case INTEL_PT_BEP_IP:
|
||||
case INTEL_PT_EXSTOP_IP:
|
||||
return snprintf(buf, buf_len, "%s IP:1", name);
|
||||
case INTEL_PT_MWAIT:
|
||||
@ -621,6 +749,12 @@ int intel_pt_pkt_desc(const struct intel_pt_pkt *packet, char *buf,
|
||||
(unsigned int)((payload >> 4) & 0xf),
|
||||
(unsigned int)(payload & 0xf),
|
||||
(unsigned int)((payload >> 8) & 0xf));
|
||||
case INTEL_PT_BBP:
|
||||
return snprintf(buf, buf_len, "%s SZ %s-byte Type 0x%llx",
|
||||
name, packet->count ? "4" : "8", payload);
|
||||
case INTEL_PT_BIP:
|
||||
return snprintf(buf, buf_len, "%s ID 0x%02x Value 0x%llx",
|
||||
name, packet->count, payload);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -50,6 +50,10 @@ enum intel_pt_pkt_type {
|
||||
INTEL_PT_MWAIT,
|
||||
INTEL_PT_PWRE,
|
||||
INTEL_PT_PWRX,
|
||||
INTEL_PT_BBP,
|
||||
INTEL_PT_BIP,
|
||||
INTEL_PT_BEP,
|
||||
INTEL_PT_BEP_IP,
|
||||
};
|
||||
|
||||
struct intel_pt_pkt {
|
||||
@ -58,10 +62,25 @@ struct intel_pt_pkt {
|
||||
uint64_t payload;
|
||||
};
|
||||
|
||||
/*
|
||||
* Decoding of BIP packets conflicts with single-byte TNT packets. Since BIP
|
||||
* packets only occur in the context of a block (i.e. between BBP and BEP), that
|
||||
* context must be recorded and passed to the packet decoder.
|
||||
*/
|
||||
enum intel_pt_pkt_ctx {
|
||||
INTEL_PT_NO_CTX, /* BIP packets are invalid */
|
||||
INTEL_PT_BLK_4_CTX, /* 4-byte BIP packets */
|
||||
INTEL_PT_BLK_8_CTX, /* 8-byte BIP packets */
|
||||
};
|
||||
|
||||
const char *intel_pt_pkt_name(enum intel_pt_pkt_type);
|
||||
|
||||
int intel_pt_get_packet(const unsigned char *buf, size_t len,
|
||||
struct intel_pt_pkt *packet);
|
||||
struct intel_pt_pkt *packet,
|
||||
enum intel_pt_pkt_ctx *ctx);
|
||||
|
||||
void intel_pt_upd_pkt_ctx(const struct intel_pt_pkt *packet,
|
||||
enum intel_pt_pkt_ctx *ctx);
|
||||
|
||||
int intel_pt_pkt_desc(const struct intel_pt_pkt *packet, char *buf, size_t len);
|
||||
|
||||
|
@ -35,6 +35,8 @@
|
||||
#include "config.h"
|
||||
#include "time-utils.h"
|
||||
|
||||
#include "../arch/x86/include/uapi/asm/perf_regs.h"
|
||||
|
||||
#include "intel-pt-decoder/intel-pt-log.h"
|
||||
#include "intel-pt-decoder/intel-pt-decoder.h"
|
||||
#include "intel-pt-decoder/intel-pt-insn-decoder.h"
|
||||
@ -101,6 +103,9 @@ struct intel_pt {
|
||||
u64 pwrx_id;
|
||||
u64 cbr_id;
|
||||
|
||||
bool sample_pebs;
|
||||
struct perf_evsel *pebs_evsel;
|
||||
|
||||
u64 tsc_bit;
|
||||
u64 mtc_bit;
|
||||
u64 mtc_freq_bits;
|
||||
@ -177,13 +182,14 @@ static void intel_pt_dump(struct intel_pt *pt __maybe_unused,
|
||||
int ret, pkt_len, i;
|
||||
char desc[INTEL_PT_PKT_DESC_MAX];
|
||||
const char *color = PERF_COLOR_BLUE;
|
||||
enum intel_pt_pkt_ctx ctx = INTEL_PT_NO_CTX;
|
||||
|
||||
color_fprintf(stdout, color,
|
||||
". ... Intel Processor Trace data: size %zu bytes\n",
|
||||
len);
|
||||
|
||||
while (len) {
|
||||
ret = intel_pt_get_packet(buf, len, &packet);
|
||||
ret = intel_pt_get_packet(buf, len, &packet, &ctx);
|
||||
if (ret > 0)
|
||||
pkt_len = ret;
|
||||
else
|
||||
@ -1178,28 +1184,37 @@ static inline bool intel_pt_skip_event(struct intel_pt *pt)
|
||||
pt->num_events++ < pt->synth_opts.initial_skip;
|
||||
}
|
||||
|
||||
static void intel_pt_prep_a_sample(struct intel_pt_queue *ptq,
|
||||
union perf_event *event,
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
event->sample.header.type = PERF_RECORD_SAMPLE;
|
||||
event->sample.header.size = sizeof(struct perf_event_header);
|
||||
|
||||
sample->pid = ptq->pid;
|
||||
sample->tid = ptq->tid;
|
||||
sample->cpu = ptq->cpu;
|
||||
sample->insn_len = ptq->insn_len;
|
||||
memcpy(sample->insn, ptq->insn, INTEL_PT_INSN_BUF_SZ);
|
||||
}
|
||||
|
||||
static void intel_pt_prep_b_sample(struct intel_pt *pt,
|
||||
struct intel_pt_queue *ptq,
|
||||
union perf_event *event,
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
intel_pt_prep_a_sample(ptq, event, sample);
|
||||
|
||||
if (!pt->timeless_decoding)
|
||||
sample->time = tsc_to_perf_time(ptq->timestamp, &pt->tc);
|
||||
|
||||
sample->ip = ptq->state->from_ip;
|
||||
sample->cpumode = intel_pt_cpumode(pt, sample->ip);
|
||||
sample->pid = ptq->pid;
|
||||
sample->tid = ptq->tid;
|
||||
sample->addr = ptq->state->to_ip;
|
||||
sample->period = 1;
|
||||
sample->cpu = ptq->cpu;
|
||||
sample->flags = ptq->flags;
|
||||
sample->insn_len = ptq->insn_len;
|
||||
memcpy(sample->insn, ptq->insn, INTEL_PT_INSN_BUF_SZ);
|
||||
|
||||
event->sample.header.type = PERF_RECORD_SAMPLE;
|
||||
event->sample.header.misc = sample->cpumode;
|
||||
event->sample.header.size = sizeof(struct perf_event_header);
|
||||
}
|
||||
|
||||
static int intel_pt_inject_event(union perf_event *event,
|
||||
@ -1534,6 +1549,261 @@ static int intel_pt_synth_pwrx_sample(struct intel_pt_queue *ptq)
|
||||
pt->pwr_events_sample_type);
|
||||
}
|
||||
|
||||
/*
|
||||
* PEBS gp_regs array indexes plus 1 so that 0 means not present. Refer
|
||||
* intel_pt_add_gp_regs().
|
||||
*/
|
||||
static const int pebs_gp_regs[] = {
|
||||
[PERF_REG_X86_FLAGS] = 1,
|
||||
[PERF_REG_X86_IP] = 2,
|
||||
[PERF_REG_X86_AX] = 3,
|
||||
[PERF_REG_X86_CX] = 4,
|
||||
[PERF_REG_X86_DX] = 5,
|
||||
[PERF_REG_X86_BX] = 6,
|
||||
[PERF_REG_X86_SP] = 7,
|
||||
[PERF_REG_X86_BP] = 8,
|
||||
[PERF_REG_X86_SI] = 9,
|
||||
[PERF_REG_X86_DI] = 10,
|
||||
[PERF_REG_X86_R8] = 11,
|
||||
[PERF_REG_X86_R9] = 12,
|
||||
[PERF_REG_X86_R10] = 13,
|
||||
[PERF_REG_X86_R11] = 14,
|
||||
[PERF_REG_X86_R12] = 15,
|
||||
[PERF_REG_X86_R13] = 16,
|
||||
[PERF_REG_X86_R14] = 17,
|
||||
[PERF_REG_X86_R15] = 18,
|
||||
};
|
||||
|
||||
static u64 *intel_pt_add_gp_regs(struct regs_dump *intr_regs, u64 *pos,
|
||||
const struct intel_pt_blk_items *items,
|
||||
u64 regs_mask)
|
||||
{
|
||||
const u64 *gp_regs = items->val[INTEL_PT_GP_REGS_POS];
|
||||
u32 mask = items->mask[INTEL_PT_GP_REGS_POS];
|
||||
u32 bit;
|
||||
int i;
|
||||
|
||||
for (i = 0, bit = 1; i < PERF_REG_X86_64_MAX; i++, bit <<= 1) {
|
||||
/* Get the PEBS gp_regs array index */
|
||||
int n = pebs_gp_regs[i] - 1;
|
||||
|
||||
if (n < 0)
|
||||
continue;
|
||||
/*
|
||||
* Add only registers that were requested (i.e. 'regs_mask') and
|
||||
* that were provided (i.e. 'mask'), and update the resulting
|
||||
* mask (i.e. 'intr_regs->mask') accordingly.
|
||||
*/
|
||||
if (mask & 1 << n && regs_mask & bit) {
|
||||
intr_regs->mask |= bit;
|
||||
*pos++ = gp_regs[n];
|
||||
}
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
#ifndef PERF_REG_X86_XMM0
|
||||
#define PERF_REG_X86_XMM0 32
|
||||
#endif
|
||||
|
||||
static void intel_pt_add_xmm(struct regs_dump *intr_regs, u64 *pos,
|
||||
const struct intel_pt_blk_items *items,
|
||||
u64 regs_mask)
|
||||
{
|
||||
u32 mask = items->has_xmm & (regs_mask >> PERF_REG_X86_XMM0);
|
||||
const u64 *xmm = items->xmm;
|
||||
|
||||
/*
|
||||
* If there are any XMM registers, then there should be all of them.
|
||||
* Nevertheless, follow the logic to add only registers that were
|
||||
* requested (i.e. 'regs_mask') and that were provided (i.e. 'mask'),
|
||||
* and update the resulting mask (i.e. 'intr_regs->mask') accordingly.
|
||||
*/
|
||||
intr_regs->mask |= (u64)mask << PERF_REG_X86_XMM0;
|
||||
|
||||
for (; mask; mask >>= 1, xmm++) {
|
||||
if (mask & 1)
|
||||
*pos++ = *xmm;
|
||||
}
|
||||
}
|
||||
|
||||
#define LBR_INFO_MISPRED (1ULL << 63)
|
||||
#define LBR_INFO_IN_TX (1ULL << 62)
|
||||
#define LBR_INFO_ABORT (1ULL << 61)
|
||||
#define LBR_INFO_CYCLES 0xffff
|
||||
|
||||
/* Refer kernel's intel_pmu_store_pebs_lbrs() */
|
||||
static u64 intel_pt_lbr_flags(u64 info)
|
||||
{
|
||||
union {
|
||||
struct branch_flags flags;
|
||||
u64 result;
|
||||
} u = {
|
||||
.flags = {
|
||||
.mispred = !!(info & LBR_INFO_MISPRED),
|
||||
.predicted = !(info & LBR_INFO_MISPRED),
|
||||
.in_tx = !!(info & LBR_INFO_IN_TX),
|
||||
.abort = !!(info & LBR_INFO_ABORT),
|
||||
.cycles = info & LBR_INFO_CYCLES,
|
||||
}
|
||||
};
|
||||
|
||||
return u.result;
|
||||
}
|
||||
|
||||
static void intel_pt_add_lbrs(struct branch_stack *br_stack,
|
||||
const struct intel_pt_blk_items *items)
|
||||
{
|
||||
u64 *to;
|
||||
int i;
|
||||
|
||||
br_stack->nr = 0;
|
||||
|
||||
to = &br_stack->entries[0].from;
|
||||
|
||||
for (i = INTEL_PT_LBR_0_POS; i <= INTEL_PT_LBR_2_POS; i++) {
|
||||
u32 mask = items->mask[i];
|
||||
const u64 *from = items->val[i];
|
||||
|
||||
for (; mask; mask >>= 3, from += 3) {
|
||||
if ((mask & 7) == 7) {
|
||||
*to++ = from[0];
|
||||
*to++ = from[1];
|
||||
*to++ = intel_pt_lbr_flags(from[2]);
|
||||
br_stack->nr += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* INTEL_PT_LBR_0, INTEL_PT_LBR_1 and INTEL_PT_LBR_2 */
|
||||
#define LBRS_MAX (INTEL_PT_BLK_ITEM_ID_CNT * 3)
|
||||
|
||||
static int intel_pt_synth_pebs_sample(struct intel_pt_queue *ptq)
|
||||
{
|
||||
const struct intel_pt_blk_items *items = &ptq->state->items;
|
||||
struct perf_sample sample = { .ip = 0, };
|
||||
union perf_event *event = ptq->event_buf;
|
||||
struct intel_pt *pt = ptq->pt;
|
||||
struct perf_evsel *evsel = pt->pebs_evsel;
|
||||
u64 sample_type = evsel->attr.sample_type;
|
||||
u64 id = evsel->id[0];
|
||||
u8 cpumode;
|
||||
|
||||
if (intel_pt_skip_event(pt))
|
||||
return 0;
|
||||
|
||||
intel_pt_prep_a_sample(ptq, event, &sample);
|
||||
|
||||
sample.id = id;
|
||||
sample.stream_id = id;
|
||||
|
||||
if (!evsel->attr.freq)
|
||||
sample.period = evsel->attr.sample_period;
|
||||
|
||||
/* No support for non-zero CS base */
|
||||
if (items->has_ip)
|
||||
sample.ip = items->ip;
|
||||
else if (items->has_rip)
|
||||
sample.ip = items->rip;
|
||||
else
|
||||
sample.ip = ptq->state->from_ip;
|
||||
|
||||
/* No support for guest mode at this time */
|
||||
cpumode = sample.ip < ptq->pt->kernel_start ?
|
||||
PERF_RECORD_MISC_USER :
|
||||
PERF_RECORD_MISC_KERNEL;
|
||||
|
||||
event->sample.header.misc = cpumode | PERF_RECORD_MISC_EXACT_IP;
|
||||
|
||||
sample.cpumode = cpumode;
|
||||
|
||||
if (sample_type & PERF_SAMPLE_TIME) {
|
||||
u64 timestamp = 0;
|
||||
|
||||
if (items->has_timestamp)
|
||||
timestamp = items->timestamp;
|
||||
else if (!pt->timeless_decoding)
|
||||
timestamp = ptq->timestamp;
|
||||
if (timestamp)
|
||||
sample.time = tsc_to_perf_time(timestamp, &pt->tc);
|
||||
}
|
||||
|
||||
if (sample_type & PERF_SAMPLE_CALLCHAIN &&
|
||||
pt->synth_opts.callchain) {
|
||||
thread_stack__sample(ptq->thread, ptq->cpu, ptq->chain,
|
||||
pt->synth_opts.callchain_sz, sample.ip,
|
||||
pt->kernel_start);
|
||||
sample.callchain = ptq->chain;
|
||||
}
|
||||
|
||||
if (sample_type & PERF_SAMPLE_REGS_INTR &&
|
||||
items->mask[INTEL_PT_GP_REGS_POS]) {
|
||||
u64 regs[sizeof(sample.intr_regs.mask)];
|
||||
u64 regs_mask = evsel->attr.sample_regs_intr;
|
||||
u64 *pos;
|
||||
|
||||
sample.intr_regs.abi = items->is_32_bit ?
|
||||
PERF_SAMPLE_REGS_ABI_32 :
|
||||
PERF_SAMPLE_REGS_ABI_64;
|
||||
sample.intr_regs.regs = regs;
|
||||
|
||||
pos = intel_pt_add_gp_regs(&sample.intr_regs, regs, items, regs_mask);
|
||||
|
||||
intel_pt_add_xmm(&sample.intr_regs, pos, items, regs_mask);
|
||||
}
|
||||
|
||||
if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
|
||||
struct {
|
||||
struct branch_stack br_stack;
|
||||
struct branch_entry entries[LBRS_MAX];
|
||||
} br;
|
||||
|
||||
if (items->mask[INTEL_PT_LBR_0_POS] ||
|
||||
items->mask[INTEL_PT_LBR_1_POS] ||
|
||||
items->mask[INTEL_PT_LBR_2_POS]) {
|
||||
intel_pt_add_lbrs(&br.br_stack, items);
|
||||
sample.branch_stack = &br.br_stack;
|
||||
} else if (pt->synth_opts.last_branch) {
|
||||
intel_pt_copy_last_branch_rb(ptq);
|
||||
sample.branch_stack = ptq->last_branch;
|
||||
} else {
|
||||
br.br_stack.nr = 0;
|
||||
sample.branch_stack = &br.br_stack;
|
||||
}
|
||||
}
|
||||
|
||||
if (sample_type & PERF_SAMPLE_ADDR && items->has_mem_access_address)
|
||||
sample.addr = items->mem_access_address;
|
||||
|
||||
if (sample_type & PERF_SAMPLE_WEIGHT) {
|
||||
/*
|
||||
* Refer kernel's setup_pebs_adaptive_sample_data() and
|
||||
* intel_hsw_weight().
|
||||
*/
|
||||
if (items->has_mem_access_latency)
|
||||
sample.weight = items->mem_access_latency;
|
||||
if (!sample.weight && items->has_tsx_aux_info) {
|
||||
/* Cycles last block */
|
||||
sample.weight = (u32)items->tsx_aux_info;
|
||||
}
|
||||
}
|
||||
|
||||
if (sample_type & PERF_SAMPLE_TRANSACTION && items->has_tsx_aux_info) {
|
||||
u64 ax = items->has_rax ? items->rax : 0;
|
||||
/* Refer kernel's intel_hsw_transaction() */
|
||||
u64 txn = (u8)(items->tsx_aux_info >> 32);
|
||||
|
||||
/* For RTM XABORTs also log the abort code from AX */
|
||||
if (txn & PERF_TXN_TRANSACTION && ax & 1)
|
||||
txn |= ((ax >> 24) & 0xff) << PERF_TXN_ABORT_SHIFT;
|
||||
sample.transaction = txn;
|
||||
}
|
||||
|
||||
return intel_pt_deliver_synth_event(pt, ptq, event, &sample, sample_type);
|
||||
}
|
||||
|
||||
static int intel_pt_synth_error(struct intel_pt *pt, int code, int cpu,
|
||||
pid_t pid, pid_t tid, u64 ip, u64 timestamp)
|
||||
{
|
||||
@ -1621,6 +1891,16 @@ static int intel_pt_sample(struct intel_pt_queue *ptq)
|
||||
ptq->ipc_cyc_cnt = ptq->state->tot_cyc_cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do PEBS first to allow for the possibility that the PEBS timestamp
|
||||
* precedes the current timestamp.
|
||||
*/
|
||||
if (pt->sample_pebs && state->type & INTEL_PT_BLK_ITEMS) {
|
||||
err = intel_pt_synth_pebs_sample(ptq);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (pt->sample_pwr_events && (state->type & INTEL_PT_PWR_EVT)) {
|
||||
if (state->type & INTEL_PT_CBR_CHG) {
|
||||
err = intel_pt_synth_cbr_sample(ptq);
|
||||
|
@ -709,9 +709,7 @@ static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
|
||||
{
|
||||
int i;
|
||||
struct pmu_events_map *map;
|
||||
struct pmu_event *pe;
|
||||
const char *name = pmu->name;
|
||||
const char *pname;
|
||||
|
||||
map = perf_pmu__find_map(pmu);
|
||||
if (!map)
|
||||
@ -722,28 +720,26 @@ static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
|
||||
*/
|
||||
i = 0;
|
||||
while (1) {
|
||||
const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu";
|
||||
struct pmu_event *pe = &map->table[i++];
|
||||
const char *pname = pe->pmu ? pe->pmu : cpu_name;
|
||||
|
||||
pe = &map->table[i++];
|
||||
if (!pe->name) {
|
||||
if (pe->metric_group || pe->metric_name)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_arm_pmu_core(name)) {
|
||||
pname = pe->pmu ? pe->pmu : "cpu";
|
||||
/*
|
||||
* uncore alias may be from different PMU
|
||||
* with common prefix
|
||||
*/
|
||||
if (pmu_is_uncore(name) &&
|
||||
!strncmp(pname, name, strlen(pname)))
|
||||
goto new_alias;
|
||||
|
||||
/*
|
||||
* uncore alias may be from different PMU
|
||||
* with common prefix
|
||||
*/
|
||||
if (pmu_is_uncore(name) &&
|
||||
!strncmp(pname, name, strlen(pname)))
|
||||
goto new_alias;
|
||||
|
||||
if (strcmp(pname, name))
|
||||
continue;
|
||||
}
|
||||
if (strcmp(pname, name))
|
||||
continue;
|
||||
|
||||
new_alias:
|
||||
/* need type casts to override 'const' */
|
||||
|
Loading…
Reference in New Issue
Block a user