Last active
June 22, 2022 05:29
-
-
Save Jaykul/d7f2e7bb7ef1febaeae62953a4ee868b to your computer and use it in GitHub Desktop.
We need a better Measure-Command which can show averages
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
function Measure-CommandEx { | |
<# | |
.SYNOPSIS | |
A from-scratch approach to timing command execution using Stopwatch | |
#> | |
[CmdletBinding()] | |
param( | |
# The command to test (accepts value from pipeline) | |
[Parameter(ValueFromPipeline)] | |
[ScriptBlock[]]$Command, | |
# The number of times to test the command (defaults to 30) | |
[Alias("Count")] | |
[Int]$Iterations = 30, | |
# By default, Measure-CommandEx adds 20% overhead to the number of runs, and then discards the top and bottom 10% | |
# If set, this disables that feature, so you can see the outliers | |
[Switch]$ShowOutliers, | |
# If set, writes progress messages | |
# This is generally useful for very long runs, so you know it's working... | |
# But it will slow down your runs if you have a very large number of very quick iterations | |
[switch]$Progress | |
) | |
begin { | |
$watch = [System.Diagnostics.Stopwatch]::new() | |
$watch.Start() | |
## Increase count by 20% so we can discard the top and bottom 10% | |
if (!$ShowOutliers) { | |
[int]$totalIterations = $iterations * 1.2 | |
} else { | |
[int]$totalIterations = $iterations | |
} | |
} | |
end { | |
$watch.Stop() | |
} | |
process { | |
foreach ($c in $command) { | |
if (!$NoBuffer) { $Null = & $c } | |
$Measurements = for ($i=0; $i -lt $totalIterations; $i++) { | |
$Before = $watch.ElapsedTicks | |
$Null = &$c | |
$After = $watch.ElapsedTicks | |
$After - $Before | |
if ($Progress) { | |
Write-Progress -Id 1 -Activity $c -CurrentOperation "Iteration $i - $([Timespan]::FromTicks($After - $Before))" -PercentComplete $(100 * ($i / $totalIterations)) | |
} | |
} | |
if ($Progress) { | |
Write-Progress -Id 1 -Activity $c -Completed | |
} | |
if (!$ShowOutliers) { | |
$Measurements = $Measurements | Sort-Object | Select-Object -Skip ([int]($Iterations * 0.1)) -First $Iterations | |
} | |
$Measurements | | |
Measure-Object -Average -Minimum -Maximum | | |
&{ process{ | |
[PSCustomObject]@{ | |
PSTypeName = "ExecutionPerformance" | |
Average = [Timespan]::FromTicks($_.Average) | |
Maximum = [Timespan]::FromTicks($_.Maximum) | |
Minimum = [Timespan]::FromTicks($_.Minimum) | |
Iterations = $Iterations | |
Command = "$c".Trim() | |
} | |
} | |
} | |
} | |
} | |
} |
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
############################################################################## | |
## | |
## Measure-CommandPerformance | |
## | |
## From Windows PowerShell Cookbook (O'Reilly) | |
## by Lee Holmes (http://www.leeholmes.com/guide) | |
## | |
############################################################################## | |
<# | |
.SYNOPSIS | |
Measures the average time of a command, accounting for natural variability by | |
automatically ignoring the top and bottom ten percent. | |
.EXAMPLE | |
PS >Measure-CommandPerformance.ps1 { Start-Sleep -m 300 } | |
Count : 30 | |
Average : 312.10155 | |
(...) | |
#> | |
param( | |
## The command to measure | |
[Scriptblock] $Scriptblock, | |
## The number of times to measure the command's performance | |
[Alias("Count")] | |
[int] $Iterations = 30 | |
) | |
Set-StrictMode -Version Latest | |
## Figure out how many extra iterations we need to account for the outliers | |
$buffer = [int] ($iterations * 0.1) | |
$totalIterations = $iterations + (2 * $buffer) | |
## Get the results | |
$results = 1..$totalIterations | | |
Foreach-Object { Measure-Command $scriptblock } | |
## Sort the results, and skip the outliers | |
$middleResults = $results | Sort TotalMilliseconds | | |
Select -Skip $buffer -First $iterations | |
## Show the average | |
$middleResults | Measure-Object -Average TotalMilliseconds |
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
filter Measure-CommandRepeatedly { | |
<# | |
.SYNOPSIS | |
A wrapper for Measure-Command to run commands multiple times and report averages (avg, min, max) | |
#> | |
param( | |
# The script to measure | |
[Parameter(ValueFromPipeline)] | |
[ScriptBlock]$Expression, | |
# Number of iterations to run | |
## The number of times to measure the command's performance | |
[Alias("Count")] | |
[int] $Iterations = 30 | |
) | |
@(1..$Iterations).ForEach{ Microsoft.PowerShell.Utility\Measure-Command $Expression } | | |
Measure-Object TotalMilliseconds -Average -Minimum -Maximum | | |
ForEach-Object { | |
[PSCustomObject]@{ | |
PSTypeName = "ExecutionPerformance" | |
Average = $_.Average | |
Maximum = $_.Maximum | |
Minimum = $_.Minimum | |
Command = $Expression | |
Iterations = $_.Count | |
} | |
} | |
} | |
Update-TypeData -TypeName ExecutionPerformance -DefaultDisplayPropertySet Average, Maximum, Minimum, Command |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment