test/Measure-QuietPerformance.ps1
|
#requires -Version 7.6 #requires -PSEdition Core [CmdletBinding()] param([int[]]$Records=@(2000,20000),[ValidateRange(1,10)][int]$Samples=2,[string]$OutputPath=(Join-Path $PSScriptRoot '../verification/v2-performance.json')) $ErrorActionPreference='Stop' $root=Split-Path -Parent $PSScriptRoot Import-Module (Join-Path $root 'FrenchExDev.QuietCli.PoSh.psd1') -DisableNameChecking $temporary=Join-Path ([IO.Path]::GetTempPath()) ('quietcli-benchmark-'+[guid]::NewGuid().ToString('N'));[void][IO.Directory]::CreateDirectory($temporary) $previous=@{};foreach($key in @('QUIETCLI_DB_PATH','QUIETCLI_CONFIG_PATH','QUIETCLI_TRACKING','QUIETCLI_RECALL')){$previous[$key]=[Environment]::GetEnvironmentVariable($key)} $sourceHashes=[ordered]@{};foreach($file in Get-ChildItem (Join-Path $root 'src') -File|Sort-Object Name){$sourceHashes[$file.Name]=(Get-FileHash $file.FullName -Algorithm SHA256).Hash} $results=[Collections.Generic.List[object]]::new() try{ $env:QUIETCLI_DB_PATH=Join-Path $temporary 'history.sqlite3';$env:QUIETCLI_CONFIG_PATH=Join-Path $temporary 'settings.json';$env:QUIETCLI_TRACKING='1';$env:QUIETCLI_RECALL='0' $engine=(Get-Process -Id $PID).Path foreach($count in $Records){ foreach($recording in @($false,$true)){ foreach($tokenizer in @('off','o200k_base')){ [IO.File]::WriteAllText($env:QUIETCLI_CONFIG_PATH,(@{Recall=$false;Tokenizer=$tokenizer}|ConvertTo-Json)) for($sample=0;$sample -le $Samples;$sample++){ $code='for($i=0;$i -lt '+$count+';$i++){[Console]::WriteLine("item-"+$i)}' $encoded=[Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($code));$state=@{Count=0L} $watch=[Diagnostics.Stopwatch]::StartNew() $result=Invoke-QuietCli -FilePath $engine -ArgumentList @('-NoProfile','-EncodedCommand',$encoded) -State $state -OnOutput {param($r,$s) if($r.Stream -eq 'stdout'){$s.Count++}} -Complete {param($s,$c) @{Count=$s.Count}} -Record:$recording $text=$result|ConvertTo-QuietJson;$watch.Stop() if($result.Outcome -ne 'Success' -or $result.Data.Count -ne $count){throw 'Benchmark semantic assertion failed.'} $results.Add(@{Records=$count;Record=$recording;Tokenizer=$tokenizer;Sample=$sample;Warmup=($sample -eq 0);ElapsedMs=$watch.Elapsed.TotalMilliseconds DeliveredBytes=[Text.Encoding]::UTF8.GetByteCount($text);Observed=$result.Data.Count;CaptureComplete=$result.Completeness.Capture;Measurement=$result.Measurement.Status}) $result.Capture.Dispose() } } } } }finally{foreach($key in $previous.Keys){[Environment]::SetEnvironmentVariable($key,$previous[$key])}} $groups=@($results|Where-Object {!$_.Warmup}|Group-Object Records,Record,Tokenizer|ForEach-Object { $sorted=@($_.Group.ElapsedMs|Sort-Object);$middle=[int][Math]::Floor($sorted.Count/2) $median=if($sorted.Count%2){$sorted[$middle]}else{($sorted[$middle-1]+$sorted[$middle])/2} @{Case=$_.Name;Samples=$sorted.Count;MedianMs=$median;MinMs=$sorted[0];MaxMs=$sorted[-1]} }) $report=@{SchemaVersion=2;ExecutedAtUtc=[DateTimeOffset]::UtcNow.ToString('o');Platform=$PSVersionTable.OS;PowerShell=$PSVersionTable.PSVersion.ToString() SourceSHA256=$sourceHashes;Note='Fresh native PowerShell child per sample; first sample per case excluded. This is a local workload measurement, not an overall speedup claim.';Groups=$groups;Samples=$results.ToArray()} [void][IO.Directory]::CreateDirectory((Split-Path -Parent ([IO.Path]::GetFullPath($OutputPath)))) [IO.File]::WriteAllText([IO.Path]::GetFullPath($OutputPath),($report|ConvertTo-Json -Depth 12),[Text.UTF8Encoding]::new($false)) @{Outcome='Success';Data=@{Groups=$groups;Report=[IO.Path]::GetFullPath($OutputPath)}}|ConvertTo-Json -Depth 10 -Compress |