Created
August 28, 2018 18:03
-
-
Save jbirley/b419c05292ca3e06254b35b2f6de3f88 to your computer and use it in GitHub Desktop.
This function gives Virtual Machine vCPU and vNuma rightsizing recommendations based on Rules of Thumb from this popular VMWare blog post: https://blogs.vmware.com/performance/2017/03/virtual-machine-vcpu-and-vnuma-rightsizing-rules-of-thumb.html#comment-117062 This function assumes that each VM is part of a vSphere cluster and will therefore ev…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Requires -Version 3.0 | |
function Get-vNumaInfo { | |
<# | |
.SYNOPSIS | |
Gets the current resource (vCPU and vRAM) information about one or more VMs and makes a recommendation based on best practice for vNuma. | |
.DESCRIPTION | |
This function gives Virtual Machine vCPU and vNuma rightsizing recommendations based on Rules of Thumb from this popular VMWare blog post: | |
https://blogs.vmware.com/performance/2017/03/virtual-machine-vcpu-and-vnuma-rightsizing-rules-of-thumb.html#comment-117062 | |
This function assumes that each VM is part of a vSphere cluster and will therefore evaluate recommendations based on the smallest | |
node within a cluster, both from a CPU and Memory perspective. Currently, this function also assumes that all VMHosts are dual socket | |
servers and are already NUMA balanced at the physical layer since this is the most common deployment scenario. | |
.PARAMETER Cluster | |
One or more vSphere Cluster objects. Using this parameter is preferred over the VM parameter since it will evaluate the cluster | |
resources only once as it determines a recommendation for all VM's within the cluster. | |
.PARAMETER VM | |
One or more vSphere VM's. Using this parameter is less performant, especially when analyzing larger numbers of VM's. | |
For each VM, the cluster membership is determined before a recommendation is calculated. For larger numbers, | |
please see the Cluster parameter for better performance. | |
.PARAMETER VmClusterName | |
This is an optional parameter used in combination with the 'VM' parameter. It can help speed up results | |
in the case that all VMs are to be measured against a single cluster's resources or if you wish to "What-if" model | |
a set of VM's into another cluster. See example #2 below. | |
.EXAMPLE | |
Connect-ViServer -Server 'vCenterServer' | |
$AllClusters = Get-Cluster | |
Get-vNumaInfo -Cluster $AllClusters | |
.EXAMPLE | |
Connect-ViServer -Server 'vCenterServer' | |
$LargeVMs = Get-VM | Where {$_.NumCPU -gt 14} | |
Get-vNumaInfo -VM $LargeVMs -VmClusterName 'BigCluster' | |
.EXAMPLE | |
Connect-ViServer -Server 'vCenterServer' | |
Get-Datastore 'DataStore1' | Get-VM | get-vNumaInfo | |
.INPUTS | |
String | |
.OUTPUTS | |
PSCustomObject | |
.NOTES | |
Author: Jim Birley | |
@jbirley | |
#> | |
[CmdletBinding()] | |
[OutputType('PSCustomObject')] | |
param ( | |
[Parameter(Mandatory,Position=0,ParameterSetName='ByCluster')] | |
#[VMware.VimAutomation.ViCore.Impl.V1.Inventory.ComputeResourceImpl[]]$Cluster, | |
[VMware.VimAutomation.ViCore.Impl.V1.Inventory.ClusterImpl[]]$Cluster, | |
[Parameter(Mandatory,ValueFromPipeline,Position=0,ParameterSetName='ByVM')] | |
[VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl[]]$VM, #typename obtained by $VM.GetType() and grabbed 'BaseType' | |
[Parameter(Position=1,ParameterSetName='ByVM')] | |
[string]$VmClusterName | |
) | |
BEGIN { | |
if ($VmClusterName) { | |
Write-Verbose "Evaluating $VmClusterName for smallest VMHost" | |
$pNumaCpu = (Get-Cluster $VmClusterName | Get-VMhost | Sort-Object -Property 'NumCPU' | Select-Object -First 1).NumCPU/2 | |
$pNumaMem = [math]::Round((Get-cluster $VmClusterName | Get-VMhost | Sort-Object -Property 'MemoryTotalGB' | Select-Object -First 1).MemoryTotalGB,0)/2 | |
} | |
} | |
PROCESS { | |
if ($VM) { | |
foreach ($MyVM in $VM) { | |
if (-Not $VmClusterName) { | |
#Determine each VM's VMHost and cluster and derive the minimum pNUMA Size. (Cores and pMem) | |
$HostName = ($MyVM | Select-Object VMHost).VMHost | |
$VmClusterName = (Get-VMHost -Name $HostName | Select-Object Parent).Parent | |
$pNumaCpu = (Get-Cluster $VmClusterName | Get-VMhost | Sort-Object -property 'NumCPU' | Select-Object -First 1).NumCPU/2 | |
$pNumaMem = [math]::Round((Get-Cluster $VmClusterName | Get-VMhost | Sort-Object -Property 'MemoryTotalGB' | Select-Object -First 1).MemoryTotalGB,0)/2 | |
} | |
$vNumaNodes = $MyVM.NumCPU/$MyVM.CoresPerSocket | |
$IsOverSized = if ($MyVM.NumCPU -gt ($pNumaCpu * 2) -Or $MyVM.MemoryGB -gt ($pNumaMem * 2)) {$true} else {$false} | |
$IsWide = if ($MyVM.NumCPU -gt $pNumaCpu -Or $MyVM.MemoryGB -gt $pNumaMem) {$true} else {$false} | |
$ReconfigureVM = $true | |
$NewvCPU = $MyVM.NumCPU | |
$NewMemGB = $MyVM.MemoryGB | |
if ($vNumaNodes -eq 1) { | |
if (-Not $IsWide) { | |
$ReconfigureVM = $false #already optimal | |
$NewCoresPerSocket = $MyVM.CoresPerSocket | |
$NewvNumaNodes = 1 | |
} else { #wide VM with one vNUMA node | |
if ($IsOverSized) { #shrink the VM by CPU or Mem if necessary | |
if ($NewvCPU -gt $pNumaCpu) { | |
$NewvCPU = $pNumaCpu * 2 | |
} | |
if ($NewMemGB -gt $pNumaMem) { | |
$NewMemGB = $pNumaMem * 2 | |
} | |
} | |
$NewCoresPerSocket = $NewvCPU / 2 | |
$NewvNumaNodes = 2 | |
} | |
} else { #more than one vNuma Node | |
if (-Not $IsWide) { #make it one vNuma node | |
$NewCoresPerSocket = $NewvCPU | |
$NewvNumaNodes = 1 | |
} else { #wide VM with more than one vNuma Node | |
if ($IsOverSized) { #shrink the VM by CPU or Mem if necessary | |
if ($NewvCPU -gt $pNumaCpu) { | |
$NewvCPU = $pNumaCpu * 2 | |
} | |
if ($NewMemGB -gt $pNumaMem) { | |
$NewMemGB = $pNumaMem * 2 | |
} | |
} | |
$NewCoresPerSocket = $NewvCPU / 2 | |
$NewvNumaNodes = 2 | |
} | |
} | |
#In the case that the VM was "wide", but already configured optimally, set ReconfigureVM to false. | |
if (($vNumaNodes -eq $NewvNumaNodes) -And ($MyVM.CoresPerSocket -eq $NewCoresPerSocket)) {$ReconfigureVM = $false} | |
[PSCustomObject]@{ | |
'Name' = $MyVM.Name | |
'Cluster' = $VmClusterName | |
'pNumaCpu' = $pNumaCpu | |
'pNumaMem' = $pNumaMem | |
'NumCPU' = $MyVM.NumCPU | |
'MemoryGB' = $MyVM.MemoryGB | |
'vSockets' = $vNumaNodes | |
'CoresPerSocket' = $MyVM.CoresPerSocket | |
'IsWide' = $IsWide | |
'IsOverSized' = $IsOverSized | |
'ReconfigureVM' = $ReconfigureVM | |
'NewvCPU' = $NewvCPU | |
'NewMemGB' = $NewMemGB | |
'NewvSockets' = $NewvNumaNodes | |
'NewCoresPerSocket' = $NewCoresPerSocket | |
} | |
} | |
} else { | |
foreach ($MyCluster in $Cluster) { | |
$AllVms = Get-VM -Location $MyCluster | |
if ($AllVms) { | |
Get-vNumaInfo -VM $AllVms -VmClusterName $MyCluster.Name | |
} | |
} | |
} | |
} | |
END {} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment