Sunday, 5 April 2026

Improving Windows 11 VM Performance on Unraid (Threadripper)

I’ve been running a Windows 11 VM on my Unraid server for a while now. It’s reasonably well specced. Threadripper 3960X, RTX 3090 passed through, dedicated SSD. On paper it should feel very close to bare metal.

In reality, it didn’t.

Nothing obviously broken, but general UI usage felt a bit sluggish. Windows took a little longer to open things than expected.  With the help of my ChatGPT sidekick, I decided to go through the config properly and see what could be improved. Logging it here mainly for my own reference later.

CPU Pinning Cleanup

First issue was my CPU pinning. It was scattered all over the place. That’s not ideal on Threadripper.

I switched to a clean contiguous block with proper SMT pairing. In my case:

  • 8–15
  • 32–39

That gives 8 cores / 16 threads, all neatly paired.

Also worth noting:

  • I deliberately avoided CPU 0 as Unraid prefers to keep that for housekeeping.

This didn’t massively change performance on its own, but it removed a bad baseline.


CPU Isolation

I already had isolcpus set in syslinux, but it didn’t match my VM anymore.

Quick check:

cat /proc/cmdline

In my case I’m running multiple VMs, all with explicitly pinned cores, so I’ve kept a broader isolation range. The key point is consistency. Every isolated core should be accounted for and pinned somewhere. No overlap, no gaps.

If you’re only running a single VM, it’s probably cleaner to match isolcpus exactly to your VM cores.


Hugepages

Next step was hugepages. This was not enabled via the UI, so done manually.

Edit:

/boot/syslinux/syslinux.cfg

Add:

hugepages=16384

That reserves 32GB, which matches the RAM assigned to my VM.

After reboot, confirm:

grep Huge /proc/meminfo

Then add to the VM XML:

<memoryBacking>
<hugepages/>
<locked/>
<nosharepages/>
</memoryBacking>

Result here was modest. Slightly smoother overall, but nothing dramatic. VM boot took a bit longer which makes sense.


VBS (Virtualization Based Security)

This turned out to be the big one.

Even though Memory Integrity was already off in Windows settings, VBS was still running.

Check:

msinfo32

Look for:

  • Virtualization-based security

Mine showed as running.

To disable:

Open Group Policy:

gpedit.msc

Navigate to:

Computer Configuration
→ Administrative Templates
→ System
→ Device Guard

Set:

  • Turn On Virtualization Based Security → Disabled

Then in an admin command prompt:

bcdedit /set hypervisorlaunchtype off

Reboot the VM.

After that:

  • Boot time improved
  • Applications opened noticeably faster
  • General UI responsiveness improved straight away

This was easily the most impactful change.


Hyper-V Settings

Checked the Hyper-V section in the VM XML. Mine was mostly correct, just needed to tidy up the vendor_id:

<hyperv mode='custom'>
<relaxed state='on'/>
<vapic state='on'/>
<spinlocks state='on' retries='8191'/>
<vendor_id state='on' value='KVM12345678'/>
</hyperv>

No obvious difference after this, but it’s the correct setup.


GPU MSI Mode

Worth checking interrupt mode on the GPU.

Used MSI Utility v3 and confirmed the RTX 3090 was already using MSI. If it isn’t, enabling it can help with latency.

No change needed in my case.


CPU Power Mode

Checked Unraid was running in performance mode:

cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

All cores already set to performance, so nothing to do there.


Where This Leaves Things

After all of the above:

  • Windows definitely feels snappier
  • Apps open faster
  • General responsiveness improved
  • Still not quite identical to bare metal

At this point, there’s nothing obviously wrong in the Unraid or VM config.


Remaining Limitation

One thing I noticed earlier is that the system is reporting a single NUMA node. On Threadripper that’s not ideal.

Without proper NUMA exposure:

  • Windows scheduler is less efficient
  • Memory locality isn’t optimal

Fixing that will require a trip into the BIOS to enable proper NUMA settings. That’s for another day.


Summary

Things that actually made a difference:

  • Cleaning up CPU pinning
  • Matching CPU isolation
  • Hugepages (minor improvement)
  • Disabling VBS (big improvement)

Things that didn’t move the needle much:

  • Minor XML tweaks
  • GPU settings (already correct)

Overall, worthwhile exercise. The VM now behaves much closer to what I’d expect given the hardware. I’ll revisit this once I sort out NUMA and see if that closes the remaining gap.

No comments: