Skip to content

[efficiency-improver] perf: cache newline+color string in SimpleAnsiTerminal#8834

Merged
Evangelink merged 1 commit into
mainfrom
efficiency/simple-ansi-terminal-cache-newline-color-4c6453f2dadd0685
Jun 5, 2026
Merged

[efficiency-improver] perf: cache newline+color string in SimpleAnsiTerminal#8834
Evangelink merged 1 commit into
mainfrom
efficiency/simple-ansi-terminal-cache-newline-color-4c6453f2dadd0685

Conversation

@Evangelink
Copy link
Copy Markdown
Member

🤖 Efficiency Improver — automated AI assistant focused on reducing the energy consumption and computational footprint of this repository.

Goal and Rationale

Eliminate a per-call heap allocation in SimpleAnsiTerminal.SetColorPerLine. This method is called on every Append and AppendLine invocation while a foreground color is active — which is the common case during any colored test run in a CI environment (Azure DevOps, GitHub Actions, etc.).

Focus Area

Code-Level Efficiency — unnecessary object allocation per terminal write.

Approach

Previously, SetColorPerLine constructed the replacement string $"\n{_foregroundColor}" on every call:

// Before: allocates "\n" + _foregroundColor on every Append/AppendLine
private string? SetColorPerLine(string value)
    => _foregroundColor == null ? value : value.Replace("\n", $"\n{_foregroundColor}");

Since _foregroundColor only changes when SetColor or ResetColor is called, the "\n" + _foregroundColor string can be cached at color-change time and reused for all subsequent writes:

// After: compute once in SetColor, reuse on every Append/AppendLine
private string? _newlineAndColor; // cached "\n" + _foregroundColor

public override void SetColor(TerminalColor color)
{
    string setColor = $"{AnsiCodes.CSI}{(int)color}{AnsiCodes.SetColor}";
    _foregroundColor = setColor;
    _newlineAndColor = "\n" + setColor; // computed once per color change
    ...
}

public override void ResetColor()
{
    _foregroundColor = null;
    _newlineAndColor = null; // cleared on reset
    ...
}

private string? SetColorPerLine(string value)
    => _newlineAndColor == null ? value : value.Replace("\n", _newlineAndColor); // no allocation

Energy Efficiency Evidence

Proxy metric: heap allocation count.

  • Before: 1 short-lived string object allocated per Append/AppendLine call when a color is active
  • After: 0 allocations per call — the replacement string is computed once per SetColor invocation

SimpleAnsiTerminal is used in CI environments that support ANSI but not full cursor control (Azure DevOps, GitHub Actions, etc.). A test run producing 1 000 colored output lines would previously allocate ~1 000 unnecessary small strings (~10–15 bytes each). These all become GC garbage immediately, adding pressure on the GC and wasting CPU cycles reclaiming them.

GSF — Hardware Efficiency: fewer short-lived heap objects → less GC work → better utilization of CPU and DRAM already in use.

Trade-offs

  • An additional string? field (_newlineAndColor) is added to SimpleAnsiTerminal. This is negligible — one pointer-sized field on a per-session singleton.
  • No behaviour change: _newlineAndColor is always "\n" + _foregroundColor when non-null, matching the previous inline computation exactly.

Reproducibility

./build.sh          # verify build succeeds

Unit test coverage: TerminalTestReporterTests.SimpleAnsiTerminal_OutputFormattingIsCorrect exercises colored output through SimpleAnsiTerminal.

Test Status

✅ Build succeeded (0 errors, 0 warnings)
Microsoft.Testing.Platform.UnitTests — all tests passed

Generated by Efficiency Improver · sonnet46 7.7M ·

Add this agentic workflows to your repo

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/efficiency-improver.md@main

…all allocation

SetColorPerLine previously computed $"\\n{\_foregroundColor}" on every
Append/AppendLine call when a color was active.  Add a `_newlineAndColor`
field that is populated once inside SetColor (and cleared in ResetColor),
so the replacement string is built at most once per color-change rather
than once per terminal write.

Proxy metric: heap allocation.
In a typical colored test run (CI output) this eliminates one small string
allocation per colored Append/AppendLine call, reducing GC pressure.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 4, 2026 22:28
@Evangelink Evangelink added area/performance Runtime / build performance / efficiency. type/automation Created or maintained by an agentic workflow. labels Jun 4, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR optimizes Microsoft.Testing.Platform’s ANSI terminal output by removing a per-call string allocation in SimpleAnsiTerminal.SetColorPerLine, which is invoked for every Append/AppendLine while a foreground color is active (common during colored CI logs).

Changes:

  • Cache the computed newline+color prefix ("\n" + setColor) once per SetColor call.
  • Reuse the cached value in SetColorPerLine to avoid allocating the same replacement string on every append.
  • Clear the cached value in ResetColor to keep state consistent.
Show a summary per file
File Description
src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/SimpleAnsiTerminal.cs Adds _newlineAndColor cache and uses it in SetColorPerLine to eliminate repeated newline+color string allocations during colored output.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0

@Evangelink Evangelink marked this pull request as ready for review June 5, 2026 07:28
@Evangelink Evangelink enabled auto-merge (squash) June 5, 2026 07:28
@Evangelink Evangelink merged commit d29f6a1 into main Jun 5, 2026
38 checks passed
@Evangelink Evangelink deleted the efficiency/simple-ansi-terminal-cache-newline-color-4c6453f2dadd0685 branch June 5, 2026 08:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/performance Runtime / build performance / efficiency. type/automation Created or maintained by an agentic workflow.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants