[efficiency-improver] Single-pass min/max for Azure DevOps result date aggregation
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 25/100
- Issue type
- Refactor
- Clarity
- Clearly specified
- Activity status
- Stale
- Tech stack
- csharp
- Domain
- testing-qa
Research direction
Review AzureDevOpsResultIdStore.cs and AzureDevOpsResultIdStore.AttemptHistory.cs, starting with GetEarliestStartedDate and GetLatestCompletedDate. Run the AzureDevOps-filtered Microsoft.Testing.Extensions.UnitTests suite and build.sh. Done means both method pairs use the intended single-pass aggregation without public API changes and the reported tests and formatting checks pass.
Written by the indexing model from the issue text.
Description
[!TIP]
Your pull request is ready to create! 🎉 ✅Everything is OK—the changes have been pushed to branch
efficiency/azuredevops-single-pass-min-max-1d374458b554a417. Please review the changes, including any protected files, before creating the pull request.The original pull request description is below.
Goal and rationale
AzureDevOpsResultIdStore.GetEarliestStartedDate/GetLatestCompletedDate (public AzureDevOpsTestCaseResult overload in AzureDevOpsResultIdStore.cs, plus the internal AzureDevOpsTestSubResult overload in AzureDevOpsResultIdStore.AttemptHistory.cs) used attempts.Where(a => a.X is not null).Min/Max(a => a.X). Each pair of calls is always invoked together from the AzureDevOps live-publishing result-flush hot path, so every invocation double-enumerated the attempts list and allocated a Where iterator per call, for no benefit over a single manual pass.
Focus area
Code-Level Efficiency — replacing a LINQ-based double-enumeration with a single-pass loop.
Approach
Replaced both Where().Min()/Where().Max() chains (4 methods total across the two files) with manual single-pass foreach loops tracking a running min/max, mirroring the existing hand-rolled SumDurations/AddDurations pattern already present in the same files. No public API signature changes.
Energy efficiency evidence
Proxy metrics: execution time (wall clock) and memory allocation (GC.GetAllocatedBytesForCurrentThread()), both mapping directly to reduced CPU cycles and reduced GC pressure — i.e. lower energy draw per call, consistent with the Green Software Foundation's Hardware Efficiency principle (doing the same work with less computation).
Standalone console benchmark (net8.0 Release, Stopwatch + GC.GetAllocatedBytesForCurrentThread(), 2,000,000 call-pairs of GetEarliestStartedDate+GetLatestCompletedDate over a representative 5-element attempts list):
| Old (LINQ) | New (single-pass loop) | Delta | |
|---|---|---|---|
| Time | 581 ms | 308 ms | ~1.9x faster |
| Allocated | 288,000,040 B | 160,000,040 B | ~44% less allocation |
This is a hot path invoked once per result flush during AzureDevOps live test-result publishing, so the reduction compounds across large test runs.
Trade-offs
Slightly more verbose than the LINQ one-liners, but the same shape as the existing SumDurations helper in the same file, so it's consistent with the surrounding code style rather than introducing a new pattern. No readability concerns beyond that.
Reproducibility
Benchmark: standalone console app (net8.0, -c Release) exercising both implementations with the same synthetic attempts list, measuring Stopwatch.ElapsedMilliseconds and GC.GetAllocatedBytesForCurrentThread() deltas across 2,000,000 call-pairs (warmup of 1,000 iterations before each measured loop, GC.Collect() before each measurement).
Test status
./build.sh: Build succeeded, 0 warnings, 0 errors.Microsoft.Testing.Extensions.UnitTests(net8.0, full suite): 1839/1839 passed (37 pre-existing skips).Microsoft.Testing.Extensions.UnitTestsfiltered toFullyQualifiedName~AzureDevOps: 387/387 passed.dotnet format whitespace TestFx.slnx --verify-no-changes --include <both changed files>: clean, no formatting issues.
[!NOTE]
GitHub Actions is not permitted to create or approve pull requests in this repository.
The changes have been pushed to branch
efficiency/azuredevops-single-pass-min-max-1d374458b554a417and are ready to review.
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 (32 of 105 lines)
From 9e3ace0ad133c61d5b334fd981c366325772c36b Mon Sep 17 00:00:00 2001
X-GH-AW-Base-Commit: f0fe5a89980d2b29daeb3c949c08d7f61b9cf939
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Sun, 20 Sep 2026 21:51:26 +0000
Subject: [PATCH] Use single-pass loops for AzureDevOps result date aggregation
Replace Where().Min()/Where().Max() LINQ chains with manual single-pass
foreach loops tracking running min/max in AzureDevOpsResultIdStore's
GetEarliestStartedDate/GetLatestCompletedDate (both the public
AzureDevOpsTestCaseResult overload and the internal
AzureDevOpsTestSubResult overload). Mirrors the existing hand-rolled
SumDurations/AddDurations pattern already used in the same files.
Both method pairs are invoked together per-attempt from the AzureDevOps
live-publishing result-flush hot path, so each call previously
double-enumerated the attempts list and allocated a Where iterator.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
...AzureDevOpsResultIdStore.AttemptHistory.cs | 26 +++++++++++++++++--
.../AzureDevOpsResultIdStore.cs | 26 +++++++++++++++++--
2 files changed, 48 insertions(+), 4 deletions(-)
diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsResultIdStore.AttemptHistory.cs b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsResultIdStore.AttemptHistory.cs
index 3ae5eda..a03f7e7 100644
--- a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsResultIdStore.AttemptHistory.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsResultIdStore.AttemptHistory.cs
@@ -59,10 +59,32 @@ or AzureDevOpsLivePublishingConstants.NotExecutedTestOutcome
: right.Value > long.MaxValue - left.Value ? long.MaxValue : left.Value + right.Value;
private static DateTimeOffset? GetEarliestStartedDate(IReadOnlyList<AzureDevOpsTestSubResult> attempts)
- => attempts.Where(attempt => attemp
... (truncated)
[!WARNING]
Firewall blocked 1 domain
The following domain was blocked by the firewall during workflow execution:
southcentralus0.in.applicationinsights.azure.comTo allow these domains, add them to the
network.allowedlist in your workflow frontmatter:network: allowed: - defaults - "southcentralus0.in.applicationinsights.azure.com"See Network Configuration for more information.
🤖 Automated content by GitHub Copilot. Generated by the Efficiency Improver workflow. · copilot · auto · 168.8 AIC · ⌖ 13.9 AIC · ⊞ 17.8K · [◷]( · ◷)
Add this agentic workflow to your repo
To install this agentic workflow, run
gh aw add githubnext/agentics/workflows/efficiency-improver.md@main
- Dominant language
- C#
- Stars
- 1k
- Forks
- 312
- Avg merge
- 7h 46m
- Merged PRs (30d)
- 465
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from microsoft/testfx
-
agentic-workflows area/performance type/automation
Difficulty 3/5 1-2 days Newbie friendliness 15/100
-
area/mtp-observability needs/triage
Difficulty 3/5 1-2 days Newbie friendliness 25/100
-
agentic-workflows area/performance type/automation
Difficulty 2/5 1-3 hours Newbie friendliness 25/100
-
agentic-workflows area/performance type/automation
Difficulty 3/5 1-2 days Newbie friendliness 25/100
-
agentic-workflows
Difficulty 3/5 1-2 days Newbie friendliness 25/100
All issues in microsoft/testfx
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
-
:watch: Not Triaged 11.0 fundamentals/subsvc
Difficulty 2/5 1-3 hours Newbie friendliness 92/100
dotnet/AspNetCore.Docs#37699 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
SubtitleEdit/subtitleedit#15108 · 1 comment ·
-
area/docs-content Bug pulumi/docs
Difficulty 1/5 1-3 hours Newbie friendliness 94/100
-
agentic-workflows untriaged
Difficulty 2/5 1-3 hours Newbie friendliness 76/100