[efficiency-improver] perf: single-pass PropertyBag walk in OpenTelemetryResultHandler.HandleTestResult - #8938

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
efficiency/otel-single-pass-property-walk-00e4dea485646cad
Jun 9, 2026
Merged

[efficiency-improver] perf: single-pass PropertyBag walk in OpenTelemetryResultHandler.HandleTestResult#8938
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
efficiency/otel-single-pass-property-walk-00e4dea485646cad

Conversation

@Evangelink

Copy link
Copy Markdown
Member

🤖 This is a draft PR created by Efficiency Improver, an automated AI assistant focused on reducing the energy consumption and computational footprint of this repository.

Goal and Rationale

Reduce redundant CPU work and heap allocations in OpenTelemetryResultHandler.HandleTestResult(), which runs on every completed test when OpenTelemetry is enabled.

Focus area: Code-Level Efficiency — eliminating unnecessary heap allocations and CPU-cycle waste from repeated linked-list traversal.

Before

HandleTestResult made 5 separatePropertyBag linked-list walks per test result:

testNode.Properties.SingleOrDefault<TimingProperty>()// walk 1
testNode.Properties.OfType<TestMetadataProperty>()// walk 2 + TProperty[] alloc
testNode.Properties.SingleOrDefault<StandardOutputProperty>()// walk 3
testNode.Properties.SingleOrDefault<StandardErrorProperty>()// walk 4
testNode.Properties.OfType<FileArtifactProperty>()// walk 5 + TProperty[] alloc

OfType<T>() always allocates a TProperty[] — even when zero properties match (it returns Array.Empty<T>(), which avoids the empty-array allocation but still performs the full traversal).

After

A single GetStructEnumerator() pass handles all five properties in one traversal:

  • 1 linked-list walk (down from 5 — a 5× reduction)
  • 0 array allocations from OfType<T>() (down from 2 per test result)

GetStructEnumerator() returns the internal struct enumerator by value (no boxing, no heap allocation). It is accessible here because OpenTelemetryResultHandler lives in the same Microsoft.Testing.Platform assembly as PropertyBag.

Energy Efficiency Evidence

Proxy metrics: Heap allocations and CPU cycles from linked-list traversal, both directly proportional to energy consumption.

MetricBeforeAfterSaving (per completed test)
PropertyBag linked-list walks51−4 walks
TProperty[] heap allocations from OfType<T>()20−2 allocations

For a 10 000-test run with OTel enabled:

  • ~40 000 fewer linked-list node traversals
  • ~20 000 fewer short-lived array heap allocations → reduced GC pressure

Proxy-based reasoning caveat: actual energy reduction depends on property bag sizes, CPU architecture, and GC behaviour. The savings are modest per test but accumulate linearly with test-suite size.

Green Software Foundation Context

Hardware Efficiency: Reducing GC pressure frees CPU cycles from collection pauses, making better use of the underlying hardware.

Energy Proportionality: The change makes the OTel-enabled code path use compute more proportional to the actual number of test results produced.

Trade-offs

  • The refactored block is slightly longer (38 LOC vs. 15 LOC) due to the switch statement.
  • Tags that were previously set in a fixed order (timing → metadata → stdout → stderr → artifacts) are now set in property-bag iteration order. OTel exporters treat tags as unordered key-value pairs, so this has no semantic impact.

Reproducibility

./build.sh -build
dotnet run --project test/UnitTests/Microsoft.Testing.Platform.UnitTests \
-f net8.0 --no-build -c Debug
# Expected: 1106 tests pass, 0 failures

Test Status

✅ All 1106 unit tests pass (Microsoft.Testing.Platform.UnitTests, net8.0, Debug, no failures).

Generated by Efficiency Improver · sonnet46 12M ·

Add this agentic workflows to your repo

To install this agentic workflow, run

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

…leTestResult
Replace five separate PropertyBag walks in HandleTestResult
(SingleOrDefault<TimingProperty>, OfType<TestMetadataProperty>,
SingleOrDefault<StandardOutputProperty>, SingleOrDefault<StandardErrorProperty>,
OfType<FileArtifactProperty>) with a single GetStructEnumerator() pass.
This eliminates two TProperty[] heap allocations from OfType<T>() and
reduces linked-list traversal from 5 to 1 per test result when OTel is
enabled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 8, 2026 22:39
@EvangelinkAmaury Levé (Evangelink) added area/performance Runtime / build performance / efficiency. type/automation Created or maintained by an agentic workflow. labels Jun 8, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 the OpenTelemetry test-result reporting path in Microsoft.Testing.Platform by switching OpenTelemetryResultHandler.HandleTestResult() from multiple PropertyBag queries to a single struct-enumerator pass, reducing repeated linked-list traversal and avoiding OfType<T>() array allocations.

Changes:

  • Refactors HandleTestResult() to collect timing, metadata, stdout/stderr, and file artifacts in one GetStructEnumerator() walk.
  • Removes OfType<T>() usage for metadata and file artifacts to avoid per-result array allocations.
  • Defers setting test.stdout / test.stderr tags until after the single pass.
Show a summary per file
FileDescription
src/Platform/Microsoft.Testing.Platform/Telemetry/OpenTelemetryResultHandler.csConsolidates property extraction into a single PropertyBag walk for lower per-test overhead when OpenTelemetry is enabled.

Copilot's findings

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

@Evangelink
Amaury Levé (Evangelink) marked this pull request as ready for review June 9, 2026 06:52
…walk
Track timing/stdout/stderr properties during the PropertyBag walk and
throw InvalidOperationException if a duplicate is encountered, matching
the prior SingleOrDefault<T>() behavior the refactor inadvertently changed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) merged commit 8d72aa4 into mainJun 9, 2026
32 of 34 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the efficiency/otel-single-pass-property-walk-00e4dea485646cad branch June 9, 2026 09:00
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/performanceRuntime / build performance / efficiency.type/automationCreated or maintained by an agentic workflow.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[efficiency-improver] perf: single-pass PropertyBag walk in OpenTelemetryResultHandler.HandleTestResult - #8938

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
efficiency/otel-single-pass-property-walk-00e4dea485646cad
Jun 9, 2026
Merged

