Skip to content

[efficiency-improver] perf: avoid MethodInfo.GetParameters() allocation on every test invocation #9661

Description

@github-actions

Goal and Rationale

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

  1. 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.
  2. 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.
  3. 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.
  4. 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).
  5. 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).

ScenarioBeforeAfter
Non-generic data-driven, N rowsN ParameterInfo[] allocs at invocation0 (array already cached in ParameterTypes)
Generic data-driven, N rows2N ParameterInfo[] allocs at invocation0
Single-row / cleanup methods1 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.

Click here to create the pull request

To fix the permissions issue, go to SettingsActionsGeneral 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)

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/agentic-workflowsGitHub agentic workflow definitions under .github/workflows/*.md.area/performanceRuntime / build performance / efficiency.type/automationCreated or maintained by an agentic workflow.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions