') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); Make browser StopwatchTests robust to coarse clock resolution by Copilot · Pull Request #130605 · dotnet/runtime · GitHub
Skip to content

Make browser StopwatchTests robust to coarse clock resolution - #130605

Merged
pavelsavara merged 2 commits into
mainfrom
copilot/fix-stopwatch-tests-issue
Jul 13, 2026
Merged

Make browser StopwatchTests robust to coarse clock resolution#130605
pavelsavara merged 2 commits into
mainfrom
copilot/fix-stopwatch-tests-issue

Conversation

CopilotAI commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Fixes#62021

StopwatchTests.GetTimestamp and StartNewAndReset fail intermittently on the browser/WASM target: consecutive GetTimestamp() reads return equal values and Elapsed measures zero.

Root cause

On browser, Stopwatch.GetTimestamp()minipal_hires_ticks() → emscripten clock_gettime(CLOCK_MONOTONIC), backed by performance.now(), which is security-clamped to a coarse resolution. Blocking waits (ManualResetEvent.WaitOne(timeout)) also don't advance real time on the single browser thread. A fixed-timeout sleep therefore isn't guaranteed to move the timestamp past a resolution boundary. The monotonic hi-res clock in use is already the best clock the browser exposes — there is no higher-resolution alternative to switch to — so the test must tolerate coarse resolution rather than assume a fixed sleep crosses a boundary.

Changes

  • Stopwatch.cs test Sleep helper: on browser only, spin (re-issuing the existing WaitOne) until the Stopwatch timestamp advances by at least one TimeSpan tick. Non-browser platforms are unchanged.
privatestaticvoidSleep(intmilliseconds){if(PlatformDetection.IsBrowser){longstart=Stopwatch.GetTimestamp();longminTicks=Math.Max(1,Stopwatch.Frequency/TimeSpan.TicksPerSecond);do{s_sleepEvent.WaitOne(milliseconds);}while(Stopwatch.GetTimestamp()-start<minTicks);return;}s_sleepEvent.WaitOne(milliseconds);}

This guarantees a measurable delta before dependent asserts (Assert.NotEqual(ts1, ts2), Elapsed > TimeSpan.Zero), covering GetTimestamp, StartNewAndReset, ConstructStartAndStop, and OverridesToString. No tests are disabled.

Note

This PR was generated with the assistance of GitHub Copilot.

Co-authored-by: pavelsavara <271576+pavelsavara@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotJuly 13, 2026 08:59
CopilotAI changed the title [WIP] Fix System.Diagnostics.Tests.StopwatchTests.GetTimestamp test in CIMake browser StopwatchTests robust to coarse clock resolutionJul 13, 2026
CopilotAI requested a review from pavelsavaraJuly 13, 2026 09:00
@pavelsavara
pavelsavara marked this pull request as ready for review July 13, 2026 09:55
CopilotAI review requested due to automatic review settings July 13, 2026 09:55

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 adjusts System.Diagnostics.Tests.StopwatchTests to reduce intermittent failures on browser/WASM by making the test’s sleep helper wait until Stopwatch.GetTimestamp() observably advances, rather than assuming a single fixed wait crosses the clock’s resolution boundary.

Changes:

  • Add a browser-specific loop in the Sleep(int milliseconds) helper to retry waiting until the stopwatch timestamp advances.

@pavelsavara

Copy link
Copy Markdown
Member

/ba-g CI failure is #130618

CopilotAItemporarily deployed to copilot-pat-pool July 13, 2026 15:06 Inactive
CopilotAItemporarily deployed to copilot-pat-pool July 13, 2026 15:06 Inactive
@pavelsavara
pavelsavara merged commit 8a53018 into mainJul 13, 2026
96 of 100 checks passed
@pavelsavara
pavelsavara deleted the copilot/fix-stopwatch-tests-issue branch July 13, 2026 15:15
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 14, 2026
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 13, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Runtimeos-browserBrowser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

System.Diagnostics.Tests.StopwatchTests.GetTimestamp test fails in the CI

6 participants

@pavelsavara@akoeplinger@jkotas@tarekgh