mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Anthony Harivel <aharivel@redhat.com>
To: kvm@vger.kernel.org
Cc: pbonzini@redhat.com, seanjc@google.com,
	linux-kernel@vger.kernel.org,
	Anthony Harivel <aharivel@redhat.com>
Subject: [PATCH RFC v3 0/3] KVM: x86: per-VM C-state policy enforcement (KVM_CAP_CSTATE_POLICY)
Date: Mon, 14 Sep 2026 16:36:59 +0200	[thread overview]
Message-ID: <20260914143702.915401-1-aharivel@redhat.com> (raw)

This is v3 of the RFC for KVM_CAP_CSTATE_POLICY, a new VM-scoped
capability that lets userspace set a maximum C-state ceiling per VM.

Changes since v2 (RFC, design questions only):
  - Implemented Option A from v2 design discussion: temporarily toggle
    cpuidle states_usage[].disable on the pinned pCPU before/after
    kvm_vcpu_block(). Uses CPUIDLE_STATE_DISABLED_BY_DRIVER flag.
  - Added KVM selftest (7 tests, all passing on bare metal).
  - Added QEMU prototype (not in this series -- separate tree).
  - Answered design questions from v2 based on implementation experience.

Changes since v1:
  - Corrected internal flow: enforcement goes through kvm_vcpu_halt() +
    cpuidle constraint, not inline MWAIT execution.
  - Expanded design questions with concrete enforcement options.

== Problem ==

Cloud operators running NFV workloads want to reduce energy consumption
by disabling halt-polling (halt_poll_ns=0). This lets vCPUs enter real
idle states instead of busy-looping, saving power.

However, disabling halt-polling is system-wide and ALL VMs on the host
lose halt-polling. The kernel cpuidle governor then picks deep C-states
(C6, ~133us wakeup) by default, which hurts latency-sensitive VMs.

There is no per-VM mechanism to say: "save power on batch VMs, but keep
wakeup latency low on this latency-sensitive VM."

Existing knobs are all system-wide or not VM-aware:
  - intel_idle.max_cstate: system-wide kernel parameter
  - /sys/devices/system/cpu/cpuN/cpuidle/stateN/disable: per-CPU, not VM-aware
  - halt_poll_ns: system-wide, all or nothing

== Solution ==

KVM_CAP_CSTATE_POLICY: a VM-scoped ioctl (same pattern as
KVM_CAP_HALT_POLL) that constrains cpuidle state selection when
vCPUs halt.

  args[0] = max_cstate:
    -1 = disabled (default, no constraint)
     0 = force C0 (HLT returns immediately, no idle)
     1 = cap at C1 (~2us wakeup)
     6 = cap at C6 (effectively unrestricted)

When a vCPU enters kvm_vcpu_block(), KVM disables cpuidle states
deeper than max_cstate on the current pCPU (preempt-disabled), then
restores after wakeup. The capability is re-callable at runtime --
policy changes take effect on the next vCPU HLT without VM restart.

== Test results ==

Tested on Dell R640 (Intel Xeon Gold 5118, intel_idle driver with
POLL/C1/C1E/C6 states).

KVM selftest (7/7 pass):

  ok 1 cap_supported
  ok 2 valid_policies
  ok 3 invalid_policies
  ok 4 policy_change
  ok 5 cpuidle_no_policy
  ok 6 cpuidle_enforcement
  ok 7 policy_c0_no_idle

Selftest cpuidle counters (1000 guest HLTs per test):

                  No policy     Policy=C1     Policy=C0
  POLL usage:     +0            +0            +56,743
  C1 usage:       +3            +1,073        +0
  C1E usage:      +70           +0            +0
  C6 usage:       +1,003        +0            +0

Multi-VM demo (2 VMs, 60s, same host, turbostat):

                  VM-A (policy=C1)    VM-B (no policy)
  C1 residency:   98-99%              0%
  C6 residency:   0%                  54-99%

The enforcement is clear: VM-A stays in C1 while VM-B on the same
host goes deep into C6.

== Design decisions (answers to v2 questions) ==

(a) Enforcement mechanism: Option A (toggle states_usage[].disable)
    works correctly for pinned-core NFV configurations. The disable
    flags are set/cleared with preemption disabled, so no migration
    race. A WARN_ON_ONCE guards against unexpected CPU changes.

(b) VMCS toggling: not needed for v1 -- enforcement works within the
    existing HLT exit path. MWAIT interception is a separate concern
    for a future series if cpu-pm=on integration is desired.

(c) MWAIT hint mapping: not needed for v1 -- the policy operates on
    cpuidle state indices, which the intel_idle driver maps to
    hardware C-states. This is the same abstraction sysfs uses.

(d) halt_poll_ns interaction: orthogonal as expected. halt_poll_ns
    controls spin duration before idle; max_cstate controls idle
    depth after polling. Both knobs work together.

(e) Per-vCPU vs per-VM: starting with per-VM. Per-vCPU can be added
    later as a separate capability if needed.

== Scope ==

This v3 is scoped to pinned-core configurations (NFV, DPDK). A
per-task cpuidle constraint (Option C from v2) would cover all cases
including overcommit, but requires cpuidle subsystem changes. Happy
to pursue that if maintainers prefer, but Option A covers the
immediate customer need.

== QEMU prototype (separate tree) ==

A working QEMU patch adds -accel kvm,cstate-policy=N. Available at:
  https://github.com/aharivel/qemu/tree/kvm-cstate-policy

== Series ==

  [1/3] cpuidle: export cpuidle_devices for KVM module access
  [2/3] KVM: x86: add KVM_CAP_CSTATE_POLICY capability
  [3/3] KVM: selftests: add cstate_policy_test

Anthony Harivel (3):
  cpuidle: export cpuidle_devices for KVM C-state policy enforcement
  KVM: x86: add KVM_CAP_CSTATE_POLICY for per-VM C-state enforcement
  KVM: selftests: add cstate_policy_test for KVM_CAP_CSTATE_POLICY

 drivers/cpuidle/cpuidle.c                     |   1 +
 include/linux/kvm_host.h                      |   2 +
 include/uapi/linux/kvm.h                      |   1 +
 tools/testing/selftests/kvm/Makefile.kvm      |   1 +
 .../selftests/kvm/x86/cstate_policy_test.c    | 517 ++++++++++++++++++
 virt/kvm/kvm_main.c                           | 101 ++++
 6 files changed, 623 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/x86/cstate_policy_test.c

-- 
2.55.0


             reply	other threads:[~2026-09-14 14:37 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-14 14:36 Anthony Harivel [this message]
2026-09-14 14:37 ` [PATCH RFC v3 1/3] cpuidle: export cpuidle_devices for KVM C-state policy enforcement Anthony Harivel
2026-09-14 14:37 ` [PATCH RFC v3 2/3] KVM: x86: add KVM_CAP_CSTATE_POLICY for per-VM C-state enforcement Anthony Harivel
2026-09-14 15:23   ` Sean Christopherson
2026-09-15  5:30     ` Paolo Bonzini
2026-09-15 12:53     ` Anthony Harivel
2026-09-14 14:37 ` [PATCH RFC v3 3/3] KVM: selftests: add cstate_policy_test for KVM_CAP_CSTATE_POLICY Anthony Harivel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260914143702.915401-1-aharivel@redhat.com \
    --to=aharivel@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=seanjc@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®