forked from Minki/linux
New features:
- Port 'perf kvm stat' to PowerPC (Hemant Kumar) Infrastructure: - Use the 'feature-dump' target to do the feature checks just once and then add code to reuse that in the tests/make makefile, speeding up the 'make -C tools/perf build-test' target (Wang Nan) - Reduce the number of tests the 'build-test' target do to those that don't pollute the source tree (Arnaldo Carvalho de Melo) - Improve the output of the build tests a bit by aligning the name of the tests, more can be done to filter out uninteresting info in the output (Arnaldo Carvalho de Melo) - Add perf_evlist pointer to *info_priv_size(), more prep work for supporting the coresight architecture (Mathieu Poirier) - Improve the 'perf test bp_signal' test (Wang Nan) - Check environment before starting the BPF 'perf test', so that we can just 'Skip' older kernels instead of 'FAIL'ing them (Wang Nan) - Fix cpumode of synthesized buildid event (Wang Nan) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWq9VUAAoJENZQFvNTUqpAi0QP/2i7itD/P9wkGLsPb+HbNlX+ umTxbhdKkyLc9WI8hGfdXXtdHcdkHUAmuZ/DzMbOcnGUE0mJdL6dphslsm1VFslP Q9sAj43BjWddEKfka1ylos1u/nDhpdpRX7bkRaepA9Zl0P0BSPXv+S28GO3jttxX uadXN9K7Amsa8tibKicxgLTUhZH05lmhPO00xGHuhQ6EQHcaw8VDYUlA+Wrh+NIa jIVnRE5q/hBwOyFQR/1gal8N5w2vO0vCglQmGQTEDjgQVMf/cSZChUlVqtxcDxcu FIDE42+jAnbESmVkBHq2n8ZvNxHOVlG6hTqZOqeiqs+tyfw7fYnGf+tkFPgBIEXP hB/hwgCJVBbbYo5hzT12eBz7UeWwn1ljqTpTnBrCaOl05MwvN4bMAMFVBXPLQHtm 47AsyaOXEli9RaRwgdcYGVUhqIPTa2Ql2vPRb1PmQ3ugBqqLyUpYOox8WUYQv2g9 sd61KMoXxUiuNsoq0ZXXkjWBeEBz2joRQYrlBQ0tZR8m06UA8FXLUXFopAUZKHGh 7w8BTXRRCc9lEm/pWfHjVykObRlHew0qcDihybtMVsNGpUQzqKh7A8b2DmMvmRrJ BmnUBQA8kFiE4BJSdOdqwH8PpDRYpTCg0a6cyK4RDlm7isX2ho40edstspEO1N4n BUG1zE5SIPC1o1MSFxBn =CFBX -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo-2' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core Pull perf tooling changes from Arnaldo Carvalho de Melo: New features: - Port 'perf kvm stat' to PowerPC (Hemant Kumar) Infrastructure changes: - Use the 'feature-dump' target to do the feature checks just once and then add code to reuse that in the tests/make makefile, speeding up the 'make -C tools/perf build-test' target (Wang Nan) - Reduce the number of tests the 'build-test' target do to those that don't pollute the source tree (Arnaldo Carvalho de Melo) - Improve the output of the build tests a bit by aligning the name of the tests, more can be done to filter out uninteresting info in the output (Arnaldo Carvalho de Melo) - Add perf_evlist pointer to *info_priv_size(), more prep work for supporting the coresight architecture (Mathieu Poirier) - Improve the 'perf test bp_signal' test (Wang Nan) - Check environment before starting the BPF 'perf test', so that we can just 'Skip' older kernels instead of 'FAIL'ing them (Wang Nan) - Fix cpumode of synthesized buildid event (Wang Nan) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
d072b89d3b
@ -119,6 +119,14 @@ ifeq ($(feature-all), 1)
|
||||
# test-all.c passed - just set all the core feature flags to 1:
|
||||
#
|
||||
$(foreach feat,$(FEATURE_TESTS),$(call feature_set,$(feat)))
|
||||
#
|
||||
# test-all.c does not comprise these tests, so we need to
|
||||
# for this case to get features proper values
|
||||
#
|
||||
$(call feature_check,compile-32)
|
||||
$(call feature_check,compile-x32)
|
||||
$(call feature_check,bionic)
|
||||
$(call feature_check,libbabeltrace)
|
||||
else
|
||||
$(foreach feat,$(FEATURE_TESTS),$(call feature_check,$(feat)))
|
||||
endif
|
||||
|
@ -1,4 +1,6 @@
|
||||
#include <stdio.h>
|
||||
int main(void)
|
||||
{
|
||||
printf("Hello World!\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -75,10 +75,17 @@ clean:
|
||||
$(make)
|
||||
|
||||
#
|
||||
# The build-test target is not really parallel, don't print the jobs info:
|
||||
# The build-test target is not really parallel, don't print the jobs info,
|
||||
# it also uses only the tests/make targets that don't pollute the source
|
||||
# repository, i.e. that uses O= or builds the tarpkg outside the source
|
||||
# repo directories.
|
||||
#
|
||||
# For a full test, use:
|
||||
#
|
||||
# make -C tools/perf -f tests/make
|
||||
#
|
||||
build-test:
|
||||
@$(MAKE) SHUF=1 -f tests/make --no-print-directory
|
||||
@$(MAKE) SHUF=1 -f tests/make REUSE_FEATURES_DUMP=1 MK=Makefile --no-print-directory tarpkg out
|
||||
|
||||
#
|
||||
# All other targets get passed through:
|
||||
|
@ -1,3 +1,5 @@
|
||||
ifndef NO_DWARF
|
||||
PERF_HAVE_DWARF_REGS := 1
|
||||
endif
|
||||
|
||||
HAVE_KVM_STAT_SUPPORT := 1
|
||||
|
@ -1,5 +1,6 @@
|
||||
libperf-y += header.o
|
||||
libperf-y += sym-handling.o
|
||||
libperf-y += kvm-stat.o
|
||||
|
||||
libperf-$(CONFIG_DWARF) += dwarf-regs.o
|
||||
libperf-$(CONFIG_DWARF) += skip-callchain-idx.o
|
||||
|
123
tools/perf/arch/powerpc/util/book3s_hcalls.h
Normal file
123
tools/perf/arch/powerpc/util/book3s_hcalls.h
Normal file
@ -0,0 +1,123 @@
|
||||
#ifndef ARCH_PERF_BOOK3S_HV_HCALLS_H
|
||||
#define ARCH_PERF_BOOK3S_HV_HCALLS_H
|
||||
|
||||
/*
|
||||
* PowerPC HCALL codes : hcall code to name mapping
|
||||
*/
|
||||
#define kvm_trace_symbol_hcall \
|
||||
{0x4, "H_REMOVE"}, \
|
||||
{0x8, "H_ENTER"}, \
|
||||
{0xc, "H_READ"}, \
|
||||
{0x10, "H_CLEAR_MOD"}, \
|
||||
{0x14, "H_CLEAR_REF"}, \
|
||||
{0x18, "H_PROTECT"}, \
|
||||
{0x1c, "H_GET_TCE"}, \
|
||||
{0x20, "H_PUT_TCE"}, \
|
||||
{0x24, "H_SET_SPRG0"}, \
|
||||
{0x28, "H_SET_DABR"}, \
|
||||
{0x2c, "H_PAGE_INIT"}, \
|
||||
{0x30, "H_SET_ASR"}, \
|
||||
{0x34, "H_ASR_ON"}, \
|
||||
{0x38, "H_ASR_OFF"}, \
|
||||
{0x3c, "H_LOGICAL_CI_LOAD"}, \
|
||||
{0x40, "H_LOGICAL_CI_STORE"}, \
|
||||
{0x44, "H_LOGICAL_CACHE_LOAD"}, \
|
||||
{0x48, "H_LOGICAL_CACHE_STORE"}, \
|
||||
{0x4c, "H_LOGICAL_ICBI"}, \
|
||||
{0x50, "H_LOGICAL_DCBF"}, \
|
||||
{0x54, "H_GET_TERM_CHAR"}, \
|
||||
{0x58, "H_PUT_TERM_CHAR"}, \
|
||||
{0x5c, "H_REAL_TO_LOGICAL"}, \
|
||||
{0x60, "H_HYPERVISOR_DATA"}, \
|
||||
{0x64, "H_EOI"}, \
|
||||
{0x68, "H_CPPR"}, \
|
||||
{0x6c, "H_IPI"}, \
|
||||
{0x70, "H_IPOLL"}, \
|
||||
{0x74, "H_XIRR"}, \
|
||||
{0x78, "H_MIGRATE_DMA"}, \
|
||||
{0x7c, "H_PERFMON"}, \
|
||||
{0xdc, "H_REGISTER_VPA"}, \
|
||||
{0xe0, "H_CEDE"}, \
|
||||
{0xe4, "H_CONFER"}, \
|
||||
{0xe8, "H_PROD"}, \
|
||||
{0xec, "H_GET_PPP"}, \
|
||||
{0xf0, "H_SET_PPP"}, \
|
||||
{0xf4, "H_PURR"}, \
|
||||
{0xf8, "H_PIC"}, \
|
||||
{0xfc, "H_REG_CRQ"}, \
|
||||
{0x100, "H_FREE_CRQ"}, \
|
||||
{0x104, "H_VIO_SIGNAL"}, \
|
||||
{0x108, "H_SEND_CRQ"}, \
|
||||
{0x110, "H_COPY_RDMA"}, \
|
||||
{0x114, "H_REGISTER_LOGICAL_LAN"}, \
|
||||
{0x118, "H_FREE_LOGICAL_LAN"}, \
|
||||
{0x11c, "H_ADD_LOGICAL_LAN_BUFFER"}, \
|
||||
{0x120, "H_SEND_LOGICAL_LAN"}, \
|
||||
{0x124, "H_BULK_REMOVE"}, \
|
||||
{0x130, "H_MULTICAST_CTRL"}, \
|
||||
{0x134, "H_SET_XDABR"}, \
|
||||
{0x138, "H_STUFF_TCE"}, \
|
||||
{0x13c, "H_PUT_TCE_INDIRECT"}, \
|
||||
{0x14c, "H_CHANGE_LOGICAL_LAN_MAC"}, \
|
||||
{0x150, "H_VTERM_PARTNER_INFO"}, \
|
||||
{0x154, "H_REGISTER_VTERM"}, \
|
||||
{0x158, "H_FREE_VTERM"}, \
|
||||
{0x15c, "H_RESET_EVENTS"}, \
|
||||
{0x160, "H_ALLOC_RESOURCE"}, \
|
||||
{0x164, "H_FREE_RESOURCE"}, \
|
||||
{0x168, "H_MODIFY_QP"}, \
|
||||
{0x16c, "H_QUERY_QP"}, \
|
||||
{0x170, "H_REREGISTER_PMR"}, \
|
||||
{0x174, "H_REGISTER_SMR"}, \
|
||||
{0x178, "H_QUERY_MR"}, \
|
||||
{0x17c, "H_QUERY_MW"}, \
|
||||
{0x180, "H_QUERY_HCA"}, \
|
||||
{0x184, "H_QUERY_PORT"}, \
|
||||
{0x188, "H_MODIFY_PORT"}, \
|
||||
{0x18c, "H_DEFINE_AQP1"}, \
|
||||
{0x190, "H_GET_TRACE_BUFFER"}, \
|
||||
{0x194, "H_DEFINE_AQP0"}, \
|
||||
{0x198, "H_RESIZE_MR"}, \
|
||||
{0x19c, "H_ATTACH_MCQP"}, \
|
||||
{0x1a0, "H_DETACH_MCQP"}, \
|
||||
{0x1a4, "H_CREATE_RPT"}, \
|
||||
{0x1a8, "H_REMOVE_RPT"}, \
|
||||
{0x1ac, "H_REGISTER_RPAGES"}, \
|
||||
{0x1b0, "H_DISABLE_AND_GETC"}, \
|
||||
{0x1b4, "H_ERROR_DATA"}, \
|
||||
{0x1b8, "H_GET_HCA_INFO"}, \
|
||||
{0x1bc, "H_GET_PERF_COUNT"}, \
|
||||
{0x1c0, "H_MANAGE_TRACE"}, \
|
||||
{0x1d4, "H_FREE_LOGICAL_LAN_BUFFER"}, \
|
||||
{0x1d8, "H_POLL_PENDING"}, \
|
||||
{0x1e4, "H_QUERY_INT_STATE"}, \
|
||||
{0x244, "H_ILLAN_ATTRIBUTES"}, \
|
||||
{0x250, "H_MODIFY_HEA_QP"}, \
|
||||
{0x254, "H_QUERY_HEA_QP"}, \
|
||||
{0x258, "H_QUERY_HEA"}, \
|
||||
{0x25c, "H_QUERY_HEA_PORT"}, \
|
||||
{0x260, "H_MODIFY_HEA_PORT"}, \
|
||||
{0x264, "H_REG_BCMC"}, \
|
||||
{0x268, "H_DEREG_BCMC"}, \
|
||||
{0x26c, "H_REGISTER_HEA_RPAGES"}, \
|
||||
{0x270, "H_DISABLE_AND_GET_HEA"}, \
|
||||
{0x274, "H_GET_HEA_INFO"}, \
|
||||
{0x278, "H_ALLOC_HEA_RESOURCE"}, \
|
||||
{0x284, "H_ADD_CONN"}, \
|
||||
{0x288, "H_DEL_CONN"}, \
|
||||
{0x298, "H_JOIN"}, \
|
||||
{0x2a4, "H_VASI_STATE"}, \
|
||||
{0x2b0, "H_ENABLE_CRQ"}, \
|
||||
{0x2b8, "H_GET_EM_PARMS"}, \
|
||||
{0x2d0, "H_SET_MPP"}, \
|
||||
{0x2d4, "H_GET_MPP"}, \
|
||||
{0x2ec, "H_HOME_NODE_ASSOCIATIVITY"}, \
|
||||
{0x2f4, "H_BEST_ENERGY"}, \
|
||||
{0x2fc, "H_XIRR_X"}, \
|
||||
{0x300, "H_RANDOM"}, \
|
||||
{0x304, "H_COP"}, \
|
||||
{0x314, "H_GET_MPP_X"}, \
|
||||
{0x31c, "H_SET_MODE"}, \
|
||||
{0xf000, "H_RTAS"} \
|
||||
|
||||
#endif
|
33
tools/perf/arch/powerpc/util/book3s_hv_exits.h
Normal file
33
tools/perf/arch/powerpc/util/book3s_hv_exits.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef ARCH_PERF_BOOK3S_HV_EXITS_H
|
||||
#define ARCH_PERF_BOOK3S_HV_EXITS_H
|
||||
|
||||
/*
|
||||
* PowerPC Interrupt vectors : exit code to name mapping
|
||||
*/
|
||||
|
||||
#define kvm_trace_symbol_exit \
|
||||
{0x0, "RETURN_TO_HOST"}, \
|
||||
{0x100, "SYSTEM_RESET"}, \
|
||||
{0x200, "MACHINE_CHECK"}, \
|
||||
{0x300, "DATA_STORAGE"}, \
|
||||
{0x380, "DATA_SEGMENT"}, \
|
||||
{0x400, "INST_STORAGE"}, \
|
||||
{0x480, "INST_SEGMENT"}, \
|
||||
{0x500, "EXTERNAL"}, \
|
||||
{0x501, "EXTERNAL_LEVEL"}, \
|
||||
{0x502, "EXTERNAL_HV"}, \
|
||||
{0x600, "ALIGNMENT"}, \
|
||||
{0x700, "PROGRAM"}, \
|
||||
{0x800, "FP_UNAVAIL"}, \
|
||||
{0x900, "DECREMENTER"}, \
|
||||
{0x980, "HV_DECREMENTER"}, \
|
||||
{0xc00, "SYSCALL"}, \
|
||||
{0xd00, "TRACE"}, \
|
||||
{0xe00, "H_DATA_STORAGE"}, \
|
||||
{0xe20, "H_INST_STORAGE"}, \
|
||||
{0xe40, "H_EMUL_ASSIST"}, \
|
||||
{0xf00, "PERFMON"}, \
|
||||
{0xf20, "ALTIVEC"}, \
|
||||
{0xf40, "VSX"}
|
||||
|
||||
#endif
|
170
tools/perf/arch/powerpc/util/kvm-stat.c
Normal file
170
tools/perf/arch/powerpc/util/kvm-stat.c
Normal file
@ -0,0 +1,170 @@
|
||||
#include "util/kvm-stat.h"
|
||||
#include "util/parse-events.h"
|
||||
#include "util/debug.h"
|
||||
|
||||
#include "book3s_hv_exits.h"
|
||||
#include "book3s_hcalls.h"
|
||||
|
||||
#define NR_TPS 4
|
||||
|
||||
const char *vcpu_id_str = "vcpu_id";
|
||||
const int decode_str_len = 40;
|
||||
const char *kvm_entry_trace = "kvm_hv:kvm_guest_enter";
|
||||
const char *kvm_exit_trace = "kvm_hv:kvm_guest_exit";
|
||||
|
||||
define_exit_reasons_table(hv_exit_reasons, kvm_trace_symbol_exit);
|
||||
define_exit_reasons_table(hcall_reasons, kvm_trace_symbol_hcall);
|
||||
|
||||
/* Tracepoints specific to ppc_book3s_hv */
|
||||
const char *ppc_book3s_hv_kvm_tp[] = {
|
||||
"kvm_hv:kvm_guest_enter",
|
||||
"kvm_hv:kvm_guest_exit",
|
||||
"kvm_hv:kvm_hcall_enter",
|
||||
"kvm_hv:kvm_hcall_exit",
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* 1 extra placeholder for NULL */
|
||||
const char *kvm_events_tp[NR_TPS + 1];
|
||||
const char *kvm_exit_reason;
|
||||
|
||||
static void hcall_event_get_key(struct perf_evsel *evsel,
|
||||
struct perf_sample *sample,
|
||||
struct event_key *key)
|
||||
{
|
||||
key->info = 0;
|
||||
key->key = perf_evsel__intval(evsel, sample, "req");
|
||||
}
|
||||
|
||||
static const char *get_hcall_exit_reason(u64 exit_code)
|
||||
{
|
||||
struct exit_reasons_table *tbl = hcall_reasons;
|
||||
|
||||
while (tbl->reason != NULL) {
|
||||
if (tbl->exit_code == exit_code)
|
||||
return tbl->reason;
|
||||
tbl++;
|
||||
}
|
||||
|
||||
pr_debug("Unknown hcall code: %lld\n",
|
||||
(unsigned long long)exit_code);
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
static bool hcall_event_end(struct perf_evsel *evsel,
|
||||
struct perf_sample *sample __maybe_unused,
|
||||
struct event_key *key __maybe_unused)
|
||||
{
|
||||
return (!strcmp(evsel->name, kvm_events_tp[3]));
|
||||
}
|
||||
|
||||
static bool hcall_event_begin(struct perf_evsel *evsel,
|
||||
struct perf_sample *sample, struct event_key *key)
|
||||
{
|
||||
if (!strcmp(evsel->name, kvm_events_tp[2])) {
|
||||
hcall_event_get_key(evsel, sample, key);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
static void hcall_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
|
||||
struct event_key *key,
|
||||
char *decode)
|
||||
{
|
||||
const char *hcall_reason = get_hcall_exit_reason(key->key);
|
||||
|
||||
scnprintf(decode, decode_str_len, "%s", hcall_reason);
|
||||
}
|
||||
|
||||
static struct kvm_events_ops hcall_events = {
|
||||
.is_begin_event = hcall_event_begin,
|
||||
.is_end_event = hcall_event_end,
|
||||
.decode_key = hcall_event_decode_key,
|
||||
.name = "HCALL-EVENT",
|
||||
};
|
||||
|
||||
static struct kvm_events_ops exit_events = {
|
||||
.is_begin_event = exit_event_begin,
|
||||
.is_end_event = exit_event_end,
|
||||
.decode_key = exit_event_decode_key,
|
||||
.name = "VM-EXIT"
|
||||
};
|
||||
|
||||
struct kvm_reg_events_ops kvm_reg_events_ops[] = {
|
||||
{ .name = "vmexit", .ops = &exit_events },
|
||||
{ .name = "hcall", .ops = &hcall_events },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
const char * const kvm_skip_events[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
static int is_tracepoint_available(const char *str, struct perf_evlist *evlist)
|
||||
{
|
||||
struct parse_events_error err;
|
||||
int ret;
|
||||
|
||||
err.str = NULL;
|
||||
ret = parse_events(evlist, str, &err);
|
||||
if (err.str)
|
||||
pr_err("%s : %s\n", str, err.str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ppc__setup_book3s_hv(struct perf_kvm_stat *kvm,
|
||||
struct perf_evlist *evlist)
|
||||
{
|
||||
const char **events_ptr;
|
||||
int i, nr_tp = 0, err = -1;
|
||||
|
||||
/* Check for book3s_hv tracepoints */
|
||||
for (events_ptr = ppc_book3s_hv_kvm_tp; *events_ptr; events_ptr++) {
|
||||
err = is_tracepoint_available(*events_ptr, evlist);
|
||||
if (err)
|
||||
return -1;
|
||||
nr_tp++;
|
||||
}
|
||||
|
||||
for (i = 0; i < nr_tp; i++)
|
||||
kvm_events_tp[i] = ppc_book3s_hv_kvm_tp[i];
|
||||
|
||||
kvm_events_tp[i] = NULL;
|
||||
kvm_exit_reason = "trap";
|
||||
kvm->exit_reasons = hv_exit_reasons;
|
||||
kvm->exit_reasons_isa = "HV";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Wrapper to setup kvm tracepoints */
|
||||
static int ppc__setup_kvm_tp(struct perf_kvm_stat *kvm)
|
||||
{
|
||||
struct perf_evlist *evlist = perf_evlist__new();
|
||||
|
||||
if (evlist == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Right now, only supported on book3s_hv */
|
||||
return ppc__setup_book3s_hv(kvm, evlist);
|
||||
}
|
||||
|
||||
int setup_kvm_events_tp(struct perf_kvm_stat *kvm)
|
||||
{
|
||||
return ppc__setup_kvm_tp(kvm);
|
||||
}
|
||||
|
||||
int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid __maybe_unused)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ppc__setup_kvm_tp(kvm);
|
||||
if (ret) {
|
||||
kvm->exit_reasons = NULL;
|
||||
kvm->exit_reasons_isa = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "../../util/kvm-stat.h"
|
||||
#include <asm/kvm_perf.h>
|
||||
#include <asm/sie.h>
|
||||
|
||||
define_exit_reasons_table(sie_exit_reasons, sie_intercept_code);
|
||||
define_exit_reasons_table(sie_icpt_insn_codes, icpt_insn_codes);
|
||||
@ -18,6 +18,12 @@ define_exit_reasons_table(sie_sigp_order_codes, sigp_order_codes);
|
||||
define_exit_reasons_table(sie_diagnose_codes, diagnose_codes);
|
||||
define_exit_reasons_table(sie_icpt_prog_codes, icpt_prog_codes);
|
||||
|
||||
const char *vcpu_id_str = "id";
|
||||
const int decode_str_len = 40;
|
||||
const char *kvm_exit_reason = "icptcode";
|
||||
const char *kvm_entry_trace = "kvm:kvm_s390_sie_enter";
|
||||
const char *kvm_exit_trace = "kvm:kvm_s390_sie_exit";
|
||||
|
||||
static void event_icpt_insn_get_key(struct perf_evsel *evsel,
|
||||
struct perf_sample *sample,
|
||||
struct event_key *key)
|
||||
@ -73,7 +79,7 @@ static struct kvm_events_ops exit_events = {
|
||||
.name = "VM-EXIT"
|
||||
};
|
||||
|
||||
const char * const kvm_events_tp[] = {
|
||||
const char *kvm_events_tp[] = {
|
||||
"kvm:kvm_s390_sie_enter",
|
||||
"kvm:kvm_s390_sie_exit",
|
||||
"kvm:kvm_s390_intercept_instruction",
|
||||
|
@ -60,7 +60,9 @@ struct branch {
|
||||
u64 misc;
|
||||
};
|
||||
|
||||
static size_t intel_bts_info_priv_size(struct auxtrace_record *itr __maybe_unused)
|
||||
static size_t
|
||||
intel_bts_info_priv_size(struct auxtrace_record *itr __maybe_unused,
|
||||
struct perf_evlist *evlist __maybe_unused)
|
||||
{
|
||||
return INTEL_BTS_AUXTRACE_PRIV_SIZE;
|
||||
}
|
||||
|
@ -273,7 +273,9 @@ intel_pt_pmu_default_config(struct perf_pmu *intel_pt_pmu)
|
||||
return attr;
|
||||
}
|
||||
|
||||
static size_t intel_pt_info_priv_size(struct auxtrace_record *itr __maybe_unused)
|
||||
static size_t
|
||||
intel_pt_info_priv_size(struct auxtrace_record *itr __maybe_unused,
|
||||
struct perf_evlist *evlist __maybe_unused)
|
||||
{
|
||||
return INTEL_PT_AUXTRACE_PRIV_SIZE;
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "../../util/kvm-stat.h"
|
||||
#include <asm/kvm_perf.h>
|
||||
#include <asm/svm.h>
|
||||
#include <asm/vmx.h>
|
||||
#include <asm/kvm.h>
|
||||
|
||||
define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS);
|
||||
define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS);
|
||||
@ -11,6 +13,12 @@ static struct kvm_events_ops exit_events = {
|
||||
.name = "VM-EXIT"
|
||||
};
|
||||
|
||||
const char *vcpu_id_str = "vcpu_id";
|
||||
const int decode_str_len = 20;
|
||||
const char *kvm_exit_reason = "exit_reason";
|
||||
const char *kvm_entry_trace = "kvm:kvm_entry";
|
||||
const char *kvm_exit_trace = "kvm:kvm_exit";
|
||||
|
||||
/*
|
||||
* For the mmio events, we treat:
|
||||
* the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
|
||||
@ -65,7 +73,7 @@ static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
|
||||
struct event_key *key,
|
||||
char *decode)
|
||||
{
|
||||
scnprintf(decode, DECODE_STR_LEN, "%#lx:%s",
|
||||
scnprintf(decode, decode_str_len, "%#lx:%s",
|
||||
(unsigned long)key->key,
|
||||
key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R");
|
||||
}
|
||||
@ -109,7 +117,7 @@ static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
|
||||
struct event_key *key,
|
||||
char *decode)
|
||||
{
|
||||
scnprintf(decode, DECODE_STR_LEN, "%#llx:%s",
|
||||
scnprintf(decode, decode_str_len, "%#llx:%s",
|
||||
(unsigned long long)key->key,
|
||||
key->info ? "POUT" : "PIN");
|
||||
}
|
||||
@ -121,7 +129,7 @@ static struct kvm_events_ops ioport_events = {
|
||||
.name = "IO Port Access"
|
||||
};
|
||||
|
||||
const char * const kvm_events_tp[] = {
|
||||
const char *kvm_events_tp[] = {
|
||||
"kvm:kvm_entry",
|
||||
"kvm:kvm_exit",
|
||||
"kvm:kvm_mmio",
|
||||
|
@ -38,19 +38,7 @@ static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
|
||||
|
||||
static int build_id_cache__kcore_dir(char *dir, size_t sz)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct tm tm;
|
||||
char dt[32];
|
||||
|
||||
if (gettimeofday(&tv, NULL) || !localtime_r(&tv.tv_sec, &tm))
|
||||
return -1;
|
||||
|
||||
if (!strftime(dt, sizeof(dt), "%Y%m%d%H%M%S", &tm))
|
||||
return -1;
|
||||
|
||||
scnprintf(dir, sz, "%s%02u", dt, (unsigned)tv.tv_usec / 10000);
|
||||
|
||||
return 0;
|
||||
return fetch_current_timestamp(dir, sz);
|
||||
}
|
||||
|
||||
static bool same_kallsyms_reloc(const char *from_dir, char *to_dir)
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include <math.h>
|
||||
|
||||
#ifdef HAVE_KVM_STAT_SUPPORT
|
||||
#include <asm/kvm_perf.h>
|
||||
#include "util/kvm-stat.h"
|
||||
|
||||
void exit_event_get_key(struct perf_evsel *evsel,
|
||||
@ -38,12 +37,12 @@ void exit_event_get_key(struct perf_evsel *evsel,
|
||||
struct event_key *key)
|
||||
{
|
||||
key->info = 0;
|
||||
key->key = perf_evsel__intval(evsel, sample, KVM_EXIT_REASON);
|
||||
key->key = perf_evsel__intval(evsel, sample, kvm_exit_reason);
|
||||
}
|
||||
|
||||
bool kvm_exit_event(struct perf_evsel *evsel)
|
||||
{
|
||||
return !strcmp(evsel->name, KVM_EXIT_TRACE);
|
||||
return !strcmp(evsel->name, kvm_exit_trace);
|
||||
}
|
||||
|
||||
bool exit_event_begin(struct perf_evsel *evsel,
|
||||
@ -59,7 +58,7 @@ bool exit_event_begin(struct perf_evsel *evsel,
|
||||
|
||||
bool kvm_entry_event(struct perf_evsel *evsel)
|
||||
{
|
||||
return !strcmp(evsel->name, KVM_ENTRY_TRACE);
|
||||
return !strcmp(evsel->name, kvm_entry_trace);
|
||||
}
|
||||
|
||||
bool exit_event_end(struct perf_evsel *evsel,
|
||||
@ -91,7 +90,7 @@ void exit_event_decode_key(struct perf_kvm_stat *kvm,
|
||||
const char *exit_reason = get_exit_reason(kvm, key->exit_reasons,
|
||||
key->key);
|
||||
|
||||
scnprintf(decode, DECODE_STR_LEN, "%s", exit_reason);
|
||||
scnprintf(decode, decode_str_len, "%s", exit_reason);
|
||||
}
|
||||
|
||||
static bool register_kvm_events_ops(struct perf_kvm_stat *kvm)
|
||||
@ -357,7 +356,7 @@ static bool handle_end_event(struct perf_kvm_stat *kvm,
|
||||
time_diff = sample->time - time_begin;
|
||||
|
||||
if (kvm->duration && time_diff > kvm->duration) {
|
||||
char decode[DECODE_STR_LEN];
|
||||
char decode[decode_str_len];
|
||||
|
||||
kvm->events_ops->decode_key(kvm, &event->key, decode);
|
||||
if (!skip_event(decode)) {
|
||||
@ -385,7 +384,8 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, VCPU_ID);
|
||||
vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample,
|
||||
vcpu_id_str);
|
||||
thread__set_priv(thread, vcpu_record);
|
||||
}
|
||||
|
||||
@ -574,7 +574,7 @@ static void show_timeofday(void)
|
||||
|
||||
static void print_result(struct perf_kvm_stat *kvm)
|
||||
{
|
||||
char decode[DECODE_STR_LEN];
|
||||
char decode[decode_str_len];
|
||||
struct kvm_event *event;
|
||||
int vcpu = kvm->trace_vcpu;
|
||||
|
||||
@ -585,7 +585,7 @@ static void print_result(struct perf_kvm_stat *kvm)
|
||||
|
||||
pr_info("\n\n");
|
||||
print_vcpu_info(kvm);
|
||||
pr_info("%*s ", DECODE_STR_LEN, kvm->events_ops->name);
|
||||
pr_info("%*s ", decode_str_len, kvm->events_ops->name);
|
||||
pr_info("%10s ", "Samples");
|
||||
pr_info("%9s ", "Samples%");
|
||||
|
||||
@ -604,7 +604,7 @@ static void print_result(struct perf_kvm_stat *kvm)
|
||||
min = get_event_min(event, vcpu);
|
||||
|
||||
kvm->events_ops->decode_key(kvm, &event->key, decode);
|
||||
pr_info("%*s ", DECODE_STR_LEN, decode);
|
||||
pr_info("%*s ", decode_str_len, decode);
|
||||
pr_info("%10llu ", (unsigned long long)ecount);
|
||||
pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);
|
||||
pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);
|
||||
@ -1132,6 +1132,11 @@ exit:
|
||||
_p; \
|
||||
})
|
||||
|
||||
int __weak setup_kvm_events_tp(struct perf_kvm_stat *kvm __maybe_unused)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
|
||||
{
|
||||
@ -1148,7 +1153,14 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
|
||||
NULL
|
||||
};
|
||||
const char * const *events_tp;
|
||||
int ret;
|
||||
|
||||
events_tp_size = 0;
|
||||
ret = setup_kvm_events_tp(kvm);
|
||||
if (ret < 0) {
|
||||
pr_err("Unable to setup the kvm tracepoints\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (events_tp = kvm_events_tp; *events_tp; events_tp++)
|
||||
events_tp_size++;
|
||||
@ -1377,6 +1389,12 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
|
||||
/*
|
||||
* generate the event list
|
||||
*/
|
||||
err = setup_kvm_events_tp(kvm);
|
||||
if (err < 0) {
|
||||
pr_err("Unable to setup the kvm tracepoints\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
kvm->evlist = kvm_live_event_list();
|
||||
if (kvm->evlist == NULL) {
|
||||
err = -1;
|
||||
|
@ -49,7 +49,9 @@ struct record {
|
||||
const char *progname;
|
||||
int realtime_prio;
|
||||
bool no_buildid;
|
||||
bool no_buildid_set;
|
||||
bool no_buildid_cache;
|
||||
bool no_buildid_cache_set;
|
||||
bool buildid_all;
|
||||
unsigned long long samples;
|
||||
};
|
||||
@ -1097,10 +1099,12 @@ struct option __record_options[] = {
|
||||
OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"),
|
||||
OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
|
||||
"don't sample"),
|
||||
OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
|
||||
"do not update the buildid cache"),
|
||||
OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
|
||||
"do not collect buildids in perf.data"),
|
||||
OPT_BOOLEAN_SET('N', "no-buildid-cache", &record.no_buildid_cache,
|
||||
&record.no_buildid_cache_set,
|
||||
"do not update the buildid cache"),
|
||||
OPT_BOOLEAN_SET('B', "no-buildid", &record.no_buildid,
|
||||
&record.no_buildid_set,
|
||||
"do not collect buildids in perf.data"),
|
||||
OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
|
||||
"monitor event in cgroup name only",
|
||||
parse_cgroups),
|
||||
|
@ -61,50 +61,45 @@ endif
|
||||
|
||||
ifeq ($(LIBUNWIND_LIBS),)
|
||||
NO_LIBUNWIND := 1
|
||||
else
|
||||
#
|
||||
# For linking with debug library, run like:
|
||||
#
|
||||
# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
|
||||
#
|
||||
ifdef LIBUNWIND_DIR
|
||||
LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include
|
||||
LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib
|
||||
endif
|
||||
LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS)
|
||||
|
||||
# Set per-feature check compilation flags
|
||||
FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS)
|
||||
FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS)
|
||||
FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS)
|
||||
FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS)
|
||||
endif
|
||||
#
|
||||
# For linking with debug library, run like:
|
||||
#
|
||||
# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
|
||||
#
|
||||
ifdef LIBUNWIND_DIR
|
||||
LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include
|
||||
LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib
|
||||
endif
|
||||
LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS)
|
||||
|
||||
# Set per-feature check compilation flags
|
||||
FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS)
|
||||
FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS)
|
||||
FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS)
|
||||
FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS)
|
||||
|
||||
ifeq ($(NO_PERF_REGS),0)
|
||||
CFLAGS += -DHAVE_PERF_REGS_SUPPORT
|
||||
endif
|
||||
|
||||
ifndef NO_LIBELF
|
||||
# for linking with debug library, run like:
|
||||
# make DEBUG=1 LIBDW_DIR=/opt/libdw/
|
||||
ifdef LIBDW_DIR
|
||||
LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
|
||||
LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
|
||||
endif
|
||||
FEATURE_CHECK_CFLAGS-libdw-dwarf-unwind := $(LIBDW_CFLAGS)
|
||||
FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw
|
||||
# for linking with debug library, run like:
|
||||
# make DEBUG=1 LIBDW_DIR=/opt/libdw/
|
||||
ifdef LIBDW_DIR
|
||||
LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
|
||||
LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
|
||||
endif
|
||||
FEATURE_CHECK_CFLAGS-libdw-dwarf-unwind := $(LIBDW_CFLAGS)
|
||||
FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw
|
||||
|
||||
ifdef LIBBABELTRACE
|
||||
# for linking with debug library, run like:
|
||||
# make DEBUG=1 LIBBABELTRACE_DIR=/opt/libbabeltrace/
|
||||
ifdef LIBBABELTRACE_DIR
|
||||
LIBBABELTRACE_CFLAGS := -I$(LIBBABELTRACE_DIR)/include
|
||||
LIBBABELTRACE_LDFLAGS := -L$(LIBBABELTRACE_DIR)/lib
|
||||
endif
|
||||
FEATURE_CHECK_CFLAGS-libbabeltrace := $(LIBBABELTRACE_CFLAGS)
|
||||
FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf
|
||||
# for linking with debug library, run like:
|
||||
# make DEBUG=1 LIBBABELTRACE_DIR=/opt/libbabeltrace/
|
||||
ifdef LIBBABELTRACE_DIR
|
||||
LIBBABELTRACE_CFLAGS := -I$(LIBBABELTRACE_DIR)/include
|
||||
LIBBABELTRACE_LDFLAGS := -L$(LIBBABELTRACE_DIR)/lib
|
||||
endif
|
||||
FEATURE_CHECK_CFLAGS-libbabeltrace := $(LIBBABELTRACE_CFLAGS)
|
||||
FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf
|
||||
|
||||
FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/arch/$(ARCH)/include/uapi -I$(srctree)/include/uapi
|
||||
# include ARCH specific config
|
||||
@ -145,28 +140,26 @@ ifdef PARSER_DEBUG
|
||||
$(call detected_var,PARSER_DEBUG_FLEX)
|
||||
endif
|
||||
|
||||
ifndef NO_LIBPYTHON
|
||||
# Try different combinations to accommodate systems that only have
|
||||
# python[2][-config] in weird combinations but always preferring
|
||||
# python2 and python2-config as per pep-0394. If we catch a
|
||||
# python[-config] in version 3, the version check will kill it.
|
||||
PYTHON2 := $(if $(call get-executable,python2),python2,python)
|
||||
override PYTHON := $(call get-executable-or-default,PYTHON,$(PYTHON2))
|
||||
PYTHON2_CONFIG := \
|
||||
$(if $(call get-executable,$(PYTHON)-config),$(PYTHON)-config,python-config)
|
||||
override PYTHON_CONFIG := \
|
||||
$(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG))
|
||||
# Try different combinations to accommodate systems that only have
|
||||
# python[2][-config] in weird combinations but always preferring
|
||||
# python2 and python2-config as per pep-0394. If we catch a
|
||||
# python[-config] in version 3, the version check will kill it.
|
||||
PYTHON2 := $(if $(call get-executable,python2),python2,python)
|
||||
override PYTHON := $(call get-executable-or-default,PYTHON,$(PYTHON2))
|
||||
PYTHON2_CONFIG := \
|
||||
$(if $(call get-executable,$(PYTHON)-config),$(PYTHON)-config,python-config)
|
||||
override PYTHON_CONFIG := \
|
||||
$(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG))
|
||||
|
||||
PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
|
||||
PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
|
||||
|
||||
PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
|
||||
PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
|
||||
PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
|
||||
PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
|
||||
|
||||
FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS)
|
||||
FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS)
|
||||
FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS)
|
||||
FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS)
|
||||
endif
|
||||
FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS)
|
||||
FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS)
|
||||
FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS)
|
||||
FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS)
|
||||
|
||||
CFLAGS += -fno-omit-frame-pointer
|
||||
CFLAGS += -ggdb3
|
||||
|
@ -29,14 +29,59 @@
|
||||
|
||||
static int fd1;
|
||||
static int fd2;
|
||||
static int fd3;
|
||||
static int overflows;
|
||||
static int overflows_2;
|
||||
|
||||
volatile long the_var;
|
||||
|
||||
|
||||
/*
|
||||
* Use ASM to ensure watchpoint and breakpoint can be triggered
|
||||
* at one instruction.
|
||||
*/
|
||||
#if defined (__x86_64__)
|
||||
extern void __test_function(volatile long *ptr);
|
||||
asm (
|
||||
".globl __test_function\n"
|
||||
"__test_function:\n"
|
||||
"incq (%rdi)\n"
|
||||
"ret\n");
|
||||
#elif defined (__aarch64__)
|
||||
extern void __test_function(volatile long *ptr);
|
||||
asm (
|
||||
".globl __test_function\n"
|
||||
"__test_function:\n"
|
||||
"str x30, [x0]\n"
|
||||
"ret\n");
|
||||
|
||||
#else
|
||||
static void __test_function(volatile long *ptr)
|
||||
{
|
||||
*ptr = 0x1234;
|
||||
}
|
||||
#endif
|
||||
|
||||
__attribute__ ((noinline))
|
||||
static int test_function(void)
|
||||
{
|
||||
__test_function(&the_var);
|
||||
the_var++;
|
||||
return time(NULL);
|
||||
}
|
||||
|
||||
static void sig_handler_2(int signum __maybe_unused,
|
||||
siginfo_t *oh __maybe_unused,
|
||||
void *uc __maybe_unused)
|
||||
{
|
||||
overflows_2++;
|
||||
if (overflows_2 > 10) {
|
||||
ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
|
||||
ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
|
||||
ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void sig_handler(int signum __maybe_unused,
|
||||
siginfo_t *oh __maybe_unused,
|
||||
void *uc __maybe_unused)
|
||||
@ -54,10 +99,11 @@ static void sig_handler(int signum __maybe_unused,
|
||||
*/
|
||||
ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
|
||||
ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
|
||||
ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int bp_event(void *fn, int setup_signal)
|
||||
static int __event(bool is_x, void *addr, int signal)
|
||||
{
|
||||
struct perf_event_attr pe;
|
||||
int fd;
|
||||
@ -67,8 +113,8 @@ static int bp_event(void *fn, int setup_signal)
|
||||
pe.size = sizeof(struct perf_event_attr);
|
||||
|
||||
pe.config = 0;
|
||||
pe.bp_type = HW_BREAKPOINT_X;
|
||||
pe.bp_addr = (unsigned long) fn;
|
||||
pe.bp_type = is_x ? HW_BREAKPOINT_X : HW_BREAKPOINT_W;
|
||||
pe.bp_addr = (unsigned long) addr;
|
||||
pe.bp_len = sizeof(long);
|
||||
|
||||
pe.sample_period = 1;
|
||||
@ -86,17 +132,25 @@ static int bp_event(void *fn, int setup_signal)
|
||||
return TEST_FAIL;
|
||||
}
|
||||
|
||||
if (setup_signal) {
|
||||
fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
|
||||
fcntl(fd, F_SETSIG, SIGIO);
|
||||
fcntl(fd, F_SETOWN, getpid());
|
||||
}
|
||||
fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
|
||||
fcntl(fd, F_SETSIG, signal);
|
||||
fcntl(fd, F_SETOWN, getpid());
|
||||
|
||||
ioctl(fd, PERF_EVENT_IOC_RESET, 0);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int bp_event(void *addr, int signal)
|
||||
{
|
||||
return __event(true, addr, signal);
|
||||
}
|
||||
|
||||
static int wp_event(void *addr, int signal)
|
||||
{
|
||||
return __event(false, addr, signal);
|
||||
}
|
||||
|
||||
static long long bp_count(int fd)
|
||||
{
|
||||
long long count;
|
||||
@ -114,7 +168,7 @@ static long long bp_count(int fd)
|
||||
int test__bp_signal(int subtest __maybe_unused)
|
||||
{
|
||||
struct sigaction sa;
|
||||
long long count1, count2;
|
||||
long long count1, count2, count3;
|
||||
|
||||
/* setup SIGIO signal handler */
|
||||
memset(&sa, 0, sizeof(struct sigaction));
|
||||
@ -126,21 +180,52 @@ int test__bp_signal(int subtest __maybe_unused)
|
||||
return TEST_FAIL;
|
||||
}
|
||||
|
||||
sa.sa_sigaction = (void *) sig_handler_2;
|
||||
if (sigaction(SIGUSR1, &sa, NULL) < 0) {
|
||||
pr_debug("failed setting up signal handler 2\n");
|
||||
return TEST_FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* We create following events:
|
||||
*
|
||||
* fd1 - breakpoint event on test_function with SIGIO
|
||||
* fd1 - breakpoint event on __test_function with SIGIO
|
||||
* signal configured. We should get signal
|
||||
* notification each time the breakpoint is hit
|
||||
*
|
||||
* fd2 - breakpoint event on sig_handler without SIGIO
|
||||
* fd2 - breakpoint event on sig_handler with SIGUSR1
|
||||
* configured. We should get SIGUSR1 each time when
|
||||
* breakpoint is hit
|
||||
*
|
||||
* fd3 - watchpoint event on __test_function with SIGIO
|
||||
* configured.
|
||||
*
|
||||
* Following processing should happen:
|
||||
* - execute test_function
|
||||
* - fd1 event breakpoint hit -> count1 == 1
|
||||
* - SIGIO is delivered -> overflows == 1
|
||||
* - fd2 event breakpoint hit -> count2 == 1
|
||||
* Exec: Action: Result:
|
||||
* incq (%rdi) - fd1 event breakpoint hit -> count1 == 1
|
||||
* - SIGIO is delivered
|
||||
* sig_handler - fd2 event breakpoint hit -> count2 == 1
|
||||
* - SIGUSR1 is delivered
|
||||
* sig_handler_2 -> overflows_2 == 1 (nested signal)
|
||||
* sys_rt_sigreturn - return from sig_handler_2
|
||||
* overflows++ -> overflows = 1
|
||||
* sys_rt_sigreturn - return from sig_handler
|
||||
* incq (%rdi) - fd3 event watchpoint hit -> count3 == 1 (wp and bp in one insn)
|
||||
* - SIGIO is delivered
|
||||
* sig_handler - fd2 event breakpoint hit -> count2 == 2
|
||||
* - SIGUSR1 is delivered
|
||||
* sig_handler_2 -> overflows_2 == 2 (nested signal)
|
||||
* sys_rt_sigreturn - return from sig_handler_2
|
||||
* overflows++ -> overflows = 2
|
||||
* sys_rt_sigreturn - return from sig_handler
|
||||
* the_var++ - fd3 event watchpoint hit -> count3 == 2 (standalone watchpoint)
|
||||
* - SIGIO is delivered
|
||||
* sig_handler - fd2 event breakpoint hit -> count2 == 3
|
||||
* - SIGUSR1 is delivered
|
||||
* sig_handler_2 -> overflows_2 == 3 (nested signal)
|
||||
* sys_rt_sigreturn - return from sig_handler_2
|
||||
* overflows++ -> overflows == 3
|
||||
* sys_rt_sigreturn - return from sig_handler
|
||||
*
|
||||
* The test case check following error conditions:
|
||||
* - we get stuck in signal handler because of debug
|
||||
@ -152,11 +237,13 @@ int test__bp_signal(int subtest __maybe_unused)
|
||||
*
|
||||
*/
|
||||
|
||||
fd1 = bp_event(test_function, 1);
|
||||
fd2 = bp_event(sig_handler, 0);
|
||||
fd1 = bp_event(__test_function, SIGIO);
|
||||
fd2 = bp_event(sig_handler, SIGUSR1);
|
||||
fd3 = wp_event((void *)&the_var, SIGIO);
|
||||
|
||||
ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
|
||||
ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
|
||||
ioctl(fd3, PERF_EVENT_IOC_ENABLE, 0);
|
||||
|
||||
/*
|
||||
* Kick off the test by trigering 'fd1'
|
||||
@ -166,15 +253,18 @@ int test__bp_signal(int subtest __maybe_unused)
|
||||
|
||||
ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
|
||||
ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
|
||||
ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
|
||||
|
||||
count1 = bp_count(fd1);
|
||||
count2 = bp_count(fd2);
|
||||
count3 = bp_count(fd3);
|
||||
|
||||
close(fd1);
|
||||
close(fd2);
|
||||
close(fd3);
|
||||
|
||||
pr_debug("count1 %lld, count2 %lld, overflow %d\n",
|
||||
count1, count2, overflows);
|
||||
pr_debug("count1 %lld, count2 %lld, count3 %lld, overflow %d, overflows_2 %d\n",
|
||||
count1, count2, count3, overflows, overflows_2);
|
||||
|
||||
if (count1 != 1) {
|
||||
if (count1 == 11)
|
||||
@ -183,12 +273,18 @@ int test__bp_signal(int subtest __maybe_unused)
|
||||
pr_debug("failed: wrong count for bp1%lld\n", count1);
|
||||
}
|
||||
|
||||
if (overflows != 1)
|
||||
if (overflows != 3)
|
||||
pr_debug("failed: wrong overflow hit\n");
|
||||
|
||||
if (count2 != 1)
|
||||
if (overflows_2 != 3)
|
||||
pr_debug("failed: wrong overflow_2 hit\n");
|
||||
|
||||
if (count2 != 3)
|
||||
pr_debug("failed: wrong count for bp2\n");
|
||||
|
||||
return count1 == 1 && overflows == 1 && count2 == 1 ?
|
||||
if (count3 != 2)
|
||||
pr_debug("failed: wrong count for bp3\n");
|
||||
|
||||
return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ?
|
||||
TEST_OK : TEST_FAIL;
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <util/util.h>
|
||||
#include <util/bpf-loader.h>
|
||||
#include <util/evlist.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/filter.h>
|
||||
#include <bpf/bpf.h>
|
||||
#include "tests.h"
|
||||
#include "llvm.h"
|
||||
#include "debug.h"
|
||||
@ -243,6 +247,36 @@ const char *test__bpf_subtest_get_desc(int i)
|
||||
return bpf_testcase_table[i].desc;
|
||||
}
|
||||
|
||||
static int check_env(void)
|
||||
{
|
||||
int err;
|
||||
unsigned int kver_int;
|
||||
char license[] = "GPL";
|
||||
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
|
||||
err = fetch_kernel_version(&kver_int, NULL, 0);
|
||||
if (err) {
|
||||
pr_debug("Unable to get kernel version\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bpf_load_program(BPF_PROG_TYPE_KPROBE, insns,
|
||||
sizeof(insns) / sizeof(insns[0]),
|
||||
license, kver_int, NULL, 0);
|
||||
if (err < 0) {
|
||||
pr_err("Missing basic BPF support, skip this test: %s\n",
|
||||
strerror(errno));
|
||||
return err;
|
||||
}
|
||||
close(err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test__bpf(int i)
|
||||
{
|
||||
int err;
|
||||
@ -255,6 +289,9 @@ int test__bpf(int i)
|
||||
return TEST_SKIP;
|
||||
}
|
||||
|
||||
if (check_env())
|
||||
return TEST_SKIP;
|
||||
|
||||
err = __test__bpf(i);
|
||||
return err;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ else
|
||||
PERF := .
|
||||
PERF_O := $(PERF)
|
||||
O_OPT :=
|
||||
FULL_O := $(shell readlink -f $(PERF_O) || echo $(PERF_O))
|
||||
|
||||
ifneq ($(O),)
|
||||
FULL_O := $(shell readlink -f $(O) || echo $(O))
|
||||
@ -260,6 +261,8 @@ run := $(shell shuf -e $(run))
|
||||
run_O := $(shell shuf -e $(run_O))
|
||||
endif
|
||||
|
||||
max_width := $(shell echo $(run_O) | sed 's/ /\n/g' | wc -L)
|
||||
|
||||
ifdef DEBUG
|
||||
d := $(info run $(run))
|
||||
d := $(info run_O $(run_O))
|
||||
@ -273,7 +276,7 @@ $(run):
|
||||
$(call clean)
|
||||
@TMP_DEST=$$(mktemp -d); \
|
||||
cmd="cd $(PERF) && make -f $(MK) $(PARALLEL_OPT) $(O_OPT) DESTDIR=$$TMP_DEST $($@)"; \
|
||||
echo "- $@: $$cmd" && echo $$cmd > $@ && \
|
||||
printf "%*.*s: %s\n" $(max_width) $(max_width) "$@" "$$cmd" && echo $$cmd > $@ && \
|
||||
( eval $$cmd ) >> $@ 2>&1; \
|
||||
echo " test: $(call test,$@)" >> $@ 2>&1; \
|
||||
$(call test,$@) && \
|
||||
@ -284,7 +287,7 @@ $(run_O):
|
||||
@TMP_O=$$(mktemp -d); \
|
||||
TMP_DEST=$$(mktemp -d); \
|
||||
cmd="cd $(PERF) && make -f $(MK) $(PARALLEL_OPT) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \
|
||||
echo "- $@: $$cmd" && echo $$cmd > $@ && \
|
||||
printf "%*.*s: %s\n" $(max_width) $(max_width) "$@" "$$cmd" && echo $$cmd > $@ && \
|
||||
( eval $$cmd ) >> $@ 2>&1 && \
|
||||
echo " test: $(call test_O,$@)" >> $@ 2>&1; \
|
||||
$(call test_O,$@) && \
|
||||
@ -313,11 +316,43 @@ make_kernelsrc_tools:
|
||||
(make -C ../../tools $(PARALLEL_OPT) $(K_O_OPT) perf) > $@ 2>&1 && \
|
||||
test -x $(KERNEL_O)/tools/perf/perf && rm -f $@ || (cat $@ ; false)
|
||||
|
||||
FEATURES_DUMP_FILE := $(FULL_O)/BUILD_TEST_FEATURE_DUMP
|
||||
FEATURES_DUMP_FILE_STATIC := $(FULL_O)/BUILD_TEST_FEATURE_DUMP_STATIC
|
||||
|
||||
all: $(run) $(run_O) tarpkg make_kernelsrc make_kernelsrc_tools
|
||||
@echo OK
|
||||
@rm -f $(FEATURES_DUMP_FILE) $(FEATURES_DUMP_FILE_STATIC)
|
||||
|
||||
out: $(run_O)
|
||||
@echo OK
|
||||
@rm -f $(FEATURES_DUMP_FILE) $(FEATURES_DUMP_FILE_STATIC)
|
||||
|
||||
ifeq ($(REUSE_FEATURES_DUMP),1)
|
||||
$(FEATURES_DUMP_FILE):
|
||||
$(call clean)
|
||||
@cmd="cd $(PERF) && make FEATURE_DUMP_COPY=$@ $(O_OPT) feature-dump"; \
|
||||
echo "- $@: $$cmd" && echo $$cmd && \
|
||||
( eval $$cmd ) > /dev/null 2>&1
|
||||
|
||||
$(FEATURES_DUMP_FILE_STATIC):
|
||||
$(call clean)
|
||||
@cmd="cd $(PERF) && make FEATURE_DUMP_COPY=$@ $(O_OPT) LDFLAGS='-static' feature-dump"; \
|
||||
echo "- $@: $$cmd" && echo $$cmd && \
|
||||
( eval $$cmd ) > /dev/null 2>&1
|
||||
|
||||
# Add feature dump dependency for run/run_O targets
|
||||
$(foreach t,$(run) $(run_O),$(eval \
|
||||
$(t): $(if $(findstring make_static,$(t)),\
|
||||
$(FEATURES_DUMP_FILE_STATIC),\
|
||||
$(FEATURES_DUMP_FILE))))
|
||||
|
||||
# Append 'FEATURES_DUMP=' option to all test cases. For example:
|
||||
# make_no_libbpf: NO_LIBBPF=1 --> NO_LIBBPF=1 FEATURES_DUMP=/a/b/BUILD_TEST_FEATURE_DUMP
|
||||
# make_static: LDFLAGS=-static --> LDFLAGS=-static FEATURES_DUMP=/a/b/BUILD_TEST_FEATURE_DUMP_STATIC
|
||||
$(foreach t,$(run),$(if $(findstring make_static,$(t)),\
|
||||
$(eval $(t) := $($(t)) FEATURES_DUMP=$(FEATURES_DUMP_FILE_STATIC)),\
|
||||
$(eval $(t) := $($(t)) FEATURES_DUMP=$(FEATURES_DUMP_FILE))))
|
||||
endif
|
||||
|
||||
.PHONY: all $(run) $(run_O) tarpkg clean make_kernelsrc make_kernelsrc_tools
|
||||
endif # ifndef MK
|
||||
|
@ -478,10 +478,11 @@ void auxtrace_heap__pop(struct auxtrace_heap *heap)
|
||||
heap_array[last].ordinal);
|
||||
}
|
||||
|
||||
size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr)
|
||||
size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr,
|
||||
struct perf_evlist *evlist)
|
||||
{
|
||||
if (itr)
|
||||
return itr->info_priv_size(itr);
|
||||
return itr->info_priv_size(itr, evlist);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -852,7 +853,7 @@ int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr,
|
||||
int err;
|
||||
|
||||
pr_debug2("Synthesizing auxtrace information\n");
|
||||
priv_size = auxtrace_record__info_priv_size(itr);
|
||||
priv_size = auxtrace_record__info_priv_size(itr, session->evlist);
|
||||
ev = zalloc(sizeof(struct auxtrace_info_event) + priv_size);
|
||||
if (!ev)
|
||||
return -ENOMEM;
|
||||
|
@ -293,7 +293,8 @@ struct auxtrace_record {
|
||||
int (*recording_options)(struct auxtrace_record *itr,
|
||||
struct perf_evlist *evlist,
|
||||
struct record_opts *opts);
|
||||
size_t (*info_priv_size)(struct auxtrace_record *itr);
|
||||
size_t (*info_priv_size)(struct auxtrace_record *itr,
|
||||
struct perf_evlist *evlist);
|
||||
int (*info_fill)(struct auxtrace_record *itr,
|
||||
struct perf_session *session,
|
||||
struct auxtrace_info_event *auxtrace_info,
|
||||
@ -429,7 +430,8 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr,
|
||||
int auxtrace_record__options(struct auxtrace_record *itr,
|
||||
struct perf_evlist *evlist,
|
||||
struct record_opts *opts);
|
||||
size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr);
|
||||
size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr,
|
||||
struct perf_evlist *evlist);
|
||||
int auxtrace_record__info_fill(struct auxtrace_record *itr,
|
||||
struct perf_session *session,
|
||||
struct auxtrace_info_event *auxtrace_info,
|
||||
|
@ -211,6 +211,7 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
|
||||
dsos__for_each_with_build_id(pos, &machine->dsos.head) {
|
||||
const char *name;
|
||||
size_t name_len;
|
||||
bool in_kernel = false;
|
||||
|
||||
if (!pos->hit)
|
||||
continue;
|
||||
@ -227,8 +228,11 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
|
||||
name_len = pos->long_name_len + 1;
|
||||
}
|
||||
|
||||
in_kernel = pos->kernel ||
|
||||
is_kernel_module(name,
|
||||
PERF_RECORD_MISC_CPUMODE_UNKNOWN);
|
||||
err = write_buildid(name, name_len, pos->build_id, machine->pid,
|
||||
pos->kernel ? kmisc : umisc, fd);
|
||||
in_kernel ? kmisc : umisc, fd);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
@ -122,6 +122,7 @@ void exit_event_decode_key(struct perf_kvm_stat *kvm,
|
||||
|
||||
bool kvm_exit_event(struct perf_evsel *evsel);
|
||||
bool kvm_entry_event(struct perf_evsel *evsel);
|
||||
int setup_kvm_events_tp(struct perf_kvm_stat *kvm);
|
||||
|
||||
#define define_exit_reasons_table(name, symbols) \
|
||||
static struct exit_reasons_table name[] = { \
|
||||
@ -133,8 +134,13 @@ bool kvm_entry_event(struct perf_evsel *evsel);
|
||||
*/
|
||||
int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid);
|
||||
|
||||
extern const char * const kvm_events_tp[];
|
||||
extern const char *kvm_events_tp[];
|
||||
extern struct kvm_reg_events_ops kvm_reg_events_ops[];
|
||||
extern const char * const kvm_skip_events[];
|
||||
extern const char *vcpu_id_str;
|
||||
extern const int decode_str_len;
|
||||
extern const char *kvm_exit_reason;
|
||||
extern const char *kvm_entry_trace;
|
||||
extern const char *kvm_exit_trace;
|
||||
|
||||
#endif /* __PERF_KVM_STAT_H */
|
||||
|
@ -701,3 +701,20 @@ bool is_regular_file(const char *file)
|
||||
|
||||
return S_ISREG(st.st_mode);
|
||||
}
|
||||
|
||||
int fetch_current_timestamp(char *buf, size_t sz)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct tm tm;
|
||||
char dt[32];
|
||||
|
||||
if (gettimeofday(&tv, NULL) || !localtime_r(&tv.tv_sec, &tm))
|
||||
return -1;
|
||||
|
||||
if (!strftime(dt, sizeof(dt), "%Y%m%d%H%M%S", &tm))
|
||||
return -1;
|
||||
|
||||
scnprintf(buf, sz, "%s%02u", dt, (unsigned)tv.tv_usec / 10000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -344,5 +344,6 @@ int fetch_kernel_version(unsigned int *puint,
|
||||
|
||||
const char *perf_tip(const char *dirpath);
|
||||
bool is_regular_file(const char *file);
|
||||
int fetch_current_timestamp(char *buf, size_t sz);
|
||||
|
||||
#endif /* GIT_COMPAT_UTIL_H */
|
||||
|
Loading…
Reference in New Issue
Block a user