Summary
MethodInfo.GetParameters() is a CLR-guaranteed allocation: it always returns a freshly allocated ParameterInfo[] for safety (even for repeated calls on the same method). TestMethodInfo already caches this result in the ParameterTypes property (added in PR #9514), but GetInvokeResultAsync never sees that cache — it receives only the raw MethodInfo and therefore re-calls GetParameters() on every single test invocation.
For generic test methods the situation is worse: GetParameters() was called twice per invocation — once at the top of GetInvokeResultAsync and once inside ConstructGenericMethod.
Changes
Branch: efficiency/pass-cached-params-to-invoke (1 commit: 0bc0bb6)
src/Adapter/MSTestAdapter.PlatformServices/Extensions/MethodInfoExtensions.cs | +37 / -12
src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodInfo.Execution.cs| +2 / -2
MethodInfoExtensions.cs
- Added hot-path overload
GetInvokeResultAsync(MethodInfo, object?, object?[]?, ParameterInfo[]) that accepts pre-cached parameters.
- Extracted private
GetInvokeResultAsyncCore(...) so both overloads share one implementation (DRY, no behaviour change).
ConstructGenericMethod now accepts ParameterInfo[] cachedParameters instead of calling methodInfo.GetParameters() internally — eliminates the double-allocation for generic tests.
TestMethodInfo.Execution.cs
- Both hot-path call sites (lines 147 and 164) updated to pass
ParameterTypes (the already-cached property) to the new overload.
Energy Efficiency Evidence
Proxy metric: heap allocation / GC pressure (maps to energy via: fewer short-lived allocations → fewer GC collections → fewer CPU stalls due to GC → less energy drawn from DRAM and CPU during GC sweeps).
| Scenario |
Before |
After |
| Plain test (non-generic, non-data-driven) |
1 ParameterInfo[] alloc per call |
0 allocations (served from cache) |
| Data-driven test, N rows, non-generic |
N ParameterInfo[] allocs per run |
0 allocations |
| Data-driven test, N rows, generic method |
2N ParameterInfo[] allocs per run |
0 allocations |
For a typical parameterized suite with 1000 data rows, this removes ~1000+ unnecessary short-lived heap allocations per test run.
GSF Principle: Hardware Efficiency — reducing GC frequency makes better use of the CPU and DRAM that are physically powering the test host.
Relationship to existing work
Validation
The SDK required to build locally is .NET 11.0.100-preview (Arcade-provisioned via ./build.sh). CI will run the full test suite on PR open.
To review: main...efficiency/pass-cached-params-to-invoke
🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Efficiency Improver workflow. · 400.5 AIC · ⌖ 11.3 AIC · ⊞ 13.6K · [◷]( · ◷)
Add this agentic workflows to your repo
To install this agentic workflow, run
gh aw add githubnext/agentics/workflows/efficiency-improver.md@main
Summary
MethodInfo.GetParameters()is a CLR-guaranteed allocation: it always returns a freshly allocatedParameterInfo[]for safety (even for repeated calls on the same method).TestMethodInfoalready caches this result in theParameterTypesproperty (added in PR #9514), butGetInvokeResultAsyncnever sees that cache — it receives only the rawMethodInfoand therefore re-callsGetParameters()on every single test invocation.For generic test methods the situation is worse:
GetParameters()was called twice per invocation — once at the top ofGetInvokeResultAsyncand once insideConstructGenericMethod.Changes
Branch:
efficiency/pass-cached-params-to-invoke(1 commit:0bc0bb6)MethodInfoExtensions.csGetInvokeResultAsync(MethodInfo, object?, object?[]?, ParameterInfo[])that accepts pre-cached parameters.GetInvokeResultAsyncCore(...)so both overloads share one implementation (DRY, no behaviour change).ConstructGenericMethodnow acceptsParameterInfo[] cachedParametersinstead of callingmethodInfo.GetParameters()internally — eliminates the double-allocation for generic tests.TestMethodInfo.Execution.csParameterTypes(the already-cached property) to the new overload.Energy Efficiency Evidence
Proxy metric: heap allocation / GC pressure (maps to energy via: fewer short-lived allocations → fewer GC collections → fewer CPU stalls due to GC → less energy drawn from DRAM and CPU during GC sweeps).
ParameterInfo[]alloc per callParameterInfo[]allocs per runParameterInfo[]allocs per runFor a typical parameterized suite with 1000 data rows, this removes ~1000+ unnecessary short-lived heap allocations per test run.
GSF Principle: Hardware Efficiency — reducing GC frequency makes better use of the CPU and DRAM that are physically powering the test host.
Relationship to existing work
ReflectionTestMethodInfoand removes the TCS bridge. This PR targets a separate call site that perf: reduce allocations in data-driven test execution hot path #9617 does not cover (MethodInfoExtensions.GetInvokeResultAsync).TestMethodInfo.ParameterTypes; this PR threads that cache all the way to the invocation call.Validation
The SDK required to build locally is .NET 11.0.100-preview (Arcade-provisioned via
./build.sh). CI will run the full test suite on PR open.To review: main...efficiency/pass-cached-params-to-invoke
Add this agentic workflows to your repo
To install this agentic workflow, run