kvm: HyperV Enlightment for Improved Windows Server 2008+ Performance (#2870)

Windows has support for several paravirt features that it will use when running on Hyper-V, Microsoft's hypervisor. These features are called enlightenments. Many of the features are similar to paravirt functionality that exists with Linux on KVM (virtio, kvmclock, PV EOI, etc.)

Nowadays QEMU/KVM can also enable support for several Hyper-V enlightenments. When enabled, Windows VMs running on KVM will use many of the same paravirt optimizations they would use when running on Hyper-V.

A number of years ago, a PR was introduced that added a good portion of the code to enable this feature set, but it was never completed. This PR enables the existing features. The previous patch set detailed in #1013 also included the tests.

By selecting Windows PV, the enlightenment additions will be applied to the libvirt configuration. This is support on Windows Server 2008 and beyond, so all currently supported versions of Windows Server.

In our testing, we've seen benchmark improvements of around 20-25% running on Centos 7 hosts and it is also supported on Centos/RHEL 6.5 and later. Testing on Ubuntu would be appreciated.
This commit is contained in:
Simon Weller 2018-10-24 20:24:13 -05:00 committed by Rohit Yadav
parent 6f44a8d7ba
commit c4b621a418
3 changed files with 21 additions and 15 deletions

View File

@ -2016,6 +2016,19 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
}
}
protected void enlightenWindowsVm(VirtualMachineTO vmTO, FeaturesDef features) {
if (vmTO.getOs().contains("Windows PV")) {
// If OS is Windows PV, then enable the features. Features supported on Windows 2008 and later
LibvirtVMDef.HyperVEnlightenmentFeatureDef hyv = new LibvirtVMDef.HyperVEnlightenmentFeatureDef();
hyv.setFeature("relaxed", true);
hyv.setFeature("vapic", true);
hyv.setFeature("spinlocks", true);
hyv.setRetries(8096);
features.addHyperVFeature(hyv);
s_logger.info("Enabling KVM Enlightment Features to VM domain " + vmTO.getUuid());
}
}
public LibvirtVMDef createVMFromSpec(final VirtualMachineTO vmTO) {
final LibvirtVMDef vm = new LibvirtVMDef();
vm.setDomainName(vmTO.getName());
@ -2101,14 +2114,10 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
features.addFeatures("pae");
features.addFeatures("apic");
features.addFeatures("acpi");
//for rhel 6.5 and above, hyperv enlightment feature is added
/*
* if (vmTO.getOs().contains("Windows Server 2008") && hostOsVersion != null && ((hostOsVersion.first() == 6 && hostOsVersion.second() >= 5) || (hostOsVersion.first() >= 7))) {
* LibvirtVMDef.HyperVEnlightenmentFeatureDef hyv = new LibvirtVMDef.HyperVEnlightenmentFeatureDef();
* hyv.setRelaxed(true);
* features.addHyperVFeature(hyv);
* }
*/
//KVM hyperv enlightenment features based on OS Type
enlightenWindowsVm(vmTO, features);
vm.addComp(features);
final TermPolicy term = new TermPolicy();
@ -2120,7 +2129,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
final ClockDef clock = new ClockDef();
if (vmTO.getOs().startsWith("Windows")) {
clock.setClockOffset(ClockDef.ClockOffset.LOCALTIME);
clock.setTimer("rtc", "catchup", null);
clock.setTimer("hypervclock", null, null);
} else if (vmTO.getType() != VirtualMachine.Type.User || isGuestPVEnabled(vmTO.getOs())) {
if (_hypervisorLibvirtVersion >= 9 * 1000 + 10) {
clock.setTimer("kvmclock", null, null, _noKvmClock);

View File

@ -370,6 +370,8 @@ public class LibvirtVMDef {
if (_timerName.equals("kvmclock") && _noKvmClock) {
clockBuilder.append("present='no' />");
} else if (_timerName.equals("hypervclock")) {
clockBuilder.append("present='yes' />");
} else {
if (_tickPolicy != null) {
clockBuilder.append("tickpolicy='");

View File

@ -26,7 +26,6 @@ import junit.framework.TestCase;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.SCSIDef;
import com.cloud.utils.Pair;
public class LibvirtVMDefTest extends TestCase {
@ -155,12 +154,8 @@ public class LibvirtVMDefTest extends TestCase {
assertFalse(defs.contains("relaxed"));
assertFalse(defs.contains("vapic"));
assertFalse(defs.contains("spinlocks"));
assertTrue("Windows Server 2008 R2".contains("Windows Server 2008"));
assertTrue("Windows PV".contains("Windows PV"));
Pair<Integer,Integer> hostOsVersion = new Pair<Integer,Integer>(6,5);
assertTrue((hostOsVersion.first() == 6 && hostOsVersion.second() >= 5) || (hostOsVersion.first() >= 7));
hostOsVersion = new Pair<Integer,Integer>(7,1);
assertTrue((hostOsVersion.first() == 6 && hostOsVersion.second() >= 5) || (hostOsVersion.first() >= 7));
}
public void testRngDef() {