You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
MethodInfo.GetParameters() is documented to return a new ParameterInfo[] copy on every call (CLR safety guarantee — the array is mutable, so the runtime can't share it). The test-invocation hot path in GetInvokeResultAsync called it unconditionally, allocating one fresh array per test invocation even when the same test method was being re-invoked for every row of a data-driven test.
For a [DataRow]-based test with N rows, this caused N unnecessary heap allocations per test run. For generic test methods, ConstructGenericMethod called GetParameters() a second time, doubling the allocation count.
Focus Area
Code-Level Efficiency — eliminating redundant object allocations in the test invocation hot path.
Approach
Add a new primary overload of GetInvokeResultAsync that accepts a pre-cached ParameterInfo[] methodParameters (inserted before the params argument). This is the hot path; callers that hold a cached array use this overload directly.
Keep the existing params-only overload as a thin wrapper that calls methodInfo.GetParameters() once and delegates. Non-hot-path callers (assembly/class cleanup methods) are unaffected.
Thread the cached array into ConstructGenericMethod — change its signature to accept ParameterInfo[] parameters instead of calling GetParameters() internally, eliminating the second allocation for generic test methods.
Update the two hot-path call sites in TestMethodInfo.Execution.cs to pass ParameterTypes (the already-cached ParameterInfo[] from TestMethodInfo.ParameterTypes, which uses a field ??= MethodInfo.GetParameters() lazy initialiser).
Clean up redundant ?. operators on the now-non-nullable parameter (these also caused a spurious CS8604 nullable warning).
Energy Efficiency Evidence
Proxy metric: memory allocation / GC pressure (lower allocation rate → less GC → less CPU time → less energy).
Scenario
Before
After
Non-generic data-driven, N rows
N ParameterInfo[] allocs at invocation
0 (array already cached in ParameterTypes)
Generic data-driven, N rows
2N ParameterInfo[] allocs at invocation
0
Single-row / cleanup methods
1 alloc (unchanged path)
1 alloc (via thin wrapper)
Reproducibility: instrument MethodInfo.GetParameters() calls or use a memory profiler (e.g. dotMemory, BenchmarkDotNet MemoryDiagnoser) on a data-driven test with 100+ rows. The hot-path allocations will drop from N to 0.
Green Software Foundation Context
Hardware Efficiency: Reducing GC pause frequency makes the CPU work proportional to actual test logic rather than memory management overhead. Each GC pause is CPU time that generates heat without advancing test execution.
Demand Shaping: Eliminating allocations proportional to data-row count means the marginal energy cost of adding more [DataRow] entries is reduced.
Trade-offs
API surface: The new overload is internal — no public API surface added.
Overload resolution: The new overload has a ParameterInfo[] parameter before params object?[]?. Existing callers continue to resolve to the params-only wrapper. No call-site changes are needed except the two hot-path sites explicitly updated.
Complexity: Minor — adds one overload and threads one parameter through one level. The thin-wrapper pattern keeps non-hot-path callers simple.
Test Status
Build: ✅ dotnet build MSTestAdapter.PlatformServices.csproj -f net8.0 -c Debug — succeeded, 0 new warnings (2 pre-existing CS8625 in an unrelated file).
🤖 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. · 579.7 AIC · ⌖ 24.4 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
Note
This was originally intended as a pull request, but GitHub Actions is not permitted to create or approve pull requests in this repository.
The changes have been pushed to branch efficiency/pass-params-to-invoke-8ee8f989ab835011.
To fix the permissions issue, go to Settings → Actions → General and enable Allow GitHub Actions to create and approve pull requests. See also: gh-aw FAQ
Show patch preview (161 of 161 lines)
From e82a45259c607222af71372cd28d1f9aa8cf6a0b Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Mon, 6 Jul 2026 22:29:38 +0000
Subject: [PATCH] perf: avoid MethodInfo.GetParameters() allocation on every
test invocation
GetInvokeResultAsync previously called MethodInfo.GetParameters() on
every invocation, allocating a fresh ParameterInfo[] each time even
for data-driven tests with hundreds of rows.
Changes:
- Add a new primary overload of GetInvokeResultAsync that accepts a
pre-cached ParameterInfo[] (placed before the params argument),
eliminating the per-call GetParameters() allocation.
- Keep the old params-only overload as a thin wrapper (non-hot-path
callers such as cleanup methods are unaffected).
- Thread the cached array into ConstructGenericMethod, removing the
second GetParameters() call for generic test methods.
- Update the two hot-path call sites in TestMethodInfo.Execution.cs
to pass the already-cached TestMethodInfo.ParameterTypes array.
- Remove redundant ?. null-conditional operators on the now-non-
nullable ParameterInfo[] parameter.
Energy impact (proxy: memory allocation / GC pressure):
- Non-generic data-driven test with N rows: N fewer ParameterInfo[]
allocations per run.
- Generic data-driven test with N rows: 2N fewer allocations per run
(GetInvokeResultAsync + ConstructGenericMethod).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../Execution/TestMethodInfo.Execution.cs | 4 +--
.../Extensions/MethodInfoExtensions.cs | 32 +++++++++++++------
2 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodInfo.Execution.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodInfo.Execution.cs
index 6515ea5..89069cb 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodInfo.Execution.cs+++ b/src/Adapter/MSTestAdapter.PlatformServi
... (truncated)
Goal and Rationale
MethodInfo.GetParameters()is documented to return a newParameterInfo[]copy on every call (CLR safety guarantee — the array is mutable, so the runtime can't share it). The test-invocation hot path inGetInvokeResultAsynccalled it unconditionally, allocating one fresh array per test invocation even when the same test method was being re-invoked for every row of a data-driven test.For a
[DataRow]-based test with N rows, this caused N unnecessary heap allocations per test run. For generic test methods,ConstructGenericMethodcalledGetParameters()a second time, doubling the allocation count.Focus Area
Code-Level Efficiency — eliminating redundant object allocations in the test invocation hot path.
Approach
GetInvokeResultAsyncthat accepts a pre-cachedParameterInfo[] methodParameters(inserted before theparamsargument). This is the hot path; callers that hold a cached array use this overload directly.params-only overload as a thin wrapper that callsmethodInfo.GetParameters()once and delegates. Non-hot-path callers (assembly/class cleanup methods) are unaffected.ConstructGenericMethod— change its signature to acceptParameterInfo[] parametersinstead of callingGetParameters()internally, eliminating the second allocation for generic test methods.TestMethodInfo.Execution.csto passParameterTypes(the already-cachedParameterInfo[]fromTestMethodInfo.ParameterTypes, which uses afield ??= MethodInfo.GetParameters()lazy initialiser).?.operators on the now-non-nullable parameter (these also caused a spurious CS8604 nullable warning).Energy Efficiency Evidence
Proxy metric: memory allocation / GC pressure (lower allocation rate → less GC → less CPU time → less energy).
ParameterInfo[]allocs at invocationParameterTypes)ParameterInfo[]allocs at invocationReproducibility: instrument
MethodInfo.GetParameters()calls or use a memory profiler (e.g. dotMemory, BenchmarkDotNetMemoryDiagnoser) on a data-driven test with 100+ rows. The hot-path allocations will drop from N to 0.Green Software Foundation Context
[DataRow]entries is reduced.Trade-offs
internal— no public API surface added.ParameterInfo[]parameter beforeparams object?[]?. Existing callers continue to resolve to theparams-only wrapper. No call-site changes are needed except the two hot-path sites explicitly updated.Test Status
Build: ✅
dotnet build MSTestAdapter.PlatformServices.csproj -f net8.0 -c Debug— succeeded, 0 new warnings (2 pre-existing CS8625 in an unrelated file).Add this agentic workflows to your repo
To install this agentic workflow, run
Note
This was originally intended as a pull request, but GitHub Actions is not permitted to create or approve pull requests in this repository.
The changes have been pushed to branch
efficiency/pass-params-to-invoke-8ee8f989ab835011.Click here to create the pull request
To fix the permissions issue, go to Settings → Actions → General and enable Allow GitHub Actions to create and approve pull requests. See also: gh-aw FAQ
Show patch preview (161 of 161 lines)