Checkpoint-Benchmark.ps1
function Checkpoint-Benchmark { <# .Synopsis Checkpoints benchmarks .Description Checkpoints benchmark files, executing them and storing their results. .Link Measure-Benchmark .Link Get-Benchmark #> [CmdletBinding(DefaultParameterSetName='CurrentDirectory')] [OutputType([PSObject])] param( # The path to the benchmark file [Parameter(Mandatory=$true,ParameterSetName='Path',ValueFromPipelineByPropertyName=$true,Position=0)] [ValidatePattern('\.benchmark\.(psd1|ps1|clixml|csv|json)$')] [Alias('Fullname', 'FilePath')] [string] $BenchmarkPath, # The name of a module [Parameter(Mandatory=$true,ParameterSetName='Module',ValueFromPipelineByPropertyName=$true)] [string] $ModuleName, # The output path. If no OutputPath is provided, benchmarks will be executed and returned. # If a path to a folder is provided, a file will be created for each output [Parameter(ValueFromPipelineByPropertyName=$true)] [string] $OutputPath, # If set, will include the PSVersionInfo object in returned results. # If used with -OutputPath set to a folder, will include the PSVersion in the file names [Parameter(ValueFromPipelineByPropertyName=$true)] [switch] $IncludePSVersion, # If set, will include the module version in returned results # If used with -OutputPath set to a folder, will include the Module version in the file names [Parameter(ValueFromPipelineByPropertyName=$true,ParameterSetName='Module')] [switch] $IncludeModuleVersion, # If set, will not include a timestamp in output file names # This is only used is -OutputPath is passed a directory name [Parameter(ValueFromPipelineByPropertyName=$true)] [switch] $NoTimestamp ) begin { $getBenchmarkCmd = $ExecutionContext.SessionState.InvokeCommand.GetCommand('Get-Benchmark','Function') $measureBenchmarkCmd = $ExecutionContext.SessionState.InvokeCommand.GetCommand('Measure-Benchmark','Function') } process { #region Get Benchmarks $getBenchmarkSplat = @{} + $PSBoundParameters foreach ($_ in @($getBenchmarkSplat.Keys)) { if (-not $getBenchmarkCmd.Parameters[$_]) { $getBenchmarkSplat.Remove($_) } } $theBenchmarks = @(Get-Benchmark @getBenchmarkSplat) if (-not $theBenchmarks) { return } #endregion Get Benchmarks #region Run Benchmarks $benchmarkResults = [Collections.ArrayList]::new() $c, $t, $progID = 0, $theBenchmarks.Count, $(Get-Random) $theBenchmarks | . { process { $benchmark = $_ $c++ $p = $c * 100 / $t Write-Progress "Running Benchmarks" "$($benchmark.FileName)" -PercentComplete $p -Id $progID if ($Benchmark -is [Management.Automation.ExternalScriptInfo]) { & $Benchmark } else { $benchmarkSplat = @{} $props = @(if ($benchmark -is [Collections.IDictionary]) { $benchmark.Keys } else { foreach ($_ in $benchmark.psobject.properties) { $_.Name } }) foreach ($prop in $props) { $isGood? = $measureBenchmarkCmd.Parameters.ContainsKey($prop) if (-not $isGood?) { foreach ($param in $measureBenchmarkCmd.Parameters.Values) { if ($param.Aliases -contains $prop) { $isGood? = $true break } } } if ($isGood?) { $benchmarkSplat[$prop] = $benchmark.$prop } } if ($benchmarkSplat.Count) { Measure-Benchmark @benchmarkSplat } } } } | . { process { if ($OutputPath) { $null = $benchmarkResults.Add($_) } else { $_ } } } Write-Progress "Running Benchmarks" "Complete" -Id $progID -Completed if (-not $outputPath) { return } #endregion Run Benchmarks #region Save Benchmark Results $IsOutputFile? = $outputPath -match "\.(json|csv|clixml)$" $fileNameParts = if (-not $IsOutputFile?) { @([DateTime]::UtcNow.ToString('o').Substring(0,19).Replace(':','_') + 'Z') } else { @() } if ($IncludeModuleVersion -and $ModuleName) { $theModule = Get-Module $ModuleName $benchmarkResults | Add-Member NoteProperty ModuleVersion $theModule.Version -Force if (-not $IsOutputFile?) { $fileNameParts += "v$($theModule.Version)" } } if ($IncludePSVersion) { $benchmarkResults | Add-Member NoteProperty PSVersion $PSVersionTable -Force if ($IsOutputFile?) { $fileNameParts += "ps$($PSVersionTable.PSVersion)" } } if ($IsOutputFile?) { $null = $outputPath -match "\.(?<extension>json|csv|clixml)" if ($matches.extension -eq '.json') { $benchmarkResults | ConvertTo-Json -Depth 10 | Set-Content $OutputPath } elseif ($matches.extension -eq '.csv') { $benchmarkResults | Export-Csv -Path $OutputPath } elseif ($matches.extension -eq '.clixml') { $benchmarkResults| Export-Clixml -Path $OutputPath } } else { if (-not (Test-Path $OutputPath)) { $newDir = New-Item -ItemType Directory -Path $OutputPath if (-not $newDir) { return $benchmarkResults } } $resolvedBasePath = Resolve-Path $OutputPath $benchmarkResults | Group-Object FileName | & { process { $group = $_.Group $outFilePath = Join-Path $resolvedBasePath "$($_.Name).$($fileNameParts -join '.').marks.clixml" $group | Export-Clixml -Path $outFilePath } } } #endregion Save Benchmark Results } } |