Skip to content

[efficiency-improver] perf: cache JsonSerializerOptions in performance runner steps #9714

Description

@github-actions

Goal and Rationale

Cache the JsonSerializerOptions { WriteIndented = true } instance as a private static readonly field in PlainProcess and DotnetTestProcess, removing CA1869 pragma suppressions that were previously hiding the issue.

Why this matters for energy efficiency:JsonSerializerOptions construction triggers reflection-based scanning of converter types and type metadata. Creating a new instance on every benchmark run means this work is repeated unnecessarily — in a tool specifically designed to measure performance, the tool itself should not incur avoidable overhead.

Focus Area

Code-Level Efficiency — eliminate unnecessary object construction and reflection work.

Changes

FileChange
test/Performance/MSTest.Performance.Runner/Steps/PlainProcess.csAdded private static readonly JsonSerializerOptions s_writeIndented; removed CA1869 pragma pair
test/Performance/MSTest.Performance.Runner/Steps/DotnetTestProcess.csSame

Energy Efficiency Evidence

Proxy metric: memory allocation / CPU reflection work

JsonSerializerOptions construction is not free — it registers built-in converters and initialises type metadata dictionaries. The CA1869 analyser exists precisely because repeated construction is recognised as a performance anti-pattern by the .NET team.

While the per-invocation cost is low (this code runs once per benchmark run, not per test), the principle of "benchmark tooling should be exemplary" applies directly. A tool that measures allocations should not itself generate avoidable ones.

Before:new JsonSerializerOptions { WriteIndented = true } created on every ExecuteAsync() call (once per scenario run).
After: single allocation at class-load time, reused for all subsequent calls.

Green Software Foundation Context

Hardware Efficiency: Removing reflection work at class-load time reduces unnecessary CPU cycles — however marginal — in line with the GSF principle that software should use as little hardware resource as needed.

Trade-offs

None. The change is purely mechanical — same behaviour, same output, no logic changes. Readability is unchanged; the static field name is self-documenting.

Reproducibility

# Build the performance runner
./build.sh # installs SDK first time
.dotnet/dotnet build test/Performance/MSTest.Performance.Runner/MSTest.Performance.Runner.csproj -f net9.0 -c Debug
# CA1869 now produces no warnings (previously suppressed with pragmas)

Test Status

Build not run (repo SDK 11.0.100-preview.5.26302.115 not provisioned in this environment). The changes are mechanical — the only modification is replacing new JsonSerializerOptions { WriteIndented = true } with a pre-allocated s_writeIndented static field of the same type. No logic changes.

🤖 Automated content by GitHub Copilot. Generated by the Efficiency Improver workflow. · 351.3 AIC · ⌖ 19.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

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-json-serializer-options-cf226ce60ce3db6d.

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 (79 of 79 lines)
From 8a9ec3abe2f116ba74f895665fa4a4c8e7317f3a Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Tue, 7 Jul 2026 22:13:17 +0000
Subject: [PATCH] perf: cache JsonSerializerOptions in performance runner steps
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Cache the shared JsonSerializerOptions instance as a static readonly
field in both PlainProcess and DotnetTestProcess, eliminating repeated
construction of JsonSerializerOptions on every benchmark run.
JsonSerializerOptions construction triggers reflection scanning of
converters and type metadata — caching it removes this work from
measured hot paths. Fixes CA1869 suppression pragmas that were
previously masking the issue.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../MSTest.Performance.Runner/Steps/DotnetTestProcess.cs | 6 +++---
.../MSTest.Performance.Runner/Steps/PlainProcess.cs | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/test/Performance/MSTest.Performance.Runner/Steps/DotnetTestProcess.cs b/test/Performance/MSTest.Performance.Runner/Steps/DotnetTestProcess.cs
index 9f2585f..49ce352 100644
--- a/test/Performance/MSTest.Performance.Runner/Steps/DotnetTestProcess.cs+++ b/test/Performance/MSTest.Performance.Runner/Steps/DotnetTestProcess.cs@@ -31,6 +31,8 @@ namespace MSTest.Performance.Runner.Steps;
/// </remarks>
internal class DotnetTestProcess : IStep<BuildArtifact, Files>
{
+ private static readonly JsonSerializerOptions s_writeIndented = new() { WriteIndented = true };+
private readonly string _reportFileName;
private readonly BuildConfiguration _buildConfiguration;
private readonly int _numberOfRun;
@@ -117,11 +119,9 @@ public async Task<Files> ExecuteAsync(BuildArtifact payload, IContext context)
results.Add(result);
}
-#pragma warning disable CA1869 // Cache and reuse 'JsonSerializerOptio
... (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