Issue:

When guest-VMs are being migrated between Hyper-V Hosts within a cluster, CPU core scheduling seems to have been disproportionately distributed toward even-numbered cores (0,2,4,6,8, etc.)

Cause:

There appears to be a new type of processor scheduling named ‘core scheduler’ in Windows Server 2019 that succeeds the previous versions of Windows of ‘classic scheduler’. The difference between those two types of scheduling would affect how migrating VMs would be pinned toward certain numbered CPUs. In the screenshot above, odd-numbered CPU cores seem to be excluded from those migrated VMs.

Resolution:

Check VMHost Supported Versions (notice the IsDefault field):

PS C:\Windows\system32> Get-VMHostSupportedVersion

Name Version IsDefault
---- ------- ---------
Microsoft Windows 8.1/Server 2012 R2 5.0 False
Microsoft Windows 10 1507/Server 2016 Technical Preview 3 6.2 False
Microsoft Windows 10 1511/Server 2016 Technical Preview 4 7.0 False
Microsoft Windows Server 2016 Technical Preview 5 7.1 False
Microsoft Windows 10 Anniversary Update/Server 2016 8.0 False
Microsoft Windows 10 Creators Update 8.1 False
Microsoft Windows 10 Fall Creators Update/Server 1709 8.2 False
Microsoft Windows 10 April 2018 Update/Server 1803 8.3 False
Microsoft Windows 10 October 2018 Update/Server 2019 9.0 True

Check Guest VMs Configured Versions:

PS C:\Windows\system32> Get-VM | FT Name,Version,State

Name Version State
---- ------- -----
TESTVM01 8.0 Off
TESTVM02 8.0 Running
TESTVM03 9.0 Off
TESTVM04 9.0 Running

Perform ‘whole-sale’ Updates:
Note: only ‘offline’ guest VMs will be able to update. Any running VMs will throw errors upon invoking the Update-VMVersion command

PS C:\WINDOWS\system32> Get-VM | Update-VMVersion

Confirm
Are you sure you want to perform this action?
Performing a configuration version update of "TESTVM01" will prevent it from being migrated to or imported on previous
versions of Windows. This operation is not reversible.

[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): A
Update-VMVersion : The operation cannot be performed while the virtual machine is in its current state.
At line:1 char:10
+ Get-VM | Update-VMVersion
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (VirtualMachine ...-5cb7879f5c4f']:VirtualMachine) [Update-VMVersion],
VirtualizationException
+ FullyQualifiedErrorId : InvalidState,Microsoft.HyperV.PowerShell.Commands.UpdateVMVersion

Check VM Processor’s Hardware Thread Counts:

PS C:\WINDOWS\system32> Get-VM | Get-VMProcessor | FT VMName,HwThreadCountPerCore

VMName HwThreadCountPerCore
------ --------------------
TESTVM01 1
TESTVM01 1
TESTVM01 1
TESTVM01 1

Fix the CPU Core Scheduling Affinity:
Note: the below command only affects off-lined guest VMs

PS C:\WINDOWS\system32> Get-VM | Set-VMProcessor -HwThreadCountPerCore 0
Set-VMProcessor : Failed to modify device 'Processor'.
Cannot change the processor functionality of a virtual machine now.
'TESTVM02' failed to modify device 'Processor'. (Virtual machine ID C99B-4469-A0E7)
Cannot change the processor functionality of virtual machine 'TESTVM02' while it is running. (Virtual machine ID
C99B-4469-A0E7)
At line:1 char:10
+ Get-VM | Set-VMProcessor -HwThreadCountPerCore 0
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Set-VMProcessor], VirtualizationException
+ FullyQualifiedErrorId : InvalidState,Microsoft.HyperV.PowerShell.Commands.SetVMProcessor

Generalized Approach:

To fix all guest VMs that have a lowered version of VM Host CPU support, each of the VM must be turned off. If that is not convenient due to production impacts, one could run this command to only target off-lined VMs:

Get-VM |?{$_.Version -lt 9.0}|Update-VMVersion -Force -EA SilentlyContinue|?{$_.State -eq 'Off'}|Set-VMProcessor -HwThreadCountPerCore 0

In our environment, the VM update command has no adverse effects on the performance of the machines thereafter. More importantly, the guest VMs have powered on without errors triggered by these changes. Also, it appears that version 9.0 guest VMs may have been patched to optimally allocate CPU resources. Hence, the Set-VMProcessor -HwThreadCountPerCore 0 may be unnecessary as of this writing. Still, setting that value as zero is recommended for consistency.

Result:

Screenshot of a more balanced CPU Core Scheduling