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
Eliminate redundant ParameterInfo[] allocations in the data-driven test hot path. MethodInfo.GetParameters() is a CLR method that always returns a freshly allocated array (CLR safety guarantee). For a test with N data rows every row triggers one or more such allocations, creating O(N) heap pressure that is avoidable.
Focus area: Code-Level Efficiency — unnecessary object creation on a per-row hot path.
Approach
Three targeted changes:
1. ReflectionTestMethodInfo.GetParameters() — cache result
ReflectionTestMethodInfo wraps an immutable MethodInfo and is used to compute row display names. The parameter list cannot change between calls, so caching is safe.
2. TestMethodInfo.ResolveArguments() — use cached ParameterTypes
PR #9514 added ParameterTypes (lazy-cached MethodInfo.GetParameters()) to TestMethodInfo, but ResolveArguments() was left calling the raw method, bypassing the cache. This fixes the oversight.
3. TestMethodRunner._cachedReflectionMethodInfo — reuse wrapper across rows
// Before (in ExecuteTestWithDataSourceAsync — called once per row)varreflectionMethodInfo=newReflectionTestMethodInfo(_testMethodInfo.MethodInfo,_test.DisplayName);// After_cachedReflectionMethodInfo??=newReflectionTestMethodInfo(_testMethodInfo.MethodInfo,_test.DisplayName);
_testMethodInfo.MethodInfo and _test.DisplayName are both immutable for the TestMethodRunner lifetime, so the wrapper can safely be cached as a field and shared across all data rows.
Energy Efficiency Evidence
Proxy metric used: Heap allocation count — directly maps to GC pressure and the CPU energy spent on GC collection cycles.
Scenario
Before
After
ReflectionTestMethodInfo instances per data-driven test
N
1
ParameterInfo[] from GetParameters() in display-name path
N
1
ParameterInfo[] from GetParameters() in ResolveArguments()
N
1
N = number of data rows. For a [DynamicData] test providing 100 rows, this reduces from ~300 short-lived heap objects (3 × N) to 3 total — a 99% reduction in these allocations.
Reproducibility: Run any data-driven MSTest test under a profiler (dotnet-trace / BenchmarkDotNet with MemoryDiagnoser) to observe allocation counts per row before and after this change.
Green Software Foundation Context
Hardware Efficiency / Demand Shaping: Reduced GC frequency means the runtime reclaims CPU resources for actual test execution rather than collection bookkeeping. On energy-proportional hardware, lower background CPU demand translates directly to lower power draw during test runs.
Trade-offs
The cached ParameterInfo[] in ReflectionTestMethodInfo must not be mutated by callers. All existing call sites read the array without mutation (display-name formatting, parameter-count checks), so this is safe. The existing ITestMethod.ParameterTypes interface contract (which clones the array for external consumers) is unchanged.
The _cachedReflectionMethodInfo field is null for non-data-driven tests, adding 8 bytes to TestMethodRunner instances with no behavioural change.
Test Status
✅ ./build.sh — build succeeded, 0 warnings
✅ ./build.sh -test — all unit tests passed (MTP-hosted suite)
i️ MSTestAdapter-internal tests not run locally (CI-only; handled separately per repo convention)
🤖 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. · 177.3 AIC · ⌖ 21.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/cache-getparameters-across-data-rows-31a88443c00219eb.
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 (110 of 110 lines)
From 4a4f8ce1bae6cea21822017e340049cf98731b51 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Sat, 4 Jul 2026 22:10:21 +0000
Subject: [PATCH] perf: cache GetParameters() and ReflectionTestMethodInfo
across data rows
Three micro-optimisations that eliminate redundant ParameterInfo[] allocations
for every row in a data-driven test run:
1. ReflectionTestMethodInfo.GetParameters():
MethodInfo.GetParameters() allocates a fresh ParameterInfo[] on every call
(CLR safety guarantee). Cache with _parameters ??= _methodInfo.GetParameters()
so all callers on the same wrapper share a single allocation.
2. TestMethodInfo.ResolveArguments():
Was calling MethodInfo.GetParameters() directly, bypassing the cached
TestMethodInfo.ParameterTypes property added in #9514. Switch to ParameterTypes.
3. TestMethodRunner._cachedReflectionMethodInfo:
ExecuteTestWithDataSourceAsync() created a new ReflectionTestMethodInfo per
data row. Since both wrapped MethodInfo and DisplayName are immutable for the
TestMethodRunner lifetime, cache the wrapper so N rows share one instance.
Impact (proxy metric: heap allocations per data-driven test execution):
- Before: N ReflectionTestMethodInfo + N ParameterInfo[] from GetParameters()
in the display-name path, plus N ParameterInfo[] in ResolveArguments()
- After: 1 ReflectionTestMethodInfo + 1 ParameterInfo[] shared across N rows
(N = number of data rows supplied by the ITestDataSource/DynamicData attribute)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../Execution/TestMethodInfo.ArgumentResolution.cs | 2 +-
.../Execution/TestMethodRunner.cs | 12 +++++++++---
.../Internal/ReflectionTestMethodInfo.cs | 6 +++++-
3 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodInfo.ArgumentResolution.cs b/src/Adapter/MSTestAdapter.PlatformS
... (truncated)
Goal and Rationale
Eliminate redundant
ParameterInfo[]allocations in the data-driven test hot path.MethodInfo.GetParameters()is a CLR method that always returns a freshly allocated array (CLR safety guarantee). For a test with N data rows every row triggers one or more such allocations, creating O(N) heap pressure that is avoidable.Focus area: Code-Level Efficiency — unnecessary object creation on a per-row hot path.
Approach
Three targeted changes:
1.
ReflectionTestMethodInfo.GetParameters()— cache resultReflectionTestMethodInfowraps an immutableMethodInfoand is used to compute row display names. The parameter list cannot change between calls, so caching is safe.2.
TestMethodInfo.ResolveArguments()— use cachedParameterTypesPR #9514 added
ParameterTypes(lazy-cachedMethodInfo.GetParameters()) toTestMethodInfo, butResolveArguments()was left calling the raw method, bypassing the cache. This fixes the oversight.3.
TestMethodRunner._cachedReflectionMethodInfo— reuse wrapper across rows_testMethodInfo.MethodInfoand_test.DisplayNameare both immutable for theTestMethodRunnerlifetime, so the wrapper can safely be cached as a field and shared across all data rows.Energy Efficiency Evidence
Proxy metric used: Heap allocation count — directly maps to GC pressure and the CPU energy spent on GC collection cycles.
ReflectionTestMethodInfoinstances per data-driven testParameterInfo[]fromGetParameters()in display-name pathParameterInfo[]fromGetParameters()inResolveArguments()N = number of data rows. For a
[DynamicData]test providing 100 rows, this reduces from ~300 short-lived heap objects (3 × N) to 3 total — a 99% reduction in these allocations.Reproducibility: Run any data-driven MSTest test under a profiler (dotnet-trace / BenchmarkDotNet with MemoryDiagnoser) to observe allocation counts per row before and after this change.
Green Software Foundation Context
Hardware Efficiency / Demand Shaping: Reduced GC frequency means the runtime reclaims CPU resources for actual test execution rather than collection bookkeeping. On energy-proportional hardware, lower background CPU demand translates directly to lower power draw during test runs.
Trade-offs
ParameterInfo[]inReflectionTestMethodInfomust not be mutated by callers. All existing call sites read the array without mutation (display-name formatting, parameter-count checks), so this is safe. The existingITestMethod.ParameterTypesinterface contract (which clones the array for external consumers) is unchanged._cachedReflectionMethodInfofield isnullfor non-data-driven tests, adding 8 bytes toTestMethodRunnerinstances with no behavioural change.Test Status
./build.sh— build succeeded, 0 warnings./build.sh -test— all unit tests passed (MTP-hosted suite)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/cache-getparameters-across-data-rows-31a88443c00219eb.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 (110 of 110 lines)