141 lines
5.4 KiB
PowerShell
141 lines
5.4 KiB
PowerShell
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$CompareCellMedianFile,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$AdaptCellMedianFile
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
function Convert-ToDouble([string]$Value, [string]$Column, [string]$Path) {
|
|
$number = 0.0
|
|
$style = [Globalization.NumberStyles]::Float
|
|
if ([double]::TryParse($Value, $style,
|
|
[Globalization.CultureInfo]::InvariantCulture, [ref]$number)) {
|
|
return $number
|
|
}
|
|
if ([double]::TryParse($Value, $style,
|
|
[Globalization.CultureInfo]::CurrentCulture, [ref]$number)) {
|
|
return $number
|
|
}
|
|
throw "Cannot parse '$Value' as $Column in $Path"
|
|
}
|
|
|
|
function Test-SelectedDeferred([string]$Structure) {
|
|
$base = ($Structure -split '@', 2)[0]
|
|
return $base -eq 'adaptive_shape_deferred' `
|
|
-or $base -eq 'adaptive_shape_default_deferred' `
|
|
-or $base -eq 'adaptive_shape_moderate_deferred'
|
|
}
|
|
|
|
function Test-CellFile([string]$Path, [string]$Suite) {
|
|
$resolved = (Resolve-Path -LiteralPath $Path).Path
|
|
$rows = @(Import-Csv -LiteralPath $resolved | Where-Object {
|
|
Test-SelectedDeferred $_.structure
|
|
})
|
|
if ($rows.Count -eq 0) {
|
|
throw "No selected deferred/default/moderate adaptive rows in $resolved"
|
|
}
|
|
$requiredWorkloads = if ($Suite -eq 'adapt') {
|
|
@('short_burst_negative_control', 'phase_10_uniform_10_local_80_read')
|
|
} else {
|
|
@('bursty_edit', 'phase_uniform_local_read')
|
|
}
|
|
foreach ($workload in $requiredWorkloads) {
|
|
if (-not @($rows | Where-Object { $_.workload -eq $workload }).Count) {
|
|
throw "Missing selected $Suite workload '$workload' in $resolved"
|
|
}
|
|
}
|
|
|
|
$failures = @()
|
|
foreach ($row in $rows) {
|
|
$switches = Convert-ToDouble $row.median_switches 'median_switches' $resolved
|
|
$leafRebuilds = Convert-ToDouble `
|
|
$row.median_leaf_rebuilds 'median_leaf_rebuilds' $resolved
|
|
$maxSwitches = 1.0
|
|
$maxLeafRebuilds = 1.0
|
|
$requireVector = $false
|
|
$class = 'stationary'
|
|
|
|
if ($row.workload -eq 'short_burst_negative_control') {
|
|
$maxSwitches = 0.0
|
|
$maxLeafRebuilds = 0.0
|
|
$requireVector = $true
|
|
$class = 'short-negative'
|
|
} elseif ($Suite -eq 'adapt' `
|
|
-and $row.workload -eq 'phase_10_uniform_10_local_80_read') {
|
|
$maxSwitches = 2.0
|
|
# The trace deliberately contains two different edit phases. One
|
|
# stable shape choice per phase is useful adaptation, not churn.
|
|
$maxLeafRebuilds = 2.0
|
|
# Returning to vector is optional: for wide/non-trivial values the
|
|
# measured O(N) conversion can cost more than the remaining read
|
|
# phase. The policy must avoid churn, not force an uneconomic
|
|
# second transition.
|
|
$class = 'adapt-exact-phase'
|
|
} elseif ($Suite -eq 'compare' `
|
|
-and $row.workload -eq 'phase_uniform_local_read') {
|
|
$maxSwitches = 2.0
|
|
$maxLeafRebuilds = 2.0
|
|
# The shorter compare phase, especially at smoke scale, may not
|
|
# provide enough read evidence to amortize a return to vector.
|
|
$class = 'compare-phase'
|
|
} elseif ($Suite -eq 'compare' -and $row.workload -eq 'bursty_edit') {
|
|
$maxSwitches = 2.0
|
|
$maxLeafRebuilds = 1.0
|
|
# As above, final tiered is valid when return conversion does not
|
|
# amortize within the observed read tail.
|
|
$class = 'bursty'
|
|
}
|
|
|
|
$modeFailure = $requireVector -and $row.final_mode -ne 'vector'
|
|
if ($switches -gt $maxSwitches `
|
|
-or $leafRebuilds -gt $maxLeafRebuilds `
|
|
-or $modeFailure) {
|
|
$failures += [pscustomobject]@{
|
|
suite = $Suite
|
|
class = $class
|
|
profile = $row.profile
|
|
type = $row.type
|
|
workload = $row.workload
|
|
n = $row.n
|
|
structure = $row.structure
|
|
switches = $switches
|
|
switch_limit = $maxSwitches
|
|
leaf_rebuilds = $leafRebuilds
|
|
leaf_rebuild_limit = $maxLeafRebuilds
|
|
final_mode = $row.final_mode
|
|
required_mode = if ($requireVector) { 'vector' } else { '*' }
|
|
}
|
|
}
|
|
}
|
|
|
|
[pscustomobject]@{
|
|
path = $resolved
|
|
checked = $rows.Count
|
|
failures = $failures
|
|
}
|
|
}
|
|
|
|
$compare = Test-CellFile $CompareCellMedianFile 'compare'
|
|
$adapt = Test-CellFile $AdaptCellMedianFile 'adapt'
|
|
$failures = @($compare.failures) + @($adapt.failures)
|
|
|
|
if ($failures.Count -ne 0) {
|
|
foreach ($failure in $failures) {
|
|
$message = ("FAIL {0}/{1}: {2} {3}/{4}/N={5}; " +
|
|
"switches={6} (limit {7}), leaf_rebuilds={8} (limit {9}), " +
|
|
"final_mode={10} (required {11})") -f
|
|
$failure.suite, $failure.class, $failure.structure,
|
|
$failure.type, $failure.workload, $failure.n,
|
|
$failure.switches, $failure.switch_limit,
|
|
$failure.leaf_rebuilds, $failure.leaf_rebuild_limit,
|
|
$failure.final_mode, $failure.required_mode
|
|
Write-Host $message
|
|
}
|
|
throw "Adaptation validation failed in $($failures.Count) selected cell(s)"
|
|
}
|
|
|
|
Write-Host "Adaptation validation passed: $($compare.checked) compare and $($adapt.checked) adapt cells."
|