Experiment: Windows VM Performance in Harvester

Experiment: Windows VM Performance in Harvester

Overview

This experiment evaluates the CPU performance of a Windows Server 2022 virtual machine running on Harvester. The goal is to identify which virtualization and CPU-topology settings have the greatest impact on benchmark results.

Environment

ComponentConfiguration
HostHP server with two Intel Xeon E5-2650L v3 (Haswell-EP) processors
CPU topology24 physical cores, two NUMA nodes, Hyper-Threading disabled
HypervisorHarvester with KubeVirt/QEMU
Host operating systemImmutable SUSE Elemental/SLE Micro
Guest operating systemWindows Server 2022
BenchmarkPassMark PerformanceTest

Factors Affecting Windows VM CPU Performance

The experiment focuses on the following factors:

  • vCPU count: How many virtual processors are available to the guest.
  • Hyper-V enlightenments: Expose paravirtualized interfaces to Windows, allowing the guest to communicate with the hypervisor more efficiently. Their effectiveness is described in Tuning Windows VM Performance.
  • NUMA configuration: Helps the guest schedule work and access memory close to the physical CPU running that work.
  • Huge pages: Reduce page-table and address-translation overhead by using larger memory pages.
  • CPU model: Host passthrough exposes more of the host CPU’s features to the guest.

The primary question is: which of these factors has the greatest effect on Windows VM CPU performance?

Experiment Design

Three vCPU configurations were tested while keeping guest memory at 8 GiB:

ConfigurationvCPUsMemory
Small48 GiB
Medium168 GiB
Large248 GiB

Before plotting the results, each metric was normalized to improve readability and make the different benchmark categories easier to compare.

Normalized PassMark results for the 4-vCPU configuration

Normalized PassMark results for the 16-vCPU configuration

Normalized PassMark results for the 24-vCPU configuration

Across all three configurations, enabling Hyper-V generally produced the most noticeable performance improvement, particularly in several multi-threaded workloads. Other optimizations—such as host passthrough, CPU pinning, power settings, and huge pages—provided smaller or workload-specific gains.

VM Configuration in YAML

The following yaml shows the final tuning results. Disk, network, and volume definitions are omitted because they are unrelated to CPU benchmarking.

apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: windows-server-2022
spec:
  runStrategy: RerunOnFailure
  template:
    spec:
      domain:
        cpu:
          # Expose the host CPU features to the guest.
          model: host-passthrough
          # Pin vCPUs to dedicated physical CPUs on the host.
          dedicatedCpuPlacement: true
          # Run the QEMU emulator thread on an additional dedicated pCPU.
          isolateEmulatorThread: true
          sockets: 4
          cores: 1
          threads: 1
          # Expose the host NUMA topology to the guest.
          numa:
            guestMappingPassthrough: {}
          features:
            # Nested virtualization is disabled for this benchmark.
            - name: vmx
              policy: disable
            - name: svm
              policy: disable
        features:
          acpi:
            enabled: true
          # Enable Hyper-V enlightenments for the Windows guest.
          hyperv:
            ipi: {}
            relaxed: {}
            reset: {}
            runtime: {}
            spinlocks:
              spinlocks: 8191
            synic: {}
            synictimer: {}
            vapic: {}
            vpindex: {} 
        clock:
          timer:
            hyperv: {}
        memory:
          hugepages:
            pageSize: 2Mi
        resources:
          requests:
            cpu: "4"
            memory: 8Gi
          limits:
            cpu: "4"
            memory: 8Gi

Mapping the experiment factors to YAML

FactorYAML settingPurpose
CPU modeldomain.cpu.model: host-passthroughExposes the host CPU model and instruction-set features to the guest.
VMX/SVMdomain.cpu.features with policy: disableDisables nested virtualization because the guest does not need to run another hypervisor.
Hyper-Vdomain.features.hyperv and domain.clock.timerEnables Hyper-V enlightenments and paravirtualized Windows timers.
NUMAdomain.cpu.numa.guestMappingPassthrough: {}Exposes the host NUMA topology to the guest so CPU and memory placement can be aligned.
Dedicated CPUdomain.cpu.dedicatedCpuPlacement: trueRequests CPU pinning through the Kubernetes CPU Manager.
Emulator thread isolationdomain.cpu.isolateEmulatorThread: trueRuns the QEMU emulator thread on an additional dedicated pCPU to reduce contention with the VM’s vCPUs.
Power policyWindows guest command: powercfg /setactive SCHEME_MINSelects the Windows High performance power plan. This is a guest OS setting, not a VM YAML field.
Huge pagesdomain.memory.hugepages.pageSize: 2MiAllocates guest memory using 2 MiB host huge pages.

Results

The experiments indicate that enabling Hyper-V enlightenments had the largest positive effect on Windows guest performance. CPU host passthrough also improved performance, but the improvement was comparatively modest. NUMA placement, huge pages, and additional vCPUs provided smaller, incremental gains under this workload.

The results also suggest that assigning more vCPUs does not automatically produce a proportional increase in every PassMark score. Additional vCPUs are most useful for multi-threaded workloads; single-threaded performance is primarily determined by the performance of an individual physical core and the amount of virtualization overhead.

Takeaways

  1. Hyper-V enlightenments had the greatest impact on Windows VM CPU performance.
  2. CPU host passthrough provided a smaller but measurable improvement.
  3. NUMA alignment and huge pages are useful tuning options, especially for larger VMs, but their benefit was incremental in this experiment.
  4. When optimizing a Windows VM on Harvester, enabling the appropriate paravirtualized Hyper-V features should be the first priority, followed by CPU model and NUMA tuning.
  5. comparable metric is Single Thread (MOps/sec), because it uses one core regardless of the total number of cores or vCPUs available.

Reference