[efficiency-improver] perf: single-pass PropertyBag walk in OpenTelemetryResultHandler.HandleTestResult#8938
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
efficiency/otel-single-pass-property-walk-00e4dea485646cad

Conversation

@Evangelink

Copy link
Copy Markdown
Member

🤖 This is a draft PR created by Efficiency Improver, an automated AI assistant focused on reducing the energy consumption and computational footprint of this repository.

Goal and Rationale

Reduce redundant CPU work and heap allocations in OpenTelemetryResultHandler.HandleTestResult(), which runs on every completed test when OpenTelemetry is enabled.

Focus area: Code-Level Efficiency — eliminating unnecessary heap allocations and CPU-cycle waste from repeated linked-list traversal.

Before

HandleTestResult made 5 separatePropertyBag linked-list walks per test result:

testNode.Properties.SingleOrDefault<TimingProperty>()// walk 1
testNode.Properties.OfType<TestMetadataProperty>()// walk 2 + TProperty[] alloc
testNode.Properties.SingleOrDefault<StandardOutputProperty>()// walk 3
testNode.Properties.SingleOrDefault<StandardErrorProperty>()// walk 4
testNode.Properties.OfType<FileArtifactProperty>()// walk 5 + TProperty[] alloc

OfType<T>() always allocates a TProperty[] — even when zero properties match (it returns Array.Empty<T>(), which avoids the empty-array allocation but still performs the full traversal).

After

A single GetStructEnumerator() pass handles all five properties in one traversal:

  • 1 linked-list walk (down from 5 — a 5× reduction)
  • 0 array allocations from OfType<T>() (down from 2 per test result)

GetStructEnumerator() returns the internal struct enumerator by value (no boxing, no heap allocation). It is accessible here because OpenTelemetryResultHandler lives in the same Microsoft.Testing.Platform assembly as PropertyBag.

Energy Efficiency Evidence

Proxy metrics: Heap allocations and CPU cycles from linked-list traversal, both directly proportional to energy consumption.

MetricBeforeAfterSaving (per completed test)
PropertyBag linked-list walks51−4 walks
TProperty[] heap allocations from OfType<T>()20−2 allocations

For a 10 000-test run with OTel enabled:

  • ~40 000 fewer linked-list node traversals
  • ~20 000 fewer short-lived array heap allocations → reduced GC pressure

Proxy-based reasoning caveat: actual energy reduction depends on property bag sizes, CPU architecture, and GC behaviour. The savings are modest per test but accumulate linearly with test-suite size.

Green Software Foundation Context

Hardware Efficiency: Reducing GC pressure frees CPU cycles from collection pauses, making better use of the underlying hardware.

Energy Proportionality: The change makes the OTel-enabled code path use compute more proportional to the actual number of test results produced.

Trade-offs

  • The refactored block is slightly longer (38 LOC vs. 15 LOC) due to the switch statement.
  • Tags that were previously set in a fixed order (timing → metadata → stdout → stderr → artifacts) are now set in property-bag iteration order. OTel exporters treat tags as unordered key-value pairs, so this has no semantic impact.

Reproducibility

./build.sh -build
dotnet run --project test/UnitTests/Microsoft.Testing.Platform.UnitTests \
-f net8.0 --no-build -c Debug
# Expected: 1106 tests pass, 0 failures

Test Status

✅ All 1106 unit tests pass (Microsoft.Testing.Platform.UnitTests, net8.0, Debug, no failures).

Generated by Efficiency Improver · sonnet46 12M ·

Add this agentic workflows to your repo

To install this agentic workflow, run

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

…leTestResult
Replace five separate PropertyBag walks in HandleTestResult
(SingleOrDefault<TimingProperty>, OfType<TestMetadataProperty>,
SingleOrDefault<StandardOutputProperty>, SingleOrDefault<StandardErrorProperty>,
OfType<FileArtifactProperty>) with a single GetStructEnumerator() pass.
This eliminates two TProperty[] heap allocations from OfType<T>() and
reduces linked-list traversal from 5 to 1 per test result when OTel is
enabled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 8, 2026 22:39
@EvangelinkAmaury Levé (Evangelink) added area/performance Runtime / build performance / efficiency. type/automation Created or maintained by an agentic workflow. labels Jun 8, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 the OpenTelemetry test-result reporting path in Microsoft.Testing.Platform by switching OpenTelemetryResultHandler.HandleTestResult() from multiple PropertyBag queries to a single struct-enumerator pass, reducing repeated linked-list traversal and avoiding OfType<T>() array allocations.

Changes:

  • Refactors HandleTestResult() to collect timing, metadata, stdout/stderr, and file artifacts in one GetStructEnumerator() walk.
  • Removes OfType<T>() usage for metadata and file artifacts to avoid per-result array allocations.
  • Defers setting test.stdout / test.stderr tags until after the single pass.
Show a summary per file
FileDescription
src/Platform/Microsoft.Testing.Platform/Telemetry/OpenTelemetryResultHandler.csConsolidates property extraction into a single PropertyBag walk for lower per-test overhead when OpenTelemetry is enabled.

Copilot's findings

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

@Evangelink
Amaury Levé (Evangelink) marked this pull request as ready for review June 9, 2026 06:52
…walk
Track timing/stdout/stderr properties during the PropertyBag walk and
throw InvalidOperationException if a duplicate is encountered, matching
the prior SingleOrDefault<T>() behavior the refactor inadvertently changed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) merged commit 8d72aa4 into mainJun 9, 2026
32 of 34 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the efficiency/otel-single-pass-property-walk-00e4dea485646cad branch June 9, 2026 09:00
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/performanceRuntime / build performance / efficiency.type/automationCreated or maintained by an agentic workflow.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[efficiency-improver] perf: single-pass PropertyBag walk in OpenTelemetryResultHandler.HandleTestResult - #8938

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
efficiency/otel-single-pass-property-walk-00e4dea485646cad
Jun 9, 2026
Merged

[efficiency-improver] perf: single-pass PropertyBag walk in OpenTelemetryResultHandler.HandleTestResult#8938
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
efficiency/otel-single-pass-property-walk-00e4dea485646cad

Conversation

@Evangelink

Copy link
Copy Markdown
Member

🤖 This is a draft PR created by Efficiency Improver, an automated AI assistant focused on reducing the energy consumption and computational footprint of this repository.

Goal and Rationale

Reduce redundant CPU work and heap allocations in OpenTelemetryResultHandler.HandleTestResult(), which runs on every completed test when OpenTelemetry is enabled.

Focus area: Code-Level Efficiency — eliminating unnecessary heap allocations and CPU-cycle waste from repeated linked-list traversal.

Before

HandleTestResult made 5 separatePropertyBag linked-list walks per test result:

testNode.Properties.SingleOrDefault<TimingProperty>()// walk 1
testNode.Properties.OfType<TestMetadataProperty>()// walk 2 + TProperty[] alloc
testNode.Properties.SingleOrDefault<StandardOutputProperty>()// walk 3
testNode.Properties.SingleOrDefault<StandardErrorProperty>()// walk 4
testNode.Properties.OfType<FileArtifactProperty>()// walk 5 + TProperty[] alloc

OfType<T>() always allocates a TProperty[] — even when zero properties match (it returns Array.Empty<T>(), which avoids the empty-array allocation but still performs the full traversal).

After

A single GetStructEnumerator() pass handles all five properties in one traversal:

  • 1 linked-list walk (down from 5 — a 5× reduction)
  • 0 array allocations from OfType<T>() (down from 2 per test result)

GetStructEnumerator() returns the internal struct enumerator by value (no boxing, no heap allocation). It is accessible here because OpenTelemetryResultHandler lives in the same Microsoft.Testing.Platform assembly as PropertyBag.

Energy Efficiency Evidence

Proxy metrics: Heap allocations and CPU cycles from linked-list traversal, both directly proportional to energy consumption.

MetricBeforeAfterSaving (per completed test)
PropertyBag linked-list walks51−4 walks
TProperty[] heap allocations from OfType<T>()20−2 allocations

For a 10 000-test run with OTel enabled:

  • ~40 000 fewer linked-list node traversals
  • ~20 000 fewer short-lived array heap allocations → reduced GC pressure

Proxy-based reasoning caveat: actual energy reduction depends on property bag sizes, CPU architecture, and GC behaviour. The savings are modest per test but accumulate linearly with test-suite size.

Green Software Foundation Context

Hardware Efficiency: Reducing GC pressure frees CPU cycles from collection pauses, making better use of the underlying hardware.

Energy Proportionality: The change makes the OTel-enabled code path use compute more proportional to the actual number of test results produced.

Trade-offs

  • The refactored block is slightly longer (38 LOC vs. 15 LOC) due to the switch statement.
  • Tags that were previously set in a fixed order (timing → metadata → stdout → stderr → artifacts) are now set in property-bag iteration order. OTel exporters treat tags as unordered key-value pairs, so this has no semantic impact.

Reproducibility

./build.sh -build
dotnet run --project test/UnitTests/Microsoft.Testing.Platform.UnitTests \
-f net8.0 --no-build -c Debug
# Expected: 1106 tests pass, 0 failures

Test Status

✅ All 1106 unit tests pass (Microsoft.Testing.Platform.UnitTests, net8.0, Debug, no failures).

Generated by Efficiency Improver · sonnet46 12M ·

Add this agentic workflows to your repo

To install this agentic workflow, run

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

…leTestResult
Replace five separate PropertyBag walks in HandleTestResult
(SingleOrDefault<TimingProperty>, OfType<TestMetadataProperty>,
SingleOrDefault<StandardOutputProperty>, SingleOrDefault<StandardErrorProperty>,
OfType<FileArtifactProperty>) with a single GetStructEnumerator() pass.
This eliminates two TProperty[] heap allocations from OfType<T>() and
reduces linked-list traversal from 5 to 1 per test result when OTel is
enabled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 8, 2026 22:39
@EvangelinkAmaury Levé (Evangelink) added area/performance Runtime / build performance / efficiency. type/automation Created or maintained by an agentic workflow. labels Jun 8, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 the OpenTelemetry test-result reporting path in Microsoft.Testing.Platform by switching OpenTelemetryResultHandler.HandleTestResult() from multiple PropertyBag queries to a single struct-enumerator pass, reducing repeated linked-list traversal and avoiding OfType<T>() array allocations.

Changes:

  • Refactors HandleTestResult() to collect timing, metadata, stdout/stderr, and file artifacts in one GetStructEnumerator() walk.
  • Removes OfType<T>() usage for metadata and file artifacts to avoid per-result array allocations.
  • Defers setting test.stdout / test.stderr tags until after the single pass.
Show a summary per file
FileDescription
src/Platform/Microsoft.Testing.Platform/Telemetry/OpenTelemetryResultHandler.csConsolidates property extraction into a single PropertyBag walk for lower per-test overhead when OpenTelemetry is enabled.

Copilot's findings

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

@Evangelink
Amaury Levé (Evangelink) marked this pull request as ready for review June 9, 2026 06:52
…walk
Track timing/stdout/stderr properties during the PropertyBag walk and
throw InvalidOperationException if a duplicate is encountered, matching
the prior SingleOrDefault<T>() behavior the refactor inadvertently changed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) merged commit 8d72aa4 into mainJun 9, 2026
32 of 34 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the efficiency/otel-single-pass-property-walk-00e4dea485646cad branch June 9, 2026 09:00
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/performanceRuntime / build performance / efficiency.type/automationCreated or maintained by an agentic workflow.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[efficiency-improver] perf: single-pass PropertyBag walk in OpenTelemetryResultHandler.HandleTestResult - #8938

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
efficiency/otel-single-pass-property-walk-00e4dea485646cad
Jun 9, 2026
Merged

[efficiency-improver] perf: single-pass PropertyBag walk in OpenTelemetryResultHandler.HandleTestResult#8938
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
efficiency/otel-single-pass-property-walk-00e4dea485646cad

Conversation

@Evangelink

Copy link
Copy Markdown
Member

🤖 This is a draft PR created by Efficiency Improver, an automated AI assistant focused on reducing the energy consumption and computational footprint of this repository.

Goal and Rationale

Reduce redundant CPU work and heap allocations in OpenTelemetryResultHandler.HandleTestResult(), which runs on every completed test when OpenTelemetry is enabled.

Focus area: Code-Level Efficiency — eliminating unnecessary heap allocations and CPU-cycle waste from repeated linked-list traversal.

Before

HandleTestResult made 5 separatePropertyBag linked-list walks per test result:

testNode.Properties.SingleOrDefault<TimingProperty>()// walk 1
testNode.Properties.OfType<TestMetadataProperty>()// walk 2 + TProperty[] alloc
testNode.Properties.SingleOrDefault<StandardOutputProperty>()// walk 3
testNode.Properties.SingleOrDefault<StandardErrorProperty>()// walk 4
testNode.Properties.OfType<FileArtifactProperty>()// walk 5 + TProperty[] alloc

OfType<T>() always allocates a TProperty[] — even when zero properties match (it returns Array.Empty<T>(), which avoids the empty-array allocation but still performs the full traversal).

After

A single GetStructEnumerator() pass handles all five properties in one traversal:

  • 1 linked-list walk (down from 5 — a 5× reduction)
  • 0 array allocations from OfType<T>() (down from 2 per test result)

GetStructEnumerator() returns the internal struct enumerator by value (no boxing, no heap allocation). It is accessible here because OpenTelemetryResultHandler lives in the same Microsoft.Testing.Platform assembly as PropertyBag.

Energy Efficiency Evidence

Proxy metrics: Heap allocations and CPU cycles from linked-list traversal, both directly proportional to energy consumption.

MetricBeforeAfterSaving (per completed test)
PropertyBag linked-list walks51−4 walks
TProperty[] heap allocations from OfType<T>()20−2 allocations

For a 10 000-test run with OTel enabled:

  • ~40 000 fewer linked-list node traversals
  • ~20 000 fewer short-lived array heap allocations → reduced GC pressure

Proxy-based reasoning caveat: actual energy reduction depends on property bag sizes, CPU architecture, and GC behaviour. The savings are modest per test but accumulate linearly with test-suite size.

Green Software Foundation Context

Hardware Efficiency: Reducing GC pressure frees CPU cycles from collection pauses, making better use of the underlying hardware.

Energy Proportionality: The change makes the OTel-enabled code path use compute more proportional to the actual number of test results produced.

Trade-offs

  • The refactored block is slightly longer (38 LOC vs. 15 LOC) due to the switch statement.
  • Tags that were previously set in a fixed order (timing → metadata → stdout → stderr → artifacts) are now set in property-bag iteration order. OTel exporters treat tags as unordered key-value pairs, so this has no semantic impact.

Reproducibility

./build.sh -build
dotnet run --project test/UnitTests/Microsoft.Testing.Platform.UnitTests \
-f net8.0 --no-build -c Debug
# Expected: 1106 tests pass, 0 failures

Test Status

✅ All 1106 unit tests pass (Microsoft.Testing.Platform.UnitTests, net8.0, Debug, no failures).

Generated by Efficiency Improver · sonnet46 12M ·

Add this agentic workflows to your repo

To install this agentic workflow, run

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

…leTestResult
Replace five separate PropertyBag walks in HandleTestResult
(SingleOrDefault<TimingProperty>, OfType<TestMetadataProperty>,
SingleOrDefault<StandardOutputProperty>, SingleOrDefault<StandardErrorProperty>,
OfType<FileArtifactProperty>) with a single GetStructEnumerator() pass.
This eliminates two TProperty[] heap allocations from OfType<T>() and
reduces linked-list traversal from 5 to 1 per test result when OTel is
enabled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 8, 2026 22:39
@EvangelinkAmaury Levé (Evangelink) added area/performance Runtime / build performance / efficiency. type/automation Created or maintained by an agentic workflow. labels Jun 8, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 the OpenTelemetry test-result reporting path in Microsoft.Testing.Platform by switching OpenTelemetryResultHandler.HandleTestResult() from multiple PropertyBag queries to a single struct-enumerator pass, reducing repeated linked-list traversal and avoiding OfType<T>() array allocations.

Changes:

  • Refactors HandleTestResult() to collect timing, metadata, stdout/stderr, and file artifacts in one GetStructEnumerator() walk.
  • Removes OfType<T>() usage for metadata and file artifacts to avoid per-result array allocations.
  • Defers setting test.stdout / test.stderr tags until after the single pass.
Show a summary per file
FileDescription
src/Platform/Microsoft.Testing.Platform/Telemetry/OpenTelemetryResultHandler.csConsolidates property extraction into a single PropertyBag walk for lower per-test overhead when OpenTelemetry is enabled.

Copilot's findings

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

@Evangelink
Amaury Levé (Evangelink) marked this pull request as ready for review June 9, 2026 06:52
…walk
Track timing/stdout/stderr properties during the PropertyBag walk and
throw InvalidOperationException if a duplicate is encountered, matching
the prior SingleOrDefault<T>() behavior the refactor inadvertently changed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) merged commit 8d72aa4 into mainJun 9, 2026
32 of 34 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the efficiency/otel-single-pass-property-walk-00e4dea485646cad branch June 9, 2026 09:00
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/performanceRuntime / build performance / efficiency.type/automationCreated or maintained by an agentic workflow.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[efficiency-improver] perf: single-pass PropertyBag walk in OpenTelemetryResultHandler.HandleTestResult - #8938

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
efficiency/otel-single-pass-property-walk-00e4dea485646cad
Jun 9, 2026
Merged

[efficiency-improver] perf: single-pass PropertyBag walk in OpenTelemetryResultHandler.HandleTestResult#8938
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
efficiency/otel-single-pass-property-walk-00e4dea485646cad

Conversation

@Evangelink

Copy link
Copy Markdown
Member

🤖 This is a draft PR created by Efficiency Improver, an automated AI assistant focused on reducing the energy consumption and computational footprint of this repository.

Goal and Rationale

Reduce redundant CPU work and heap allocations in OpenTelemetryResultHandler.HandleTestResult(), which runs on every completed test when OpenTelemetry is enabled.

Focus area: Code-Level Efficiency — eliminating unnecessary heap allocations and CPU-cycle waste from repeated linked-list traversal.

Before

HandleTestResult made 5 separatePropertyBag linked-list walks per test result:

testNode.Properties.SingleOrDefault<TimingProperty>()// walk 1
testNode.Properties.OfType<TestMetadataProperty>()// walk 2 + TProperty[] alloc
testNode.Properties.SingleOrDefault<StandardOutputProperty>()// walk 3
testNode.Properties.SingleOrDefault<StandardErrorProperty>()// walk 4
testNode.Properties.OfType<FileArtifactProperty>()// walk 5 + TProperty[] alloc

OfType<T>() always allocates a TProperty[] — even when zero properties match (it returns Array.Empty<T>(), which avoids the empty-array allocation but still performs the full traversal).

After

A single GetStructEnumerator() pass handles all five properties in one traversal:

  • 1 linked-list walk (down from 5 — a 5× reduction)
  • 0 array allocations from OfType<T>() (down from 2 per test result)

GetStructEnumerator() returns the internal struct enumerator by value (no boxing, no heap allocation). It is accessible here because OpenTelemetryResultHandler lives in the same Microsoft.Testing.Platform assembly as PropertyBag.

Energy Efficiency Evidence

Proxy metrics: Heap allocations and CPU cycles from linked-list traversal, both directly proportional to energy consumption.

MetricBeforeAfterSaving (per completed test)
PropertyBag linked-list walks51−4 walks
TProperty[] heap allocations from OfType<T>()20−2 allocations

For a 10 000-test run with OTel enabled:

  • ~40 000 fewer linked-list node traversals
  • ~20 000 fewer short-lived array heap allocations → reduced GC pressure

Proxy-based reasoning caveat: actual energy reduction depends on property bag sizes, CPU architecture, and GC behaviour. The savings are modest per test but accumulate linearly with test-suite size.

Green Software Foundation Context

Hardware Efficiency: Reducing GC pressure frees CPU cycles from collection pauses, making better use of the underlying hardware.

Energy Proportionality: The change makes the OTel-enabled code path use compute more proportional to the actual number of test results produced.

Trade-offs

  • The refactored block is slightly longer (38 LOC vs. 15 LOC) due to the switch statement.
  • Tags that were previously set in a fixed order (timing → metadata → stdout → stderr → artifacts) are now set in property-bag iteration order. OTel exporters treat tags as unordered key-value pairs, so this has no semantic impact.

Reproducibility

./build.sh -build
dotnet run --project test/UnitTests/Microsoft.Testing.Platform.UnitTests \
-f net8.0 --no-build -c Debug
# Expected: 1106 tests pass, 0 failures

Test Status

✅ All 1106 unit tests pass (Microsoft.Testing.Platform.UnitTests, net8.0, Debug, no failures).

Generated by Efficiency Improver · sonnet46 12M ·

Add this agentic workflows to your repo

To install this agentic workflow, run

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

…leTestResult
Replace five separate PropertyBag walks in HandleTestResult
(SingleOrDefault<TimingProperty>, OfType<TestMetadataProperty>,
SingleOrDefault<StandardOutputProperty>, SingleOrDefault<StandardErrorProperty>,
OfType<FileArtifactProperty>) with a single GetStructEnumerator() pass.
This eliminates two TProperty[] heap allocations from OfType<T>() and
reduces linked-list traversal from 5 to 1 per test result when OTel is
enabled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 8, 2026 22:39
@EvangelinkAmaury Levé (Evangelink) added area/performance Runtime / build performance / efficiency. type/automation Created or maintained by an agentic workflow. labels Jun 8, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 the OpenTelemetry test-result reporting path in Microsoft.Testing.Platform by switching OpenTelemetryResultHandler.HandleTestResult() from multiple PropertyBag queries to a single struct-enumerator pass, reducing repeated linked-list traversal and avoiding OfType<T>() array allocations.

Changes:

  • Refactors HandleTestResult() to collect timing, metadata, stdout/stderr, and file artifacts in one GetStructEnumerator() walk.
  • Removes OfType<T>() usage for metadata and file artifacts to avoid per-result array allocations.
  • Defers setting test.stdout / test.stderr tags until after the single pass.
Show a summary per file
FileDescription
src/Platform/Microsoft.Testing.Platform/Telemetry/OpenTelemetryResultHandler.csConsolidates property extraction into a single PropertyBag walk for lower per-test overhead when OpenTelemetry is enabled.

Copilot's findings

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

@Evangelink
Amaury Levé (Evangelink) marked this pull request as ready for review June 9, 2026 06:52
…walk
Track timing/stdout/stderr properties during the PropertyBag walk and
throw InvalidOperationException if a duplicate is encountered, matching
the prior SingleOrDefault<T>() behavior the refactor inadvertently changed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) merged commit 8d72aa4 into mainJun 9, 2026
32 of 34 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the efficiency/otel-single-pass-property-walk-00e4dea485646cad branch June 9, 2026 09:00
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/performanceRuntime / build performance / efficiency.type/automationCreated or maintained by an agentic workflow.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[efficiency-improver] perf: single-pass PropertyBag walk in OpenTelemetryResultHandler.HandleTestResult - #8938

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
efficiency/otel-single-pass-property-walk-00e4dea485646cad
Jun 9, 2026
Merged

[efficiency-improver] perf: single-pass PropertyBag walk in OpenTelemetryResultHandler.HandleTestResult#8938
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
efficiency/otel-single-pass-property-walk-00e4dea485646cad

Conversation

@Evangelink

Copy link
Copy Markdown
Member

🤖 This is a draft PR created by Efficiency Improver, an automated AI assistant focused on reducing the energy consumption and computational footprint of this repository.

Goal and Rationale

Reduce redundant CPU work and heap allocations in OpenTelemetryResultHandler.HandleTestResult(), which runs on every completed test when OpenTelemetry is enabled.

Focus area: Code-Level Efficiency — eliminating unnecessary heap allocations and CPU-cycle waste from repeated linked-list traversal.

Before

HandleTestResult made 5 separatePropertyBag linked-list walks per test result:

testNode.Properties.SingleOrDefault<TimingProperty>()// walk 1
testNode.Properties.OfType<TestMetadataProperty>()// walk 2 + TProperty[] alloc
testNode.Properties.SingleOrDefault<StandardOutputProperty>()// walk 3
testNode.Properties.SingleOrDefault<StandardErrorProperty>()// walk 4
testNode.Properties.OfType<FileArtifactProperty>()// walk 5 + TProperty[] alloc

OfType<T>() always allocates a TProperty[] — even when zero properties match (it returns Array.Empty<T>(), which avoids the empty-array allocation but still performs the full traversal).

After

A single GetStructEnumerator() pass handles all five properties in one traversal:

  • 1 linked-list walk (down from 5 — a 5× reduction)
  • 0 array allocations from OfType<T>() (down from 2 per test result)

GetStructEnumerator() returns the internal struct enumerator by value (no boxing, no heap allocation). It is accessible here because OpenTelemetryResultHandler lives in the same Microsoft.Testing.Platform assembly as PropertyBag.

Energy Efficiency Evidence

Proxy metrics: Heap allocations and CPU cycles from linked-list traversal, both directly proportional to energy consumption.

MetricBeforeAfterSaving (per completed test)
PropertyBag linked-list walks51−4 walks
TProperty[] heap allocations from OfType<T>()20−2 allocations

For a 10 000-test run with OTel enabled:

  • ~40 000 fewer linked-list node traversals
  • ~20 000 fewer short-lived array heap allocations → reduced GC pressure

Proxy-based reasoning caveat: actual energy reduction depends on property bag sizes, CPU architecture, and GC behaviour. The savings are modest per test but accumulate linearly with test-suite size.

Green Software Foundation Context

Hardware Efficiency: Reducing GC pressure frees CPU cycles from collection pauses, making better use of the underlying hardware.

Energy Proportionality: The change makes the OTel-enabled code path use compute more proportional to the actual number of test results produced.

Trade-offs

  • The refactored block is slightly longer (38 LOC vs. 15 LOC) due to the switch statement.
  • Tags that were previously set in a fixed order (timing → metadata → stdout → stderr → artifacts) are now set in property-bag iteration order. OTel exporters treat tags as unordered key-value pairs, so this has no semantic impact.

Reproducibility

./build.sh -build
dotnet run --project test/UnitTests/Microsoft.Testing.Platform.UnitTests \
-f net8.0 --no-build -c Debug
# Expected: 1106 tests pass, 0 failures

Test Status

✅ All 1106 unit tests pass (Microsoft.Testing.Platform.UnitTests, net8.0, Debug, no failures).

Generated by Efficiency Improver · sonnet46 12M ·

Add this agentic workflows to your repo

To install this agentic workflow, run

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

…leTestResult
Replace five separate PropertyBag walks in HandleTestResult
(SingleOrDefault<TimingProperty>, OfType<TestMetadataProperty>,
SingleOrDefault<StandardOutputProperty>, SingleOrDefault<StandardErrorProperty>,
OfType<FileArtifactProperty>) with a single GetStructEnumerator() pass.
This eliminates two TProperty[] heap allocations from OfType<T>() and
reduces linked-list traversal from 5 to 1 per test result when OTel is
enabled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 8, 2026 22:39
@EvangelinkAmaury Levé (Evangelink) added area/performance Runtime / build performance / efficiency. type/automation Created or maintained by an agentic workflow. labels Jun 8, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 the OpenTelemetry test-result reporting path in Microsoft.Testing.Platform by switching OpenTelemetryResultHandler.HandleTestResult() from multiple PropertyBag queries to a single struct-enumerator pass, reducing repeated linked-list traversal and avoiding OfType<T>() array allocations.

Changes:

  • Refactors HandleTestResult() to collect timing, metadata, stdout/stderr, and file artifacts in one GetStructEnumerator() walk.
  • Removes OfType<T>() usage for metadata and file artifacts to avoid per-result array allocations.
  • Defers setting test.stdout / test.stderr tags until after the single pass.
Show a summary per file
FileDescription
src/Platform/Microsoft.Testing.Platform/Telemetry/OpenTelemetryResultHandler.csConsolidates property extraction into a single PropertyBag walk for lower per-test overhead when OpenTelemetry is enabled.

Copilot's findings

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

@Evangelink
Amaury Levé (Evangelink) marked this pull request as ready for review June 9, 2026 06:52
…walk
Track timing/stdout/stderr properties during the PropertyBag walk and
throw InvalidOperationException if a duplicate is encountered, matching
the prior SingleOrDefault<T>() behavior the refactor inadvertently changed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) merged commit 8d72aa4 into mainJun 9, 2026
32 of 34 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the efficiency/otel-single-pass-property-walk-00e4dea485646cad branch June 9, 2026 09:00
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/performanceRuntime / build performance / efficiency.type/automationCreated or maintained by an agentic workflow.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[efficiency-improver] perf: single-pass PropertyBag walk in OpenTelemetryResultHandler.HandleTestResult - #8938

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
efficiency/otel-single-pass-property-walk-00e4dea485646cad
Jun 9, 2026
Merged

