212 lines
7.7 KiB
PowerShell
212 lines
7.7 KiB
PowerShell
<#
|
|
DISKSPD - VM Fleet
|
|
|
|
Copyright(c) Microsoft Corporation
|
|
All rights reserved.
|
|
|
|
MIT License
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
#>
|
|
|
|
param(
|
|
$outfile = "result-cputarget.tsv",
|
|
$cputargets = $(throw "please specify a set of cpu percentage targets"),
|
|
$addspec = ""
|
|
)
|
|
|
|
$result = "C:\ClusterStorage\collect\control\result"
|
|
|
|
# count the number of vms in the configuration
|
|
$vms = (Get-ClusterResource |? ResourceType -eq 'Virtual Machine' | measure).Count
|
|
|
|
# target cpu utilization and qos to +/- given percentage
|
|
$cputargetwindow = 5
|
|
$qoswindow = 5
|
|
|
|
# clean result file and set column headers
|
|
del -Force $outfile -ErrorAction SilentlyContinue
|
|
'WriteRatio','QOS','AVCPU','IOPS','AVRLat','AVWLat' -join "`t" > $outfile
|
|
|
|
# make qos policy and reset
|
|
Get-StorageQosPolicy -Name SweepQos -ErrorAction SilentlyContinue | Remove-StorageQosPolicy -Confirm:$false
|
|
New-StorageQosPolicy -Name SweepQoS -MinimumIops $qos -MaximumIops $qos -PolicyType Dedicated
|
|
set-storageqos -policyname SweepQoS
|
|
|
|
function is-within(
|
|
$value,
|
|
$target,
|
|
$percentage
|
|
)
|
|
{
|
|
($value -ge ($target - ($target*($percentage/100))) -and
|
|
$value -le ($target + ($target*($percentage/100))))
|
|
}
|
|
|
|
function get-pc(
|
|
[string] $blg,
|
|
[int] $center,
|
|
[string] $ctr
|
|
)
|
|
{
|
|
# get central n samples of a performance counter's sample
|
|
$pc = Import-Counter -Path $blg -Counter "\\*\$ctr"
|
|
|
|
$t0 = ($pc.length - $center)/2
|
|
$t1 = $t0 + $center - 1
|
|
($pc[$t0 .. $t1].CounterSamples.CookedValue | measure -Average).Average
|
|
}
|
|
|
|
$pc = @('\Hyper-V Hypervisor Logical Processor(_Total)\% Total Run Time',
|
|
'\Processor Information(_Total)\% Processor Performance',
|
|
'\Cluster CSVFS(_Total)\reads/sec',
|
|
'\Cluster CSVFS(_Total)\avg. sec/read',
|
|
'\Cluster CSVFS(_Total)\writes/sec',
|
|
'\Cluster CSVFS(_Total)\avg. sec/write')
|
|
|
|
# limit the number of attempts per sweep (mix) to 4 per targeted cpu util
|
|
$sweeplimit = ($cputargets.count * 4)
|
|
|
|
foreach ($w in 0,10,30) {
|
|
|
|
# track measured qos points, starting at given value
|
|
$h = @{}
|
|
$qosinitial = $qos = 400
|
|
|
|
foreach ($cputarget in $cputargets) {
|
|
|
|
# move the qos window using previous run information
|
|
if ($cputarget -ne $cputargets[0]) {
|
|
$nextqos = [int](($cputarget*$iops/$avcpu)/$vms)
|
|
$qos = $nextqos
|
|
}
|
|
|
|
write-host -ForegroundColor Cyan Starting outer loop with CPU target $cputarget and initial QoS $qos
|
|
|
|
do {
|
|
|
|
# failsafes
|
|
if ($h[$qos]) { write-host -ForegroundColor Red already measured $qos; break }
|
|
if ($h.Keys.Count -ge $sweeplimit) { write-host -ForegroundColor Red $sweeplimit tries giving up; break }
|
|
|
|
Set-StorageQosPolicy -Name SweepQoS -MaximumIops $qos
|
|
write-host -fore Cyan Starting loop with QoS target $qos
|
|
|
|
$curaddspec = "$($addspec)w$($w)qos$qos"
|
|
start-sweep.ps1 -addspec $curaddspec -b 4 -o 32 -t 1 -w $w -p r -d 60 -warm 15 -cool 15 -pc $pc
|
|
|
|
# HACKHACK bounce collect
|
|
Get-ClusterSharedVolume |? { $_.SharedVolumeInfo.FriendlyVolumeName -match 'collect' } | Move-ClusterSharedVolume
|
|
sleep 1
|
|
|
|
# get average IOPS at DISKSPD
|
|
|
|
$iops = $(dir $result\*.xml |% {
|
|
$x = [xml](gc $_)
|
|
($x.Results.TimeSpan.Iops.Bucket | measure -Property Total -Average).Average
|
|
} | measure -Sum).Sum
|
|
|
|
# get average cpu utilization for central 60 seconds of each node
|
|
# get average of all nodes
|
|
|
|
$avcpu = $(dir $result\*.blg |% {
|
|
|
|
$center = 60
|
|
$trt = get-pc $_ $center '\Hyper-V Hypervisor Logical Processor(_Total)\% Total Run Time'
|
|
$ppc = get-pc $_ $center '\Processor Information(_Total)\% Processor Performance'
|
|
$trt*$ppc/100
|
|
|
|
|
|
} | measure -Average).Average
|
|
|
|
# get average latency for central 60 seconds, all nodes
|
|
# note we must aggregate the product of av latency and iops per node to get total
|
|
# latency, and then divide by total iops to get whole-cluster average.
|
|
|
|
$csvrtotal = 0
|
|
$csvwtotal = 0
|
|
|
|
($avrlat,$avwlat) = $(dir $result\*.blg |% {
|
|
|
|
$csvrlat = get-pc $_ $center '\Cluster CSVFS(_Total)\avg. sec/read'
|
|
$csvwlat = get-pc $_ $center '\Cluster CSVFS(_Total)\avg. sec/write'
|
|
$csvr = get-pc $_ $center '\Cluster CSVFS(_Total)\reads/sec'
|
|
$csvw = get-pc $_ $center '\Cluster CSVFS(_Total)\writes/sec'
|
|
|
|
$csvrtotal += $csvr
|
|
|
|
$csvwtotal += $csvw
|
|
|
|
[pscustomobject] @{ 'avrtime' = $csvrlat*$csvr; 'avwtime' = $csvwlat*$csvw }
|
|
|
|
} | measure -Sum -Property avrtime,avwtime).Sum
|
|
|
|
$avrlat /= $csvrtotal
|
|
$avwlat /= $csvwtotal
|
|
|
|
# capture results
|
|
$w,$qos,$avcpu,$iops,$avrlat,$avwlat -join "`t" >> $outfile
|
|
|
|
# archive results
|
|
compress-archive -Path $(dir $result\* -Exclude *.zip) -DestinationPath $result\$curaddspec.zip
|
|
dir $result\* -Exclude *.zip | del
|
|
write-host Archived results to $result\$curaddspec.zip
|
|
|
|
# stop within targetwindow% of cpu (+/- % of target)
|
|
if (is-within $avcpu $cputarget $cputargetwindow) {
|
|
write-host -ForegroundColor Green "Stopping in target window at $('{0:N2}' -f $avcpu) with QoS $qos"
|
|
break
|
|
}
|
|
|
|
# assume cpu and qos have a linear relationship - extrapolate to target
|
|
# could do a direct linear fit of measurements so far
|
|
$nextqos = [int]($cputarget*$qos/$avcpu)
|
|
|
|
# stop if next qos target is within qoswindow% of any previous measurement
|
|
$inwindow = $false
|
|
foreach ($previous in $h.keys) {
|
|
|
|
if (is-within $nextqos $previous $qoswindow) {
|
|
$inwindow = $true
|
|
break
|
|
}
|
|
}
|
|
|
|
if ($inwindow) {
|
|
write-host -ForegroundColor Yellow "Stopping in window of prior measurement at $('{0:N2}' -f $avcpu) with QoS $qos"
|
|
break
|
|
}
|
|
|
|
# stop if next qos target is less than initial
|
|
if ($nextqos -lt $qosinitial) {
|
|
write-host -ForegroundColor Red "Stopping with underflow targeting $nextqos less than initial $qosinitial"
|
|
break
|
|
}
|
|
|
|
write-host -ForegroundColor Cyan "Loop acheived $('{0:N2}' -f $avcpu) @ QoS $qos v. target $cputarget - next loop targeting QoS $nextqos"
|
|
|
|
# record this datapoint as measured, move along to the next
|
|
$h[$qos] = 1
|
|
$qos = $nextqos
|
|
|
|
} while ($true)
|
|
}
|
|
}
|
|
|
|
set-storageqos -policyname $null |