Commit b9f5621c authored by Like Xu's avatar Like Xu Committed by Peter Zijlstra
Browse files

perf/core: Rework guest callbacks to prepare for static_call support



To prepare for using static_calls to optimize perf's guest callbacks,
replace ->is_in_guest and ->is_user_mode with a new multiplexed hook
->state, tweak ->handle_intel_pt_intr to play nice with being called when
there is no active guest, and drop "guest" from ->get_guest_ip.

Return '0' from ->state and ->handle_intel_pt_intr to indicate "not in
guest" so that DEFINE_STATIC_CALL_RET0 can be used to define the static
calls, i.e. no callback == !guest.

[sean: extracted from static_call patch, fixed get_ip() bug, wrote changelog]
Suggested-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Originally-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: default avatarLike Xu <like.xu@linux.intel.com>
Signed-off-by: default avatarZhu Lingshan <lingshan.zhu@intel.com>
Signed-off-by: default avatarSean Christopherson <seanjc@google.com>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: default avatarBoris Ostrovsky <boris.ostrovsky@oracle.com>
Reviewed-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Link: https://lore.kernel.org/r/20211111020738.2512932-7-seanjc@google.com
parent 84af21d8
Loading
Loading
Loading
Loading
+7 −6
Original line number Diff line number Diff line
@@ -104,7 +104,7 @@ void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
{
	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();

	if (guest_cbs && guest_cbs->is_in_guest()) {
	if (guest_cbs && guest_cbs->state()) {
		/* We don't support guest os callchain now */
		return;
	}
@@ -152,7 +152,7 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
	struct stackframe frame;

	if (guest_cbs && guest_cbs->is_in_guest()) {
	if (guest_cbs && guest_cbs->state()) {
		/* We don't support guest os callchain now */
		return;
	}
@@ -165,8 +165,8 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs)
{
	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();

	if (guest_cbs && guest_cbs->is_in_guest())
		return guest_cbs->get_guest_ip();
	if (guest_cbs && guest_cbs->state())
		return guest_cbs->get_ip();

	return instruction_pointer(regs);
}
@@ -174,10 +174,11 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs)
unsigned long perf_misc_flags(struct pt_regs *regs)
{
	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
	unsigned int guest_state = guest_cbs ? guest_cbs->state() : 0;
	int misc = 0;

	if (guest_cbs && guest_cbs->is_in_guest()) {
		if (guest_cbs->is_user_mode())
	if (guest_state) {
		if (guest_state & PERF_GUEST_USER)
			misc |= PERF_RECORD_MISC_GUEST_USER;
		else
			misc |= PERF_RECORD_MISC_GUEST_KERNEL;
+15 −20
Original line number Diff line number Diff line
@@ -13,39 +13,34 @@

DEFINE_STATIC_KEY_FALSE(kvm_arm_pmu_available);

static int kvm_is_in_guest(void)
static unsigned int kvm_guest_state(void)
{
        return kvm_get_running_vcpu() != NULL;
}

static int kvm_is_user_mode(void)
{
	struct kvm_vcpu *vcpu;
	struct kvm_vcpu *vcpu = kvm_get_running_vcpu();
	unsigned int state;

	vcpu = kvm_get_running_vcpu();
	if (!vcpu)
		return 0;

	if (vcpu)
		return !vcpu_mode_priv(vcpu);
	state = PERF_GUEST_ACTIVE;
	if (!vcpu_mode_priv(vcpu))
		state |= PERF_GUEST_USER;

	return 0;
	return state;
}

static unsigned long kvm_get_guest_ip(void)
{
	struct kvm_vcpu *vcpu;
	struct kvm_vcpu *vcpu = kvm_get_running_vcpu();

	vcpu = kvm_get_running_vcpu();
	if (WARN_ON_ONCE(!vcpu))
		return 0;

	if (vcpu)
	return *vcpu_pc(vcpu);

	return 0;
}

static struct perf_guest_info_callbacks kvm_guest_cbs = {
	.is_in_guest	= kvm_is_in_guest,
	.is_user_mode	= kvm_is_user_mode,
	.get_guest_ip	= kvm_get_guest_ip,
	.state		= kvm_guest_state,
	.get_ip		= kvm_get_guest_ip,
};

void kvm_perf_init(void)
+7 −6
Original line number Diff line number Diff line
@@ -2772,7 +2772,7 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *re
	struct unwind_state state;
	unsigned long addr;

	if (guest_cbs && guest_cbs->is_in_guest()) {
	if (guest_cbs && guest_cbs->state()) {
		/* TODO: We don't support guest os callchain now */
		return;
	}
@@ -2876,7 +2876,7 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs
	struct stack_frame frame;
	const struct stack_frame __user *fp;

	if (guest_cbs && guest_cbs->is_in_guest()) {
	if (guest_cbs && guest_cbs->state()) {
		/* TODO: We don't support guest os callchain now */
		return;
	}
@@ -2955,8 +2955,8 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs)
{
	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();

	if (guest_cbs && guest_cbs->is_in_guest())
		return guest_cbs->get_guest_ip();
	if (guest_cbs && guest_cbs->state())
		return guest_cbs->get_ip();

	return regs->ip + code_segment_base(regs);
}
@@ -2964,10 +2964,11 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs)
unsigned long perf_misc_flags(struct pt_regs *regs)
{
	struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
	unsigned int guest_state = guest_cbs ? guest_cbs->state() : 0;
	int misc = 0;

	if (guest_cbs && guest_cbs->is_in_guest()) {
		if (guest_cbs->is_user_mode())
	if (guest_state) {
		if (guest_state & PERF_GUEST_USER)
			misc |= PERF_RECORD_MISC_GUEST_USER;
		else
			misc |= PERF_RECORD_MISC_GUEST_KERNEL;
+1 −4
Original line number Diff line number Diff line
@@ -2906,10 +2906,7 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status)
		handled++;

		guest_cbs = perf_get_guest_cbs();
		if (unlikely(guest_cbs && guest_cbs->is_in_guest() &&
			     guest_cbs->handle_intel_pt_intr))
			guest_cbs->handle_intel_pt_intr();
		else
		if (likely(!guest_cbs || !guest_cbs->handle_intel_pt_intr()))
			intel_pt_interrupt();
	}

+1 −1
Original line number Diff line number Diff line
@@ -1895,7 +1895,7 @@ int kvm_skip_emulated_instruction(struct kvm_vcpu *vcpu);
int kvm_complete_insn_gp(struct kvm_vcpu *vcpu, int err);
void __kvm_request_immediate_exit(struct kvm_vcpu *vcpu);

int kvm_is_in_guest(void);
unsigned int kvm_guest_state(void);

void __user *__x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa,
				     u32 size);
Loading