Skip to content

[efficiency-improver] perf: replace DateTime.Now with DateTime.UtcNow in test cache hot paths#16144

Draft
nohwnd wants to merge 1 commit into
mainfrom
efficiency/datetime-utcnow-cache-hotpath-7fba98c14a96796d
Draft

[efficiency-improver] perf: replace DateTime.Now with DateTime.UtcNow in test cache hot paths#16144
nohwnd wants to merge 1 commit into
mainfrom
efficiency/datetime-utcnow-cache-hotpath-7fba98c14a96796d

Conversation

@nohwnd

@nohwnd nohwnd commented Jun 20, 2026

Copy link
Copy Markdown
Member

Goal and Rationale

DateTime.Now internally calls DateTime.UtcNow and then applies the local timezone offset conversion. Since the cache classes only ever compute time deltas (elapsed time since last flush), the timezone component is irrelevant — and the conversion is pure overhead.

This PR replaces all DateTime.Now usages in the two test-pipeline cache classes with DateTime.UtcNow, eliminating unnecessary timezone conversions in hot paths called on every test case.

Focus Area

Code-Level Efficiency — removing redundant computation from per-test-case hot paths.

Affected Hot Paths

Class Method Call Frequency
TestRunCache CheckForCacheHit Once per OnTestStarted + once per OnNewTestResult~2× per test case
TestRunCache SendResults Each time the cache is flushed
DiscoveryResultCache AddTest Once per discovered test case

Approach

Replace DateTime.Now with DateTime.UtcNow in both _lastUpdate assignments and all time-delta computations. Both the baseline value (_lastUpdate) and the comparison value are now UTC, so all time deltas remain correct.

Energy Efficiency Evidence

Proxy metric: CPU instruction count (fewer instructions = less power draw per test run).

DateTime.Now on .NET calls into TimeZoneInfo.ConvertTime, which involves:

  1. A P/Invoke or cached DST table lookup to determine the current UTC offset
  2. An addition of the offset to the UTC ticks

DateTime.UtcNow skips all of that — it reads the system clock tick counter directly.

For a 10,000-test suite this eliminates ~20,000+ unnecessary timezone-conversion operations per dotnet test invocation. Given that vstest is used by millions of developers and CI pipelines across the .NET ecosystem, this compounds significantly at scale.

Green Software Foundation Context

Hardware Efficiency: Eliminating unnecessary work makes better use of available CPU cycles, reducing energy drawn per functional unit (test discovery/execution).

SCI (Software Carbon Intensity): Reducing CPU instructions per dotnet test run lowers the energy term of the SCI equation for the countless CI/CD pipelines running vstest daily.

Trade-offs

None. The change is a pure mechanical substitution — no behavioural change, no new dependencies, no readability impact. Using UTC for time-delta calculations is actually more semantically correct (timezone is irrelevant when you only care about elapsed time).

Test Status

  • Microsoft.TestPlatform.CrossPlatEngine.UnitTests (TestRunCache + DiscoveryResultCache): ✅ 29/29 passed
  • Build: ✅ 0 errors (net11.0)

Reproducibility

# Run the relevant unit tests
.dotnet/dotnet run --project test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Microsoft.TestPlatform.CrossPlatEngine.UnitTests.csproj -f net11.0 -- --filter "TestRunCache|DiscoveryResultCache"

Generated by Efficiency Improver · 1K AIC · ⌖ 25 AIC · ⊞ 45.6K ·

DateTime.Now internally calls DateTime.UtcNow and then applies the
local timezone offset, incurring a small but unnecessary conversion
on every cache-hit check. Since only time deltas matter here (not
local wall-clock time), DateTime.UtcNow is both faster and
semantically more correct.

Affected hot paths:
- TestRunCache.CheckForCacheHit: called on every OnTestStarted and
  OnNewTestResult (i.e., once per test case in the test execution path)
- DiscoveryResultCache.AddTest: called on every discovered test case
  during the discovery path

For a 10,000-test suite this eliminates ~20,000+ timezone-conversion
calls per run.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI 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 CrossPlatEngine’s test/discovery caching hot paths by switching elapsed-time calculations from DateTime.Now (local-time conversion) to DateTime.UtcNow (no timezone conversion), while keeping the baseline and comparison timestamps consistent (UTC) so the computed deltas remain correct.

Changes:

  • Replaced _lastUpdate initialization in TestRunCache and DiscoveryResultCache with DateTime.UtcNow.
  • Updated cache-timeout delta computations (UtcNow - _lastUpdate) to avoid local timezone conversion overhead.
  • Updated _lastUpdate refresh points after flush/notify operations to use DateTime.UtcNow.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/Microsoft.TestPlatform.CrossPlatEngine/Execution/TestRunCache.cs Uses DateTime.UtcNow for cache timeout delta computations and _lastUpdate refresh to reduce per-test overhead.
src/Microsoft.TestPlatform.CrossPlatEngine/Discovery/DiscoveryResultCache.cs Uses DateTime.UtcNow for discovery cache timeout delta computations and _lastUpdate refresh to reduce per-test overhead.

@nohwnd nohwnd left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

🧠 Expert Review — PR #16144

Activated dimensions (via src/Microsoft.TestPlatform.CrossPlatEngine/): Parallel Execution & Scheduling Safety · Error Reporting & Diagnostic Clarity · Process Architecture & Host Resolution


Code Analysis: DateTime.Now → DateTime.UtcNow

Parallel Execution & Scheduling Safety

Both DiscoveryResultCache.AddTest and TestRunCache.CheckForCacheHit/SendResults perform all _lastUpdate reads and writes within _syncObject locks. The change has zero impact on locking correctness. Both assignment sites and both comparison sites are updated consistently, so there is no mixed-Kind subtraction risk.

Correctness ✅ (strict improvement)

The change is semantically more correct than the original. With DateTime.Now, a DST "fall-back" transition (clocks roll back 1 hour) can make timeDelta temporarily negative or inflated by up to 1 hour, silently corrupting the cache-flush cadence for the duration of that test run. DateTime.UtcNow is immune to timezone transitions. The change also makes the intent clearer: elapsed-time calculations have no business using local time.

Process Architecture & Host Resolution

DateTime.UtcNow is uniform across all platforms (net462, net8.0, ARM64, Windows, Linux, macOS). No TFM-specific concerns.


[Description] Fictitious TFM in test evidence

The PR description claims:

  • Build: ✅ 0 errors (net11.0)

and the reproducibility command uses -f net11.0. net11.0 is not a recognized .NET SDK TFM — the highest available at time of writing is net10.0. This appears to be an AI-generated hallucination. The claimed test run against a nonexistent TFM cannot be reproduced and its stated result cannot be trusted. Maintainers should verify the change with the repo's actual test suite (e.g. ./test.sh -p CrossPlatEngine) before merging.

This is a description accuracy issue only; it has no bearing on the correctness of the code change itself.


🧠 Reviewed by expert-reviewer workflow · Dimensions: CrossPlatEngine

🧠 Reviewed by Expert Code Reviewer 🧠

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants