Windows KVM: Tips and tricks for audio and improving performance

Following are a few tips and tricks I found useful when setting up my Linux/Windows KVM system. I spent a good week getting performance very close to bare metal, and most of that was spent searching for solutions that were all spread around, so I decided I’d make a summary post of what I consider to probably be common issues.

First things first, I will assume in this that you already got iommu working and that you already set up your Windows 10 KVM, it is booting and you already installed all the drivers like you would on a normal Windows installation.

If this is not the case go and have a look at @GrayBoltWolf’s guide for setting up your KVM. The post may be from 2016, but the procedure is mostly the same, and works perfectly fine on Ubuntu 18.04.

Now let’s get into it.

AUDIO
One of the first things you are likely to have problems with is audio. As of right now this does not necessarily have an easy fix, but the problem probably lies with libvirt not having the required permissions to plug into pulseaudio.

There are a couple of ways to solve this, but the simplest way is to run libvirt as your user and not as root, and make sure that pulseaudio is also running as your user and not as root. To do this, simply edit /etc/libvirt/qemu.conf and uncomment the line with #user = "root" and change it to user = "$YOURUSER". You might also need to uncomment the following line in the same config file: nographics_allow_host_audio = 1.

If you do edit the libvirt config, do remember to restart libvirtd service in systemd or reboot for the changes to take effect.

Now if your system uses systemd, you can use systemctl enable --user pulseaudio to make sure pulseaudio is always running as your user. This might not be necessary.

If you are still having trouble try adding the following to your VM settings by running $ sudo virsh edit YOURVM and adding the <qemu:commandline> like this:

<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
.
.
.
.
<qemu:commandline>
    <qemu:env name='QEMU_AUDIO_DRV' value='pa'/>
    <qemu:env name='QEMU_PA_SAMPLES' value='8192'/>
    <qemu:env name='QEMU_AUDIO_TIMER_PERIOD' value='99'/>
    <qemu:env name='QEMU_PA_SERVER' value='/run/user/1000/pulse/native'/>
</qemu:commandline>
</domain>

Make sure to edit the<domain type='kvm'> to <domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'> if you haven’t already.

This should fix audio, if not you might have to update your kernel, as of writing this the standard kernel in Ubuntu 18.04 is linux 4.15, upgrading to at least linux 4.17.11 resolved permission problems for me.

Now hopefully audio works and is perfectly fine for you, but sadly this might not be the case. At this point in my setup I was faced with terrible audio being passed from the guest to the host, but hey at least I had audio. This is where things get hard, depending on what is causing audio crackling and poor audio for you it might not be easy to fix. One thing that you can check and will have an impact is making sure the sample rate on your host and guest is set to the same frequency, this might resolve the issue.

Sadly for my setup this only helped a little, and I wound up using audio out through my GPU, through my monitor and back into the host sound card.

You could also pass an audio device/card directly to the guest and use that to play audio either over speakers or back to the sound card on the host, and though these methods seem to be the easiest way right now, they will also cost money since you might need to buy an external USB audio card depending on your current setup.

PS. If you are passing audio out from your VM through the GPU, you might be getting so called “demonic audio issues” (audio crackling and slowdown). This is solved by enabling MSI (Message Signaled Interrupts).
Check out these links on how to enable it for your GPU in your VM, remember to make sure your GPU supports it.

http://lime-technology.com/wiki/index.php/UnRAID_6/VM_Guest_Support#Enable_MSI_for_Interrupts_to_Fix_HDMI_Audio_Support

IMPROVING PERFORMANCE
If you are lucky, after setting up the KVM and getting audio to work, your setup is already good enough that your performance is close to bare metal, and you won’t have to do anything. This was not the case for me, and even though graphics weren’t an issue, processor intensive tasks proved a problem for me.

Here are a couple of things you could try to improve performance in you Windows KVM.

  1. Make sure Hypver-V Enlightenments are enabled in your VM:
  2. Tweaking the CPU topology of your VM.
    • For me, this is what made me go from processor intensive games stuttering and freezing all the time to buttery smooth performance almost as good as bare metal performance.
    • To tweak this go into the settings of your VM in Virt Manager and edit your cpu topology settings manually. For me setting it to 1 Socket, 3 Cores, 2 Threads, and 6 current allocations gave me the best performance with my old Intel i7-3770 4 core.
      You might wanna look up what someone with the same cpu as you did if you are struggling.
    • EDIT: Through tweaking and experimentation I have found that the VM seems to run best when you set it up with a couple less cpus than the host system, for example my host now runs with 8 logical cpus but I only give the guest 6 cpus. This, at least for me, improved performance in highly cpu intensive games like The Witcher 3. This is probably due to when assigning the same amount of cpus as the host, the host and the guest end up competing over resources, as well as the virtual cpus competing over resources on the logical cpus, and the VM suffers as a result. I recommend trying different topologies and cpu allocations until you find what works best for your use case.
  3. Try enabling hugepages:
    EDIT: There might be additional steps to properly configure Hugepages on your system, the stuff below only shows how to enable it in your VM. The following link to ubuntu wiki on KVM and hugepages gives some additional information about the topic: https://help.ubuntu.com/community/KVM%20-%20Using%20Hugepages
    • Enabling hugepages can improve your performance, this is also very easy. run $ sudo virsh edit YOURVM and add the <memoryBacking> segment to the end like the following.

      <domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
      .
      .
      .
      .
      <memoryBacking>
          <hugepages/>
      </memoryBacking>
      </domain>
      

These are the only things I changed on my current setup and I have close to if not as good as bare metal performance on my Windows 10 KVM now. Hope this post will help someone spend a little less time troubleshooting and more time gaming with their wonderful new linux with Windows KVM setup.

For reference my specific hardware is:

Intel i7-3770 CPU
Nvidia GeForce GTX 980
MSI Z75A-G45 Motherboard

I run Ubuntu 18.04 LTS with Linux Kernel 4.17.11.

#linux #KVM #qemu #iommu #gaming #guide #guide_lite

11 Likes

I’mma pin this for a week

I’m curious why you would set 4 cores, 2 threads but only 6 logical cpus? Frankly the RedHat docs here don’t give a good explanation at all. I’m just trying to understand your topology. Thanks for the writeup.

I was editing this yesterday because I was further tweaking my setup. I have found, at least on my hardware, that virtualizing the same amount of cores as I have logical cpus hurts performance in cpu intensive programs and games that aren’t good at multithreading.

This is probably due to the VM and the host competing for resources in addition to the virtualized cpus competing for resources on the logical cores. Leaving 2 of the cpus to the host seems to reduce this.

Using The Witcher 3 as my test, virtualizing less cores (or assigning less cores) improved performance and fps, even if the vm claimes it’s under heavier load.

I could probably achieve the same with 1 socket, 3 cores and 2 threads, and assigning 6 cpus, but I didn’t have time to test that as well yesterday, will when I get home though.

1 Like

In libvirt, when you say 4 cores, 2 threads, it means it’s going to virtualize 4 cores, each with 2 way SMT, totalling 8 threads.

1 Like

This sticky alone unpickled my brain. That topology section was key to me sorting this out!

1 Like

Has anyone ever gotten a mic to work with the pulseaudio method shown here. For me audio is near flawless if its the output from the vm to the host but mic input from the host to the vm is just crackling. Always end up having to pass my mics audio interface to the vm when i want to use a mic in game.

I’ve just managed to setup a VM with vfio for the 1st time but I get no audio at all from it, I tried the qemu.conf and qemu:cmdline options above but I get nothing at all back on the host. I’m guessing I’m missing something in my configuration. Are there any devices I need to add to the VM to get audio to pass through to the host?

On a side note, is there a way to configure static hugepages so that they are allocated from a single numa node? I have my VM bound to cpu cores from a single numa node, but, when I enable static huge pages then half of the memory is allocated from the numa node that is configured from my vm and the other half is allocated from memory on the other node. I’m trying to keep memory latency down, so, if anyone is aware of how I can allocate large pages from a single numa node I’d appreciate any pointers.

Can you post the log from your libvirt vm?
Do you have the virtual audio device on your VM, you need it to pass audio to the host.

This might be a permission problem with pulseaudio.
What distro and kernel are you on?

@kriss120 I went to look at the logs to give them to you and saw permissions errors and realized I had not restarted the libvirtd service after making the user changes, after restarting libvirtd I had sound, but, it is terrible, I need to take a look at the sample rates now to see if I can sort that out.

I’m currently running Manjaro Linux (Arch variant) and on a custom compiled 4.18.3 kernel.

Hugepages isn’t as cut and dry as adding that to the XML.

You have to modify /etc/security/limits.conf with the size you desire in bytes like this:

*    soft    memlock    (Desired size in MB * 1024)
*    hard    memlock    (Desired size in MB * 1024)

and then you have to add this to the Grub kernel command line:

hugepages=(Desired size in MB/2)
1 Like

I am aware that you should edit the limits to the desired size for your hugepages.

Pretty sure you don’t have to add the GRUB kernel command, it works by default in ubuntu at least. (I could be wrong) :slight_smile:

I simply show how to enable the VM to use hugepages, though I have edited the post to reflect that there might be additional steps for configuring hugepages further, thanks for reminding me. :slight_smile:

I ended up setting up 1G hugepages to the grub command line and then created a systemd startup service that pre-allocated the memory on the numa node I wanted (node 1, which also has my cpu’s for the VM).