Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

perf: Add APIs to load/put guest mediated PMU context

Add exported APIs to load/put a guest mediated PMU context. KVM will
load the guest PMU shortly before VM-Enter, and put the guest PMU shortly
after VM-Exit.

On the perf side of things, schedule out all exclude_guest events when the
guest context is loaded, and schedule them back in when the guest context
is put. I.e. yield the hardware PMU resources to the guest, by way of KVM.

Note, perf is only responsible for managing host context. KVM is
responsible for loading/storing guest state to/from hardware.

[sean: shuffle patches around, write changelog]
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
Signed-off-by: Mingwei Zhang <mizhang@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: Xudong Hao <xudong.hao@intel.com>
Link: https://patch.msgid.link/20251206001720.468579-8-seanjc@google.com

authored by

Kan Liang and committed by
Peter Zijlstra
42457a7f 4593b4b6

+63
+2
include/linux/perf_event.h
··· 1925 1925 #ifdef CONFIG_PERF_GUEST_MEDIATED_PMU 1926 1926 int perf_create_mediated_pmu(void); 1927 1927 void perf_release_mediated_pmu(void); 1928 + void perf_load_guest_context(void); 1929 + void perf_put_guest_context(void); 1928 1930 #endif 1929 1931 1930 1932 #else /* !CONFIG_PERF_EVENTS: */
+61
kernel/events/core.c
··· 470 470 static cpumask_var_t perf_online_sys_mask; 471 471 static struct kmem_cache *perf_event_cache; 472 472 473 + #ifdef CONFIG_PERF_GUEST_MEDIATED_PMU 474 + static DEFINE_PER_CPU(bool, guest_ctx_loaded); 475 + 476 + static __always_inline bool is_guest_mediated_pmu_loaded(void) 477 + { 478 + return __this_cpu_read(guest_ctx_loaded); 479 + } 480 + #else 473 481 static __always_inline bool is_guest_mediated_pmu_loaded(void) 474 482 { 475 483 return false; 476 484 } 485 + #endif 477 486 478 487 /* 479 488 * perf event paranoia level: ··· 6393 6384 atomic_dec(&nr_mediated_pmu_vms); 6394 6385 } 6395 6386 EXPORT_SYMBOL_GPL(perf_release_mediated_pmu); 6387 + 6388 + /* When loading a guest's mediated PMU, schedule out all exclude_guest events. */ 6389 + void perf_load_guest_context(void) 6390 + { 6391 + struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context); 6392 + 6393 + lockdep_assert_irqs_disabled(); 6394 + 6395 + guard(perf_ctx_lock)(cpuctx, cpuctx->task_ctx); 6396 + 6397 + if (WARN_ON_ONCE(__this_cpu_read(guest_ctx_loaded))) 6398 + return; 6399 + 6400 + perf_ctx_disable(&cpuctx->ctx, EVENT_GUEST); 6401 + ctx_sched_out(&cpuctx->ctx, NULL, EVENT_GUEST); 6402 + if (cpuctx->task_ctx) { 6403 + perf_ctx_disable(cpuctx->task_ctx, EVENT_GUEST); 6404 + task_ctx_sched_out(cpuctx->task_ctx, NULL, EVENT_GUEST); 6405 + } 6406 + 6407 + perf_ctx_enable(&cpuctx->ctx, EVENT_GUEST); 6408 + if (cpuctx->task_ctx) 6409 + perf_ctx_enable(cpuctx->task_ctx, EVENT_GUEST); 6410 + 6411 + __this_cpu_write(guest_ctx_loaded, true); 6412 + } 6413 + EXPORT_SYMBOL_GPL(perf_load_guest_context); 6414 + 6415 + void perf_put_guest_context(void) 6416 + { 6417 + struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context); 6418 + 6419 + lockdep_assert_irqs_disabled(); 6420 + 6421 + guard(perf_ctx_lock)(cpuctx, cpuctx->task_ctx); 6422 + 6423 + if (WARN_ON_ONCE(!__this_cpu_read(guest_ctx_loaded))) 6424 + return; 6425 + 6426 + perf_ctx_disable(&cpuctx->ctx, EVENT_GUEST); 6427 + if (cpuctx->task_ctx) 6428 + perf_ctx_disable(cpuctx->task_ctx, EVENT_GUEST); 6429 + 6430 + perf_event_sched_in(cpuctx, cpuctx->task_ctx, NULL, EVENT_GUEST); 6431 + 6432 + if (cpuctx->task_ctx) 6433 + perf_ctx_enable(cpuctx->task_ctx, EVENT_GUEST); 6434 + perf_ctx_enable(&cpuctx->ctx, EVENT_GUEST); 6435 + 6436 + __this_cpu_write(guest_ctx_loaded, false); 6437 + } 6438 + EXPORT_SYMBOL_GPL(perf_put_guest_context); 6396 6439 #else 6397 6440 static int mediated_pmu_account_event(struct perf_event *event) { return 0; } 6398 6441 static void mediated_pmu_unaccount_event(struct perf_event *event) {}