[efficiency-improver] perf: single-pass PropertyBag walk in OpenTelemetryResultHandler.HandleTestResult#8938
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
efficiency/otel-single-pass-property-walk-00e4dea485646cad

Conversation

@Evangelink

Copy link
Copy Markdown
Member

🤖 This is a draft PR created by Efficiency Improver, an automated AI assistant focused on reducing the energy consumption and computational footprint of this repository.

Goal and Rationale

Reduce redundant CPU work and heap allocations in OpenTelemetryResultHandler.HandleTestResult(), which runs on every completed test when OpenTelemetry is enabled.

Focus area: Code-Level Efficiency — eliminating unnecessary heap allocations and CPU-cycle waste from repeated linked-list traversal.

Before

HandleTestResult made 5 separatePropertyBag linked-list walks per test result:

testNode.Properties.SingleOrDefault<TimingProperty>()// walk 1
testNode.Properties.OfType<TestMetadataProperty>()// walk 2 + TProperty[] alloc
testNode.Properties.SingleOrDefault<StandardOutputProperty>()// walk 3
testNode.Properties.SingleOrDefault<StandardErrorProperty>()// walk 4
testNode.Properties.OfType<FileArtifactProperty>()// walk 5 + TProperty[] alloc

OfType<T>() always allocates a TProperty[] — even when zero properties match (it returns Array.Empty<T>(), which avoids the empty-array allocation but still performs the full traversal).

After

A single GetStructEnumerator() pass handles all five properties in one traversal:

  • 1 linked-list walk (down from 5 — a 5× reduction)
  • 0 array allocations from OfType<T>() (down from 2 per test result)

GetStructEnumerator() returns the internal struct enumerator by value (no boxing, no heap allocation). It is accessible here because OpenTelemetryResultHandler lives in the same Microsoft.Testing.Platform assembly as PropertyBag.

Energy Efficiency Evidence

Proxy metrics: Heap allocations and CPU cycles from linked-list traversal, both directly proportional to energy consumption.

MetricBeforeAfterSaving (per completed test)
PropertyBag linked-list walks51−4 walks
TProperty[] heap allocations from OfType<T>()20−2 allocations

For a 10 000-test run with OTel enabled:

  • ~40 000 fewer linked-list node traversals
  • ~20 000 fewer short-lived array heap allocations → reduced GC pressure

Proxy-based reasoning caveat: actual energy reduction depends on property bag sizes, CPU architecture, and GC behaviour. The savings are modest per test but accumulate linearly with test-suite size.

Green Software Foundation Context

Hardware Efficiency: Reducing GC pressure frees CPU cycles from collection pauses, making better use of the underlying hardware.

Energy Proportionality: The change makes the OTel-enabled code path use compute more proportional to the actual number of test results produced.

Trade-offs

  • The refactored block is slightly longer (38 LOC vs. 15 LOC) due to the switch statement.
  • Tags that were previously set in a fixed order (timing → metadata → stdout → stderr → artifacts) are now set in property-bag iteration order. OTel exporters treat tags as unordered key-value pairs, so this has no semantic impact.

Reproducibility

./build.sh -build
dotnet run --project test/UnitTests/Microsoft.Testing.Platform.UnitTests \
-f net8.0 --no-build -c Debug
# Expected: 1106 tests pass, 0 failures

Test Status

✅ All 1106 unit tests pass (Microsoft.Testing.Platform.UnitTests, net8.0, Debug, no failures).

Generated by Efficiency Improver · sonnet46 12M ·

Add this agentic workflows to your repo

To install this agentic workflow, run

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

…leTestResult
Replace five separate PropertyBag walks in HandleTestResult
(SingleOrDefault<TimingProperty>, OfType<TestMetadataProperty>,
SingleOrDefault<StandardOutputProperty>, SingleOrDefault<StandardErrorProperty>,
OfType<FileArtifactProperty>) with a single GetStructEnumerator() pass.
This eliminates two TProperty[] heap allocations from OfType<T>() and
reduces linked-list traversal from 5 to 1 per test result when OTel is
enabled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 8, 2026 22:39
@EvangelinkAmaury Levé (Evangelink) added area/performance Runtime / build performance / efficiency. type/automation Created or maintained by an agentic workflow. labels Jun 8, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 the OpenTelemetry test-result reporting path in Microsoft.Testing.Platform by switching OpenTelemetryResultHandler.HandleTestResult() from multiple PropertyBag queries to a single struct-enumerator pass, reducing repeated linked-list traversal and avoiding OfType<T>() array allocations.

Changes:

  • Refactors HandleTestResult() to collect timing, metadata, stdout/stderr, and file artifacts in one GetStructEnumerator() walk.
  • Removes OfType<T>() usage for metadata and file artifacts to avoid per-result array allocations.
  • Defers setting test.stdout / test.stderr tags until after the single pass.
Show a summary per file
FileDescription
src/Platform/Microsoft.Testing.Platform/Telemetry/OpenTelemetryResultHandler.csConsolidates property extraction into a single PropertyBag walk for lower per-test overhead when OpenTelemetry is enabled.

Copilot's findings

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

@Evangelink
Amaury Levé (Evangelink) marked this pull request as ready for review June 9, 2026 06:52
…walk
Track timing/stdout/stderr properties during the PropertyBag walk and
throw InvalidOperationException if a duplicate is encountered, matching
the prior SingleOrDefault<T>() behavior the refactor inadvertently changed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) merged commit 8d72aa4 into mainJun 9, 2026
32 of 34 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the efficiency/otel-single-pass-property-walk-00e4dea485646cad branch June 9, 2026 09:00
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/performanceRuntime / build performance / efficiency.type/automationCreated or maintained by an agentic workflow.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[efficiency-improver] perf: single-pass PropertyBag walk in OpenTelemetryResultHandler.HandleTestResult - #8938

Merged
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
efficiency/otel-single-pass-property-walk-00e4dea485646cad
Jun 9, 2026
Merged

[efficiency-improver] perf: single-pass PropertyBag walk in OpenTelemetryResultHandler.HandleTestResult#8938
Amaury Levé (Evangelink) merged 2 commits into
mainfrom
efficiency/otel-single-pass-property-walk-00e4dea485646cad

Conversation

@Evangelink

Copy link
Copy Markdown
Member

🤖 This is a draft PR created by Efficiency Improver, an automated AI assistant focused on reducing the energy consumption and computational footprint of this repository.

Goal and Rationale

Reduce redundant CPU work and heap allocations in OpenTelemetryResultHandler.HandleTestResult(), which runs on every completed test when OpenTelemetry is enabled.

Focus area: Code-Level Efficiency — eliminating unnecessary heap allocations and CPU-cycle waste from repeated linked-list traversal.

Before

HandleTestResult made 5 separatePropertyBag linked-list walks per test result:

testNode.Properties.SingleOrDefault<TimingProperty>()// walk 1
testNode.Properties.OfType<TestMetadataProperty>()// walk 2 + TProperty[] alloc
testNode.Properties.SingleOrDefault<StandardOutputProperty>()// walk 3
testNode.Properties.SingleOrDefault<StandardErrorProperty>()// walk 4
testNode.Properties.OfType<FileArtifactProperty>()// walk 5 + TProperty[] alloc

OfType<T>() always allocates a TProperty[] — even when zero properties match (it returns Array.Empty<T>(), which avoids the empty-array allocation but still performs the full traversal).

After

A single GetStructEnumerator() pass handles all five properties in one traversal:

  • 1 linked-list walk (down from 5 — a 5× reduction)
  • 0 array allocations from OfType<T>() (down from 2 per test result)

GetStructEnumerator() returns the internal struct enumerator by value (no boxing, no heap allocation). It is accessible here because OpenTelemetryResultHandler lives in the same Microsoft.Testing.Platform assembly as PropertyBag.

Energy Efficiency Evidence

Proxy metrics: Heap allocations and CPU cycles from linked-list traversal, both directly proportional to energy consumption.

MetricBeforeAfterSaving (per completed test)
PropertyBag linked-list walks51−4 walks
TProperty[] heap allocations from OfType<T>()20−2 allocations

For a 10 000-test run with OTel enabled:

  • ~40 000 fewer linked-list node traversals
  • ~20 000 fewer short-lived array heap allocations → reduced GC pressure

Proxy-based reasoning caveat: actual energy reduction depends on property bag sizes, CPU architecture, and GC behaviour. The savings are modest per test but accumulate linearly with test-suite size.

Green Software Foundation Context

Hardware Efficiency: Reducing GC pressure frees CPU cycles from collection pauses, making better use of the underlying hardware.

Energy Proportionality: The change makes the OTel-enabled code path use compute more proportional to the actual number of test results produced.

Trade-offs

  • The refactored block is slightly longer (38 LOC vs. 15 LOC) due to the switch statement.
  • Tags that were previously set in a fixed order (timing → metadata → stdout → stderr → artifacts) are now set in property-bag iteration order. OTel exporters treat tags as unordered key-value pairs, so this has no semantic impact.

Reproducibility

./build.sh -build
dotnet run --project test/UnitTests/Microsoft.Testing.Platform.UnitTests \
-f net8.0 --no-build -c Debug
# Expected: 1106 tests pass, 0 failures

Test Status

✅ All 1106 unit tests pass (Microsoft.Testing.Platform.UnitTests, net8.0, Debug, no failures).

Generated by Efficiency Improver · sonnet46 12M ·

Add this agentic workflows to your repo

To install this agentic workflow, run

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

…leTestResult
Replace five separate PropertyBag walks in HandleTestResult
(SingleOrDefault<TimingProperty>, OfType<TestMetadataProperty>,
SingleOrDefault<StandardOutputProperty>, SingleOrDefault<StandardErrorProperty>,
OfType<FileArtifactProperty>) with a single GetStructEnumerator() pass.
This eliminates two TProperty[] heap allocations from OfType<T>() and
reduces linked-list traversal from 5 to 1 per test result when OTel is
enabled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 8, 2026 22:39
@EvangelinkAmaury Levé (Evangelink) added area/performance Runtime / build performance / efficiency. type/automation Created or maintained by an agentic workflow. labels Jun 8, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 the OpenTelemetry test-result reporting path in Microsoft.Testing.Platform by switching OpenTelemetryResultHandler.HandleTestResult() from multiple PropertyBag queries to a single struct-enumerator pass, reducing repeated linked-list traversal and avoiding OfType<T>() array allocations.

Changes:

  • Refactors HandleTestResult() to collect timing, metadata, stdout/stderr, and file artifacts in one GetStructEnumerator() walk.
  • Removes OfType<T>() usage for metadata and file artifacts to avoid per-result array allocations.
  • Defers setting test.stdout / test.stderr tags until after the single pass.
Show a summary per file
FileDescription
src/Platform/Microsoft.Testing.Platform/Telemetry/OpenTelemetryResultHandler.csConsolidates property extraction into a single PropertyBag walk for lower per-test overhead when OpenTelemetry is enabled.

Copilot's findings

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

@Evangelink
Amaury Levé (Evangelink) marked this pull request as ready for review June 9, 2026 06:52
…walk
Track timing/stdout/stderr properties during the PropertyBag walk and
throw InvalidOperationException if a duplicate is encountered, matching
the prior SingleOrDefault<T>() behavior the refactor inadvertently changed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Amaury Levé (Evangelink) merged commit 8d72aa4 into mainJun 9, 2026
32 of 34 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the efficiency/otel-single-pass-property-walk-00e4dea485646cad branch June 9, 2026 09:00
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/performanceRuntime / build performance / efficiency.type/automationCreated or maintained by an agentic workflow.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Evangelink