During KVM exit processing (KVM_PUT_RUNTIME_STATE), QEMU never modifies FP or Vector registers — only core GPRs/PC and CSRs are potentially changed. Re-syncing 32 FP and 32 Vector registers on every KVM exit wastes 36-68 individual KVM_SET_ONE_REG ioctls per vCPU exit.
Follow the s390x pattern: early return on RUNTIME after syncing core registers and CSRs. KVM_PUT_FULL_STATE and KVM_PUT_RESET_STATE continue to sync everything for correctness during migration and initialization. Signed-off-by: Meng Zhuo <[email protected]> --- target/riscv/kvm/kvm-cpu.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index b047ffa9c0..dd4193ea8b 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -1385,6 +1385,17 @@ int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp) return ret; } + /* + * For RUNTIME_STATE, KVM already has the correct FP and Vector state + * from the preceding KVM_RUN exit. QEMU never modifies these registers + * during exit handling, so re-syncing is unnecessary. This saves ~68 + * KVM_SET_ONE_REG ioctls per vCPU exit. See also s390x which uses + * the same pattern. + */ + if (KVM_PUT_RUNTIME_STATE == level) { + return ret; + } + ret = kvm_riscv_put_regs_fp(cs); if (ret) { return ret; @@ -1397,11 +1408,9 @@ int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp) if (KVM_PUT_RESET_STATE == level) { RISCVCPU *cpu = RISCV_CPU(cs); - if (cs->cpu_index == 0) { - ret = kvm_riscv_sync_mpstate_to_kvm(cpu, KVM_MP_STATE_RUNNABLE); - } else { - ret = kvm_riscv_sync_mpstate_to_kvm(cpu, KVM_MP_STATE_STOPPED); - } + int state = cs->cpu_index == 0 ? KVM_MP_STATE_RUNNABLE + : KVM_MP_STATE_STOPPED; + ret = kvm_riscv_sync_mpstate_to_kvm(cpu, state); if (ret) { return ret; } -- 2.47.3
