Skip to content

Cache plugin step arrays and skip unused filter keys in the runtime#2915

Open
nohwnd wants to merge 1 commit into
mainfrom
nohwnd-perf-runtime-steps
Open

Cache plugin step arrays and skip unused filter keys in the runtime#2915
nohwnd wants to merge 1 commit into
mainfrom
nohwnd-perf-runtime-steps

Conversation

@nohwnd

@nohwnd nohwnd commented Jul 19, 2026

Copy link
Copy Markdown
Member

Three changes on the per-test path in Pester.Runtime.ps1:

  • Invoke-TestItem and Invoke-Block rebuilt the framework plugin step arrays from $state.Plugin via member enumeration for every test and block, and reversed the teardown copies each time. The plugin set cannot change during a run (the only assignment to $state.Plugin is in Invoke-Test, and all plugin objects are fully built before that), so the arrays are now precomputed once into $state.PluginSteps, with the teardown arrays stored already reversed. Invoke-ScriptBlock never mutates the arrays it receives, it filters them into fresh locals, so sharing one instance across all tests is safe.
  • Test-ShouldRun built the path:line key (string interpolation plus a regex -replace) and the dotted path (-join) for every discovered item, but they are only read by the Line/ExcludeLine/FullName filters and by debug messages. They are now computed only when one of those consumers is present, in the common no-filter run they are skipped entirely.
  • New-Test rebuilt the test path from the runtime stack (ToArray plus Reverse) on every call. The parent block already holds the same reversed path, so reuse it.

The plugin array caching alone is ~5-8us per test. A patched vs stock run produces identical output across Normal/Detailed/Diagnostic verbosity, and the Diagnostic trace shows the executed step sequence is unchanged.

Verification: full suite green on macOS (inline and dot-sourced build), Pester.Runtime.ts.ps1 (101 tests, drives the runtime directly including the plugin step ordering) and Pester.Rspec.Filtering.ts.ps1 pass in fresh processes.

Related perf PRs: #2914, #2916, #2917, #2918. Measured together they cut ~21% from four representative workloads (inline build, macOS).

🤖

Invoke-TestItem and Invoke-Block rebuilt the framework plugin step arrays
from $state.Plugin via member enumeration for every test and block, and
reversed the teardown copies each time. The plugin set cannot change during
a run (the only assignment is in Invoke-Test), so the arrays are now
precomputed once into $state.PluginSteps, with the teardown arrays stored
already reversed.

Test-ShouldRun built the path:line key and the dotted path for every
discovered item, but they are only read by the Line/ExcludeLine/FullName
filters and by debug messages. They are now computed only when one of those
consumers is present.

New-Test rebuilt the test path from the runtime stack on every call, the
parent block already holds the same reversed path, so reuse it.

🤖
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant