Skip to content

[browser][coreCLR] event pipe and browser profiler - #126324

Merged
pavelsavara merged 6 commits into
dotnet:mainfrom
pavelsavara:browser_EP_coreclr
Jun 12, 2026
Merged

[browser][coreCLR] event pipe and browser profiler#126324
pavelsavara merged 6 commits into
dotnet:mainfrom
pavelsavara:browser_EP_coreclr

Conversation

@pavelsavara

@pavelsavarapavelsavara commented Mar 30, 2026

Copy link
Copy Markdown
Member

Summary

This change builds on top of EventPipe-for-CoreCLR (#128745) and adds two WASM profiling experiences for the CoreCLR interpreter on single-threaded browser/WASI builds:

  1. EventPipe CPU sampling profiler — a cooperative, single-threaded sampling profiler that produces .nettrace CPU samples consumable by dotnet-trace / the JS collectCpuSamples API.
  2. Browser DevTools profiler — emits performance.measure() calls so managed method execution shows up as a nested flame chart in the browser Performance tab.

Both are opt-in via the DOTNET_WasmPerformanceInstrumentation MethodSet filter and are wired up through the existing WasmPerformanceInstrumentation MSBuild property (CoreCLR-compatible syntax).

Motivation

On the multi-threaded runtime the EventPipe sample profiler runs on a dedicated thread that suspends the target. On single-threaded WASM there is no such thread, so the previous ep_rt_sample_profiler_* hooks were no-ops and CPU sampling was unavailable for CoreCLR. This adds a cooperative sampling mechanism driven by the interpreter, matching the capability Mono already provides on the browser.

How it works

New interpreter opcodes

Three opcodes are added in intops.def:

  • INTOP_PROF_SAMPLEPOINT — emitted at method entry and at backward branches (loop back-edges, alongside the existing INTOP_SAFEPOINT). Drives the EventPipe sampling profiler.
  • INTOP_PROF_ENTER / INTOP_PROF_LEAVE — emitted at method entry/return (and tail-call / exception unwind paths). Drive the browser DevTools profiler.

The interpreter compiler only emits these when the method matches the WasmPerformanceInstrumentation MethodSet filter, and only on PERFTRACING_DISABLE_THREADS (single-threaded) builds. INTOP_PROF_ENTER/INTOP_PROF_LEAVE are additionally gated on TARGET_BROWSER.

EventPipe CPU sampling (single-threaded)

ep-rt-coreclr-wasm-sampling.cpp implements the ep_rt_coreclr_sample_profiler_* callbacks (now wired from ep-rt-coreclr.h instead of being no-ops). SamplingProfiler_OnSamplepoint() is invoked from the interpreter at samplepoints and:

  • Uses a fast skip-counter path to avoid overhead on every samplepoint.
  • Adaptively recomputes the skip count using an exponential-moving-average against the desired sampling interval (the same approach as Mono's ep-rt-mono-runtime-provider.c).
  • Walks the managed stack and writes a managed sample profile event when due.

On multi-threaded builds the callbacks remain no-ops (the threaded profiler is used).

Browser DevTools profiler

browserprofiler.cpp maintains a shadow stack of method enter/leave timings and calls ds_rt_browser_performance_measure() (→ performance.measure()) so methods appear as nested entries in the browser Performance/flame chart. Recording is rate-limited with an adaptive skip counter; the shadow stack always tracks enter/leave for correctness, and a parent frame is marked for recording when a child is recorded so the chart nests properly. Leave only pops when the top frame matches, guarding against mismatched enter/leave for filtered-out methods.

Configuration / MSBuild

  • New RELEASE_CONFIG_METHODSET(WasmPerformanceInstrumentation) in interpconfigvalues.h. jitStartup enables the profilers when the filter is non-empty, before any managed code is compiled.
  • BrowserWasmApp.CoreCLR.targets and Microsoft.NET.Sdk.WebAssembly.Browser.targets translate the Mono-style WasmPerformanceInstrumentation property (e.g. all,interval=0) into CoreCLR env vars (DOTNET_WasmPerformanceInstrumentation, sampling-rate var), with all mapped to the MethodSet wildcard *. Native build is forced on when the property is set.

Tests

  • Wasm.Build.Tests.Blazor.EventPipeDiagnosticsTests is added to BuildWasmAppsJobsListCoreCLR.txt so it runs for CoreCLR.
  • EventPipeDiagnosticsTests.cs: removed the class-level mono category so it runs on CoreCLR; split the AOT (Mono-only) case into its own native-mono[Fact] while the Debug/Release non-AOT cases run for both runtimes.
  • browser-eventpipe sample updated to demonstrate collectCpuSamples / collectGcDump / collectMetrics from the DevTools console.
imageimageimageimage

@pavelsavarapavelsavara added this to the 11.0.0 milestone Mar 30, 2026
@pavelsavarapavelsavara self-assigned this Mar 30, 2026
CopilotAI review requested due to automatic review settings March 30, 2026 16:51
@pavelsavarapavelsavara added arch-wasm WebAssembly architecture area-System.Diagnostics os-browser Browser variant of arch-wasm labels Mar 30, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @dotnet/area-system-diagnostics
See info in area-owners.md if you want to be subscribed.

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

Enables EventPipe/diagnostic-server plumbing for CoreCLR in browser by turning on FEATURE_PERFTRACING while keeping FEATURE_EVENT_TRACE disabled, and adds the browser-side scheduling + WebSocket/JS transport needed to drive the diagnostic server loop.

Changes:

  • Enable FEATURE_PERFTRACING for browser CoreCLR and gate ETW/EventTrace-specific code behind FEATURE_EVENT_TRACE (including EventPipe codegen changes).
  • Add browser-native diagnostic server job queue + scheduler callback wiring (SystemJS_*DiagnosticServer*).
  • Add JS diagnostics client/transport (WebSocket + in-browser “js://” scenarios) and expose ds_rt_websocket_* + dotnetApi.collect* helpers.

Reviewed changes

Copilot reviewed 42 out of 43 changed files in this pull request and generated 14 comments.

Show a summary per file
FileDescription
src/native/libs/System.Native.Browser/utils/scheduling.tsRuns the diagnostic server callback alongside other background callbacks; abort clears pending diagnostic server timer id.
src/native/libs/System.Native.Browser/native/scheduling.tsAdds SystemJS_ScheduleDiagnosticServer scheduling hook using safeSetTimeout.
src/native/libs/System.Native.Browser/native/index.tsExposes diagnostic server scheduler + callback through the native exports table; exports ds websocket shims.
src/native/libs/System.Native.Browser/native/diagnostics.tsAdds native-side re-exports for ds_rt_websocket_* via diagnostics cross-module exports.
src/native/libs/System.Native.Browser/diagnostics/types.tsIntroduces diagnostics protocol/session/provider types and enums used by the JS diagnostics client.
src/native/libs/System.Native.Browser/diagnostics/index.tsWires diagnostics exports table and installs JS diagnostics client + dotnetApi helpers.
src/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.tsAdds JS helper to collect gcdump trace via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/dotnet-cpu-profiler.tsAdds JS helper to collect CPU samples via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/dotnet-counters.tsAdds JS helper to collect metrics via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/diagnostics.tsImplements browser-side ds_rt_websocket_* transport and DS router reconnection support.
src/native/libs/System.Native.Browser/diagnostics/diagnostics-ws.tsImplements WebSocket-based diagnostic connection wrapper.
src/native/libs/System.Native.Browser/diagnostics/diagnostics-js.tsImplements in-browser “JS diagnostic client” session handling and scenario-based commands.
src/native/libs/System.Native.Browser/diagnostics/common.tsShared base queue/recv logic and trace download helper.
src/native/libs/System.Native.Browser/diagnostics/client-commands.tsImplements serialization for diagnostic IPC commands (advertise, EventPipe commands, etc.).
src/native/libs/System.Native.Browser/ds.hAdds placeholder header for diagnostic server C support.
src/native/libs/System.Native.Browser/ds.cAdds native diagnostic server job queue + callback executor for browser builds.
src/native/libs/System.Native.Browser/CMakeLists.txtLinks ds.c into System.Native.Browser-Static.
src/native/libs/Common/JavaScript/types/public-api.tsUpdates diagnostics public types (providerName).
src/native/libs/Common/JavaScript/types/exchange.tsExtends exchange tables/types for new native browser + diagnostics exports.
src/native/libs/Common/JavaScript/types/ems-ambient.tsAdds ambient symbol + timer id tracking for diagnostic server callback scheduling.
src/native/libs/Common/JavaScript/loader/dotnet.d.tsUpdates generated public type surface (providerName).
src/native/libs/Common/JavaScript/cross-module/index.tsUpdates cross-module table mapping for new native browser + diagnostics exports.
src/native/eventpipe/ds-ipc-pal-websocket.hAdds C linkage guards for websocket PAL APIs.
src/mono/mono/utils/mono-threads.hRenames/aligns DS job queue API name to SystemJS_DiagnosticServerQueueJob.
src/mono/mono/utils/mono-threads-wasm.hRenames DS exec callback export to SystemJS_ExecuteDiagnosticServerCallback.
src/mono/mono/utils/mono-threads-wasm.cRenames DS queue/exec functions for browser single-threaded mode.
src/mono/mono/mini/mini-wasm.cUpdates exported symbol name for DS exec callback.
src/mono/mono/eventpipe/ep-rt-mono.hUpdates DS job rescheduling callsite to new queue function name.
src/mono/browser/runtime/types/internal.tsUpdates runtime helper name for DS exec callback.
src/mono/browser/runtime/exports.tsExposes renamed DS exec callback in runtime exports.
src/mono/browser/runtime/diagnostics/common.tsCalls renamed DS exec callback from mono browser diagnostics event loop.
src/mono/browser/runtime/cwraps.tsUpdates cwrap signature to match renamed DS exec callback export.
src/coreclr/vm/qcallentrypoints.cppGates NativeRuntimeEventSource QCalls behind FEATURE_EVENT_TRACE while keeping EventPipe QCalls under FEATURE_PERFTRACING.
src/coreclr/vm/nativeeventsource.cppAdds non-ETW stubs when FEATURE_PERFTRACING is enabled but FEATURE_EVENT_TRACE is disabled.
src/coreclr/vm/gcenv.ee.cppWraps ETW-only GC analysis events with FEATURE_EVENT_TRACE guards.
src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.hAdds browser single-threaded job queue integration via SystemJS_DiagnosticServerQueueJob; gates ETW-only provider init behind FEATURE_EVENT_TRACE.
src/coreclr/vm/eventing/eventpipe/CMakeLists.txtAdds --noetwcallbacks option for EventPipe codegen when FEATURE_EVENT_TRACE is off.
src/coreclr/vm/eventing/CMakeLists.txtMakes dependency on eventprovider conditional.
src/coreclr/scripts/genEventPipe.pyAdds --noetwcallbacks support to omit ETW callback wiring in generated provider code.
src/coreclr/nativeaot/Runtime/disabledruntimeeventinternal.cppFixes a typo in a comment.
src/coreclr/clrfeatures.cmakeEnables FEATURE_PERFTRACING for browser targets; adjusts feature enablement logic.
src/coreclr/clrdefinitions.cmakeEnsures FEATURE_PERFTRACING defines and avoids creating dummy targets when perftracing is enabled.
src/coreclr/clr.featuredefines.propsEnables perf tracing for browser build configuration.

Comment threadsrc/native/libs/System.Native.Browser/diagnostics/common.ts
Comment threadsrc/native/libs/System.Native.Browser/diagnostics/diagnostics-ws.ts Outdated
Comment threadsrc/native/libs/Common/JavaScript/types/exchange.ts Outdated
Comment threadsrc/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.ts Outdated
Comment threadsrc/native/libs/Common/JavaScript/types/public-api.ts
Comment threadsrc/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h Outdated
CopilotAI review requested due to automatic review settings March 30, 2026 17:05
@pavelsavarapavelsavara changed the title [browser][coreCLR] event pipe[browser][coreCLR] event pipe and browser profilerApr 22, 2026
Comment threadsrc/coreclr/vm/wasm/browserprofiler.cpp Outdated
@pavelsavara

pavelsavara commented Jun 9, 2026

Copy link
Copy Markdown
MemberAuthor

@jkotas@BrzVlad please review

Edit: Let me know if you have further feedback, I'm happy to process it in next PR

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

/ba-g CI failures are unrelated

@pavelsavara
pavelsavara merged commit f867627 into dotnet:mainJun 12, 2026
175 of 183 checks passed
@pavelsavara
pavelsavara deleted the browser_EP_coreclr branch June 12, 2026 20:32
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 18, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-wasmWebAssembly architecturearea-System.Diagnosticsos-browserBrowser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@pavelsavara@akoeplinger@BrzVlad@jkotas@maraf@radekdoulik
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
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;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
[browser][coreCLR] event pipe and browser profiler by pavelsavara · Pull Request #126324 · dotnet/runtime · GitHub
Skip to content

[browser][coreCLR] event pipe and browser profiler - #126324

Merged
pavelsavara merged 6 commits into
dotnet:mainfrom
pavelsavara:browser_EP_coreclr
Jun 12, 2026
Merged

[browser][coreCLR] event pipe and browser profiler#126324
pavelsavara merged 6 commits into
dotnet:mainfrom
pavelsavara:browser_EP_coreclr

Conversation

@pavelsavara

@pavelsavarapavelsavara commented Mar 30, 2026

Copy link
Copy Markdown
Member

Summary

This change builds on top of EventPipe-for-CoreCLR (#128745) and adds two WASM profiling experiences for the CoreCLR interpreter on single-threaded browser/WASI builds:

  1. EventPipe CPU sampling profiler — a cooperative, single-threaded sampling profiler that produces .nettrace CPU samples consumable by dotnet-trace / the JS collectCpuSamples API.
  2. Browser DevTools profiler — emits performance.measure() calls so managed method execution shows up as a nested flame chart in the browser Performance tab.

Both are opt-in via the DOTNET_WasmPerformanceInstrumentation MethodSet filter and are wired up through the existing WasmPerformanceInstrumentation MSBuild property (CoreCLR-compatible syntax).

Motivation

On the multi-threaded runtime the EventPipe sample profiler runs on a dedicated thread that suspends the target. On single-threaded WASM there is no such thread, so the previous ep_rt_sample_profiler_* hooks were no-ops and CPU sampling was unavailable for CoreCLR. This adds a cooperative sampling mechanism driven by the interpreter, matching the capability Mono already provides on the browser.

How it works

New interpreter opcodes

Three opcodes are added in intops.def:

  • INTOP_PROF_SAMPLEPOINT — emitted at method entry and at backward branches (loop back-edges, alongside the existing INTOP_SAFEPOINT). Drives the EventPipe sampling profiler.
  • INTOP_PROF_ENTER / INTOP_PROF_LEAVE — emitted at method entry/return (and tail-call / exception unwind paths). Drive the browser DevTools profiler.

The interpreter compiler only emits these when the method matches the WasmPerformanceInstrumentation MethodSet filter, and only on PERFTRACING_DISABLE_THREADS (single-threaded) builds. INTOP_PROF_ENTER/INTOP_PROF_LEAVE are additionally gated on TARGET_BROWSER.

EventPipe CPU sampling (single-threaded)

ep-rt-coreclr-wasm-sampling.cpp implements the ep_rt_coreclr_sample_profiler_* callbacks (now wired from ep-rt-coreclr.h instead of being no-ops). SamplingProfiler_OnSamplepoint() is invoked from the interpreter at samplepoints and:

  • Uses a fast skip-counter path to avoid overhead on every samplepoint.
  • Adaptively recomputes the skip count using an exponential-moving-average against the desired sampling interval (the same approach as Mono's ep-rt-mono-runtime-provider.c).
  • Walks the managed stack and writes a managed sample profile event when due.

On multi-threaded builds the callbacks remain no-ops (the threaded profiler is used).

Browser DevTools profiler

browserprofiler.cpp maintains a shadow stack of method enter/leave timings and calls ds_rt_browser_performance_measure() (→ performance.measure()) so methods appear as nested entries in the browser Performance/flame chart. Recording is rate-limited with an adaptive skip counter; the shadow stack always tracks enter/leave for correctness, and a parent frame is marked for recording when a child is recorded so the chart nests properly. Leave only pops when the top frame matches, guarding against mismatched enter/leave for filtered-out methods.

Configuration / MSBuild

  • New RELEASE_CONFIG_METHODSET(WasmPerformanceInstrumentation) in interpconfigvalues.h. jitStartup enables the profilers when the filter is non-empty, before any managed code is compiled.
  • BrowserWasmApp.CoreCLR.targets and Microsoft.NET.Sdk.WebAssembly.Browser.targets translate the Mono-style WasmPerformanceInstrumentation property (e.g. all,interval=0) into CoreCLR env vars (DOTNET_WasmPerformanceInstrumentation, sampling-rate var), with all mapped to the MethodSet wildcard *. Native build is forced on when the property is set.

Tests

  • Wasm.Build.Tests.Blazor.EventPipeDiagnosticsTests is added to BuildWasmAppsJobsListCoreCLR.txt so it runs for CoreCLR.
  • EventPipeDiagnosticsTests.cs: removed the class-level mono category so it runs on CoreCLR; split the AOT (Mono-only) case into its own native-mono[Fact] while the Debug/Release non-AOT cases run for both runtimes.
  • browser-eventpipe sample updated to demonstrate collectCpuSamples / collectGcDump / collectMetrics from the DevTools console.
imageimageimageimage

@pavelsavarapavelsavara added this to the 11.0.0 milestone Mar 30, 2026
@pavelsavarapavelsavara self-assigned this Mar 30, 2026
CopilotAI review requested due to automatic review settings March 30, 2026 16:51
@pavelsavarapavelsavara added arch-wasm WebAssembly architecture area-System.Diagnostics os-browser Browser variant of arch-wasm labels Mar 30, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @dotnet/area-system-diagnostics
See info in area-owners.md if you want to be subscribed.

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

Enables EventPipe/diagnostic-server plumbing for CoreCLR in browser by turning on FEATURE_PERFTRACING while keeping FEATURE_EVENT_TRACE disabled, and adds the browser-side scheduling + WebSocket/JS transport needed to drive the diagnostic server loop.

Changes:

  • Enable FEATURE_PERFTRACING for browser CoreCLR and gate ETW/EventTrace-specific code behind FEATURE_EVENT_TRACE (including EventPipe codegen changes).
  • Add browser-native diagnostic server job queue + scheduler callback wiring (SystemJS_*DiagnosticServer*).
  • Add JS diagnostics client/transport (WebSocket + in-browser “js://” scenarios) and expose ds_rt_websocket_* + dotnetApi.collect* helpers.

Reviewed changes

Copilot reviewed 42 out of 43 changed files in this pull request and generated 14 comments.

Show a summary per file
FileDescription
src/native/libs/System.Native.Browser/utils/scheduling.tsRuns the diagnostic server callback alongside other background callbacks; abort clears pending diagnostic server timer id.
src/native/libs/System.Native.Browser/native/scheduling.tsAdds SystemJS_ScheduleDiagnosticServer scheduling hook using safeSetTimeout.
src/native/libs/System.Native.Browser/native/index.tsExposes diagnostic server scheduler + callback through the native exports table; exports ds websocket shims.
src/native/libs/System.Native.Browser/native/diagnostics.tsAdds native-side re-exports for ds_rt_websocket_* via diagnostics cross-module exports.
src/native/libs/System.Native.Browser/diagnostics/types.tsIntroduces diagnostics protocol/session/provider types and enums used by the JS diagnostics client.
src/native/libs/System.Native.Browser/diagnostics/index.tsWires diagnostics exports table and installs JS diagnostics client + dotnetApi helpers.
src/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.tsAdds JS helper to collect gcdump trace via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/dotnet-cpu-profiler.tsAdds JS helper to collect CPU samples via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/dotnet-counters.tsAdds JS helper to collect metrics via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/diagnostics.tsImplements browser-side ds_rt_websocket_* transport and DS router reconnection support.
src/native/libs/System.Native.Browser/diagnostics/diagnostics-ws.tsImplements WebSocket-based diagnostic connection wrapper.
src/native/libs/System.Native.Browser/diagnostics/diagnostics-js.tsImplements in-browser “JS diagnostic client” session handling and scenario-based commands.
src/native/libs/System.Native.Browser/diagnostics/common.tsShared base queue/recv logic and trace download helper.
src/native/libs/System.Native.Browser/diagnostics/client-commands.tsImplements serialization for diagnostic IPC commands (advertise, EventPipe commands, etc.).
src/native/libs/System.Native.Browser/ds.hAdds placeholder header for diagnostic server C support.
src/native/libs/System.Native.Browser/ds.cAdds native diagnostic server job queue + callback executor for browser builds.
src/native/libs/System.Native.Browser/CMakeLists.txtLinks ds.c into System.Native.Browser-Static.
src/native/libs/Common/JavaScript/types/public-api.tsUpdates diagnostics public types (providerName).
src/native/libs/Common/JavaScript/types/exchange.tsExtends exchange tables/types for new native browser + diagnostics exports.
src/native/libs/Common/JavaScript/types/ems-ambient.tsAdds ambient symbol + timer id tracking for diagnostic server callback scheduling.
src/native/libs/Common/JavaScript/loader/dotnet.d.tsUpdates generated public type surface (providerName).
src/native/libs/Common/JavaScript/cross-module/index.tsUpdates cross-module table mapping for new native browser + diagnostics exports.
src/native/eventpipe/ds-ipc-pal-websocket.hAdds C linkage guards for websocket PAL APIs.
src/mono/mono/utils/mono-threads.hRenames/aligns DS job queue API name to SystemJS_DiagnosticServerQueueJob.
src/mono/mono/utils/mono-threads-wasm.hRenames DS exec callback export to SystemJS_ExecuteDiagnosticServerCallback.
src/mono/mono/utils/mono-threads-wasm.cRenames DS queue/exec functions for browser single-threaded mode.
src/mono/mono/mini/mini-wasm.cUpdates exported symbol name for DS exec callback.
src/mono/mono/eventpipe/ep-rt-mono.hUpdates DS job rescheduling callsite to new queue function name.
src/mono/browser/runtime/types/internal.tsUpdates runtime helper name for DS exec callback.
src/mono/browser/runtime/exports.tsExposes renamed DS exec callback in runtime exports.
src/mono/browser/runtime/diagnostics/common.tsCalls renamed DS exec callback from mono browser diagnostics event loop.
src/mono/browser/runtime/cwraps.tsUpdates cwrap signature to match renamed DS exec callback export.
src/coreclr/vm/qcallentrypoints.cppGates NativeRuntimeEventSource QCalls behind FEATURE_EVENT_TRACE while keeping EventPipe QCalls under FEATURE_PERFTRACING.
src/coreclr/vm/nativeeventsource.cppAdds non-ETW stubs when FEATURE_PERFTRACING is enabled but FEATURE_EVENT_TRACE is disabled.
src/coreclr/vm/gcenv.ee.cppWraps ETW-only GC analysis events with FEATURE_EVENT_TRACE guards.
src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.hAdds browser single-threaded job queue integration via SystemJS_DiagnosticServerQueueJob; gates ETW-only provider init behind FEATURE_EVENT_TRACE.
src/coreclr/vm/eventing/eventpipe/CMakeLists.txtAdds --noetwcallbacks option for EventPipe codegen when FEATURE_EVENT_TRACE is off.
src/coreclr/vm/eventing/CMakeLists.txtMakes dependency on eventprovider conditional.
src/coreclr/scripts/genEventPipe.pyAdds --noetwcallbacks support to omit ETW callback wiring in generated provider code.
src/coreclr/nativeaot/Runtime/disabledruntimeeventinternal.cppFixes a typo in a comment.
src/coreclr/clrfeatures.cmakeEnables FEATURE_PERFTRACING for browser targets; adjusts feature enablement logic.
src/coreclr/clrdefinitions.cmakeEnsures FEATURE_PERFTRACING defines and avoids creating dummy targets when perftracing is enabled.
src/coreclr/clr.featuredefines.propsEnables perf tracing for browser build configuration.

Comment threadsrc/native/libs/System.Native.Browser/diagnostics/common.ts
Comment threadsrc/native/libs/System.Native.Browser/diagnostics/diagnostics-ws.ts Outdated
Comment threadsrc/native/libs/Common/JavaScript/types/exchange.ts Outdated
Comment threadsrc/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.ts Outdated
Comment threadsrc/native/libs/Common/JavaScript/types/public-api.ts
Comment threadsrc/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h Outdated
CopilotAI review requested due to automatic review settings March 30, 2026 17:05
@pavelsavarapavelsavara changed the title [browser][coreCLR] event pipe[browser][coreCLR] event pipe and browser profilerApr 22, 2026
Comment threadsrc/coreclr/vm/wasm/browserprofiler.cpp Outdated
@pavelsavara

pavelsavara commented Jun 9, 2026

Copy link
Copy Markdown
MemberAuthor

@jkotas@BrzVlad please review

Edit: Let me know if you have further feedback, I'm happy to process it in next PR

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

/ba-g CI failures are unrelated

@pavelsavara
pavelsavara merged commit f867627 into dotnet:mainJun 12, 2026
175 of 183 checks passed
@pavelsavara
pavelsavara deleted the browser_EP_coreclr branch June 12, 2026 20:32
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 18, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-wasmWebAssembly architecturearea-System.Diagnosticsos-browserBrowser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@pavelsavara@akoeplinger@BrzVlad@jkotas@maraf@radekdoulik
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [browser][coreCLR] event pipe and browser profiler by pavelsavara · Pull Request #126324 · dotnet/runtime · GitHub
Skip to content

[browser][coreCLR] event pipe and browser profiler - #126324

Merged
pavelsavara merged 6 commits into
dotnet:mainfrom
pavelsavara:browser_EP_coreclr
Jun 12, 2026
Merged

[browser][coreCLR] event pipe and browser profiler#126324
pavelsavara merged 6 commits into
dotnet:mainfrom
pavelsavara:browser_EP_coreclr

Conversation

@pavelsavara

@pavelsavarapavelsavara commented Mar 30, 2026

Copy link
Copy Markdown
Member

Summary

This change builds on top of EventPipe-for-CoreCLR (#128745) and adds two WASM profiling experiences for the CoreCLR interpreter on single-threaded browser/WASI builds:

  1. EventPipe CPU sampling profiler — a cooperative, single-threaded sampling profiler that produces .nettrace CPU samples consumable by dotnet-trace / the JS collectCpuSamples API.
  2. Browser DevTools profiler — emits performance.measure() calls so managed method execution shows up as a nested flame chart in the browser Performance tab.

Both are opt-in via the DOTNET_WasmPerformanceInstrumentation MethodSet filter and are wired up through the existing WasmPerformanceInstrumentation MSBuild property (CoreCLR-compatible syntax).

Motivation

On the multi-threaded runtime the EventPipe sample profiler runs on a dedicated thread that suspends the target. On single-threaded WASM there is no such thread, so the previous ep_rt_sample_profiler_* hooks were no-ops and CPU sampling was unavailable for CoreCLR. This adds a cooperative sampling mechanism driven by the interpreter, matching the capability Mono already provides on the browser.

How it works

New interpreter opcodes

Three opcodes are added in intops.def:

  • INTOP_PROF_SAMPLEPOINT — emitted at method entry and at backward branches (loop back-edges, alongside the existing INTOP_SAFEPOINT). Drives the EventPipe sampling profiler.
  • INTOP_PROF_ENTER / INTOP_PROF_LEAVE — emitted at method entry/return (and tail-call / exception unwind paths). Drive the browser DevTools profiler.

The interpreter compiler only emits these when the method matches the WasmPerformanceInstrumentation MethodSet filter, and only on PERFTRACING_DISABLE_THREADS (single-threaded) builds. INTOP_PROF_ENTER/INTOP_PROF_LEAVE are additionally gated on TARGET_BROWSER.

EventPipe CPU sampling (single-threaded)

ep-rt-coreclr-wasm-sampling.cpp implements the ep_rt_coreclr_sample_profiler_* callbacks (now wired from ep-rt-coreclr.h instead of being no-ops). SamplingProfiler_OnSamplepoint() is invoked from the interpreter at samplepoints and:

  • Uses a fast skip-counter path to avoid overhead on every samplepoint.
  • Adaptively recomputes the skip count using an exponential-moving-average against the desired sampling interval (the same approach as Mono's ep-rt-mono-runtime-provider.c).
  • Walks the managed stack and writes a managed sample profile event when due.

On multi-threaded builds the callbacks remain no-ops (the threaded profiler is used).

Browser DevTools profiler

browserprofiler.cpp maintains a shadow stack of method enter/leave timings and calls ds_rt_browser_performance_measure() (→ performance.measure()) so methods appear as nested entries in the browser Performance/flame chart. Recording is rate-limited with an adaptive skip counter; the shadow stack always tracks enter/leave for correctness, and a parent frame is marked for recording when a child is recorded so the chart nests properly. Leave only pops when the top frame matches, guarding against mismatched enter/leave for filtered-out methods.

Configuration / MSBuild

  • New RELEASE_CONFIG_METHODSET(WasmPerformanceInstrumentation) in interpconfigvalues.h. jitStartup enables the profilers when the filter is non-empty, before any managed code is compiled.
  • BrowserWasmApp.CoreCLR.targets and Microsoft.NET.Sdk.WebAssembly.Browser.targets translate the Mono-style WasmPerformanceInstrumentation property (e.g. all,interval=0) into CoreCLR env vars (DOTNET_WasmPerformanceInstrumentation, sampling-rate var), with all mapped to the MethodSet wildcard *. Native build is forced on when the property is set.

Tests

  • Wasm.Build.Tests.Blazor.EventPipeDiagnosticsTests is added to BuildWasmAppsJobsListCoreCLR.txt so it runs for CoreCLR.
  • EventPipeDiagnosticsTests.cs: removed the class-level mono category so it runs on CoreCLR; split the AOT (Mono-only) case into its own native-mono[Fact] while the Debug/Release non-AOT cases run for both runtimes.
  • browser-eventpipe sample updated to demonstrate collectCpuSamples / collectGcDump / collectMetrics from the DevTools console.
imageimageimageimage

@pavelsavarapavelsavara added this to the 11.0.0 milestone Mar 30, 2026
@pavelsavarapavelsavara self-assigned this Mar 30, 2026
CopilotAI review requested due to automatic review settings March 30, 2026 16:51
@pavelsavarapavelsavara added arch-wasm WebAssembly architecture area-System.Diagnostics os-browser Browser variant of arch-wasm labels Mar 30, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @dotnet/area-system-diagnostics
See info in area-owners.md if you want to be subscribed.

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

Enables EventPipe/diagnostic-server plumbing for CoreCLR in browser by turning on FEATURE_PERFTRACING while keeping FEATURE_EVENT_TRACE disabled, and adds the browser-side scheduling + WebSocket/JS transport needed to drive the diagnostic server loop.

Changes:

  • Enable FEATURE_PERFTRACING for browser CoreCLR and gate ETW/EventTrace-specific code behind FEATURE_EVENT_TRACE (including EventPipe codegen changes).
  • Add browser-native diagnostic server job queue + scheduler callback wiring (SystemJS_*DiagnosticServer*).
  • Add JS diagnostics client/transport (WebSocket + in-browser “js://” scenarios) and expose ds_rt_websocket_* + dotnetApi.collect* helpers.

Reviewed changes

Copilot reviewed 42 out of 43 changed files in this pull request and generated 14 comments.

Show a summary per file
FileDescription
src/native/libs/System.Native.Browser/utils/scheduling.tsRuns the diagnostic server callback alongside other background callbacks; abort clears pending diagnostic server timer id.
src/native/libs/System.Native.Browser/native/scheduling.tsAdds SystemJS_ScheduleDiagnosticServer scheduling hook using safeSetTimeout.
src/native/libs/System.Native.Browser/native/index.tsExposes diagnostic server scheduler + callback through the native exports table; exports ds websocket shims.
src/native/libs/System.Native.Browser/native/diagnostics.tsAdds native-side re-exports for ds_rt_websocket_* via diagnostics cross-module exports.
src/native/libs/System.Native.Browser/diagnostics/types.tsIntroduces diagnostics protocol/session/provider types and enums used by the JS diagnostics client.
src/native/libs/System.Native.Browser/diagnostics/index.tsWires diagnostics exports table and installs JS diagnostics client + dotnetApi helpers.
src/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.tsAdds JS helper to collect gcdump trace via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/dotnet-cpu-profiler.tsAdds JS helper to collect CPU samples via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/dotnet-counters.tsAdds JS helper to collect metrics via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/diagnostics.tsImplements browser-side ds_rt_websocket_* transport and DS router reconnection support.
src/native/libs/System.Native.Browser/diagnostics/diagnostics-ws.tsImplements WebSocket-based diagnostic connection wrapper.
src/native/libs/System.Native.Browser/diagnostics/diagnostics-js.tsImplements in-browser “JS diagnostic client” session handling and scenario-based commands.
src/native/libs/System.Native.Browser/diagnostics/common.tsShared base queue/recv logic and trace download helper.
src/native/libs/System.Native.Browser/diagnostics/client-commands.tsImplements serialization for diagnostic IPC commands (advertise, EventPipe commands, etc.).
src/native/libs/System.Native.Browser/ds.hAdds placeholder header for diagnostic server C support.
src/native/libs/System.Native.Browser/ds.cAdds native diagnostic server job queue + callback executor for browser builds.
src/native/libs/System.Native.Browser/CMakeLists.txtLinks ds.c into System.Native.Browser-Static.
src/native/libs/Common/JavaScript/types/public-api.tsUpdates diagnostics public types (providerName).
src/native/libs/Common/JavaScript/types/exchange.tsExtends exchange tables/types for new native browser + diagnostics exports.
src/native/libs/Common/JavaScript/types/ems-ambient.tsAdds ambient symbol + timer id tracking for diagnostic server callback scheduling.
src/native/libs/Common/JavaScript/loader/dotnet.d.tsUpdates generated public type surface (providerName).
src/native/libs/Common/JavaScript/cross-module/index.tsUpdates cross-module table mapping for new native browser + diagnostics exports.
src/native/eventpipe/ds-ipc-pal-websocket.hAdds C linkage guards for websocket PAL APIs.
src/mono/mono/utils/mono-threads.hRenames/aligns DS job queue API name to SystemJS_DiagnosticServerQueueJob.
src/mono/mono/utils/mono-threads-wasm.hRenames DS exec callback export to SystemJS_ExecuteDiagnosticServerCallback.
src/mono/mono/utils/mono-threads-wasm.cRenames DS queue/exec functions for browser single-threaded mode.
src/mono/mono/mini/mini-wasm.cUpdates exported symbol name for DS exec callback.
src/mono/mono/eventpipe/ep-rt-mono.hUpdates DS job rescheduling callsite to new queue function name.
src/mono/browser/runtime/types/internal.tsUpdates runtime helper name for DS exec callback.
src/mono/browser/runtime/exports.tsExposes renamed DS exec callback in runtime exports.
src/mono/browser/runtime/diagnostics/common.tsCalls renamed DS exec callback from mono browser diagnostics event loop.
src/mono/browser/runtime/cwraps.tsUpdates cwrap signature to match renamed DS exec callback export.
src/coreclr/vm/qcallentrypoints.cppGates NativeRuntimeEventSource QCalls behind FEATURE_EVENT_TRACE while keeping EventPipe QCalls under FEATURE_PERFTRACING.
src/coreclr/vm/nativeeventsource.cppAdds non-ETW stubs when FEATURE_PERFTRACING is enabled but FEATURE_EVENT_TRACE is disabled.
src/coreclr/vm/gcenv.ee.cppWraps ETW-only GC analysis events with FEATURE_EVENT_TRACE guards.
src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.hAdds browser single-threaded job queue integration via SystemJS_DiagnosticServerQueueJob; gates ETW-only provider init behind FEATURE_EVENT_TRACE.
src/coreclr/vm/eventing/eventpipe/CMakeLists.txtAdds --noetwcallbacks option for EventPipe codegen when FEATURE_EVENT_TRACE is off.
src/coreclr/vm/eventing/CMakeLists.txtMakes dependency on eventprovider conditional.
src/coreclr/scripts/genEventPipe.pyAdds --noetwcallbacks support to omit ETW callback wiring in generated provider code.
src/coreclr/nativeaot/Runtime/disabledruntimeeventinternal.cppFixes a typo in a comment.
src/coreclr/clrfeatures.cmakeEnables FEATURE_PERFTRACING for browser targets; adjusts feature enablement logic.
src/coreclr/clrdefinitions.cmakeEnsures FEATURE_PERFTRACING defines and avoids creating dummy targets when perftracing is enabled.
src/coreclr/clr.featuredefines.propsEnables perf tracing for browser build configuration.

Comment threadsrc/native/libs/System.Native.Browser/diagnostics/common.ts
Comment threadsrc/native/libs/System.Native.Browser/diagnostics/diagnostics-ws.ts Outdated
Comment threadsrc/native/libs/Common/JavaScript/types/exchange.ts Outdated
Comment threadsrc/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.ts Outdated
Comment threadsrc/native/libs/Common/JavaScript/types/public-api.ts
Comment threadsrc/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h Outdated
CopilotAI review requested due to automatic review settings March 30, 2026 17:05
@pavelsavarapavelsavara changed the title [browser][coreCLR] event pipe[browser][coreCLR] event pipe and browser profilerApr 22, 2026
Comment threadsrc/coreclr/vm/wasm/browserprofiler.cpp Outdated
@pavelsavara

pavelsavara commented Jun 9, 2026

Copy link
Copy Markdown
MemberAuthor

@jkotas@BrzVlad please review

Edit: Let me know if you have further feedback, I'm happy to process it in next PR

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

/ba-g CI failures are unrelated

@pavelsavara
pavelsavara merged commit f867627 into dotnet:mainJun 12, 2026
175 of 183 checks passed
@pavelsavara
pavelsavara deleted the browser_EP_coreclr branch June 12, 2026 20:32
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 18, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-wasmWebAssembly architecturearea-System.Diagnosticsos-browserBrowser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@pavelsavara@akoeplinger@BrzVlad@jkotas@maraf@radekdoulik
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', '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('^' + ".*" + ' [browser][coreCLR] event pipe and browser profiler by pavelsavara · Pull Request #126324 · dotnet/runtime · GitHub
Skip to content

[browser][coreCLR] event pipe and browser profiler - #126324

Merged
pavelsavara merged 6 commits into
dotnet:mainfrom
pavelsavara:browser_EP_coreclr
Jun 12, 2026
Merged

[browser][coreCLR] event pipe and browser profiler#126324
pavelsavara merged 6 commits into
dotnet:mainfrom
pavelsavara:browser_EP_coreclr

Conversation

@pavelsavara

@pavelsavarapavelsavara commented Mar 30, 2026

Copy link
Copy Markdown
Member

Summary

This change builds on top of EventPipe-for-CoreCLR (#128745) and adds two WASM profiling experiences for the CoreCLR interpreter on single-threaded browser/WASI builds:

  1. EventPipe CPU sampling profiler — a cooperative, single-threaded sampling profiler that produces .nettrace CPU samples consumable by dotnet-trace / the JS collectCpuSamples API.
  2. Browser DevTools profiler — emits performance.measure() calls so managed method execution shows up as a nested flame chart in the browser Performance tab.

Both are opt-in via the DOTNET_WasmPerformanceInstrumentation MethodSet filter and are wired up through the existing WasmPerformanceInstrumentation MSBuild property (CoreCLR-compatible syntax).

Motivation

On the multi-threaded runtime the EventPipe sample profiler runs on a dedicated thread that suspends the target. On single-threaded WASM there is no such thread, so the previous ep_rt_sample_profiler_* hooks were no-ops and CPU sampling was unavailable for CoreCLR. This adds a cooperative sampling mechanism driven by the interpreter, matching the capability Mono already provides on the browser.

How it works

New interpreter opcodes

Three opcodes are added in intops.def:

  • INTOP_PROF_SAMPLEPOINT — emitted at method entry and at backward branches (loop back-edges, alongside the existing INTOP_SAFEPOINT). Drives the EventPipe sampling profiler.
  • INTOP_PROF_ENTER / INTOP_PROF_LEAVE — emitted at method entry/return (and tail-call / exception unwind paths). Drive the browser DevTools profiler.

The interpreter compiler only emits these when the method matches the WasmPerformanceInstrumentation MethodSet filter, and only on PERFTRACING_DISABLE_THREADS (single-threaded) builds. INTOP_PROF_ENTER/INTOP_PROF_LEAVE are additionally gated on TARGET_BROWSER.

EventPipe CPU sampling (single-threaded)

ep-rt-coreclr-wasm-sampling.cpp implements the ep_rt_coreclr_sample_profiler_* callbacks (now wired from ep-rt-coreclr.h instead of being no-ops). SamplingProfiler_OnSamplepoint() is invoked from the interpreter at samplepoints and:

  • Uses a fast skip-counter path to avoid overhead on every samplepoint.
  • Adaptively recomputes the skip count using an exponential-moving-average against the desired sampling interval (the same approach as Mono's ep-rt-mono-runtime-provider.c).
  • Walks the managed stack and writes a managed sample profile event when due.

On multi-threaded builds the callbacks remain no-ops (the threaded profiler is used).

Browser DevTools profiler

browserprofiler.cpp maintains a shadow stack of method enter/leave timings and calls ds_rt_browser_performance_measure() (→ performance.measure()) so methods appear as nested entries in the browser Performance/flame chart. Recording is rate-limited with an adaptive skip counter; the shadow stack always tracks enter/leave for correctness, and a parent frame is marked for recording when a child is recorded so the chart nests properly. Leave only pops when the top frame matches, guarding against mismatched enter/leave for filtered-out methods.

Configuration / MSBuild

  • New RELEASE_CONFIG_METHODSET(WasmPerformanceInstrumentation) in interpconfigvalues.h. jitStartup enables the profilers when the filter is non-empty, before any managed code is compiled.
  • BrowserWasmApp.CoreCLR.targets and Microsoft.NET.Sdk.WebAssembly.Browser.targets translate the Mono-style WasmPerformanceInstrumentation property (e.g. all,interval=0) into CoreCLR env vars (DOTNET_WasmPerformanceInstrumentation, sampling-rate var), with all mapped to the MethodSet wildcard *. Native build is forced on when the property is set.

Tests

  • Wasm.Build.Tests.Blazor.EventPipeDiagnosticsTests is added to BuildWasmAppsJobsListCoreCLR.txt so it runs for CoreCLR.
  • EventPipeDiagnosticsTests.cs: removed the class-level mono category so it runs on CoreCLR; split the AOT (Mono-only) case into its own native-mono[Fact] while the Debug/Release non-AOT cases run for both runtimes.
  • browser-eventpipe sample updated to demonstrate collectCpuSamples / collectGcDump / collectMetrics from the DevTools console.
imageimageimageimage

@pavelsavarapavelsavara added this to the 11.0.0 milestone Mar 30, 2026
@pavelsavarapavelsavara self-assigned this Mar 30, 2026
CopilotAI review requested due to automatic review settings March 30, 2026 16:51
@pavelsavarapavelsavara added arch-wasm WebAssembly architecture area-System.Diagnostics os-browser Browser variant of arch-wasm labels Mar 30, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @dotnet/area-system-diagnostics
See info in area-owners.md if you want to be subscribed.

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

Enables EventPipe/diagnostic-server plumbing for CoreCLR in browser by turning on FEATURE_PERFTRACING while keeping FEATURE_EVENT_TRACE disabled, and adds the browser-side scheduling + WebSocket/JS transport needed to drive the diagnostic server loop.

Changes:

  • Enable FEATURE_PERFTRACING for browser CoreCLR and gate ETW/EventTrace-specific code behind FEATURE_EVENT_TRACE (including EventPipe codegen changes).
  • Add browser-native diagnostic server job queue + scheduler callback wiring (SystemJS_*DiagnosticServer*).
  • Add JS diagnostics client/transport (WebSocket + in-browser “js://” scenarios) and expose ds_rt_websocket_* + dotnetApi.collect* helpers.

Reviewed changes

Copilot reviewed 42 out of 43 changed files in this pull request and generated 14 comments.

Show a summary per file
FileDescription
src/native/libs/System.Native.Browser/utils/scheduling.tsRuns the diagnostic server callback alongside other background callbacks; abort clears pending diagnostic server timer id.
src/native/libs/System.Native.Browser/native/scheduling.tsAdds SystemJS_ScheduleDiagnosticServer scheduling hook using safeSetTimeout.
src/native/libs/System.Native.Browser/native/index.tsExposes diagnostic server scheduler + callback through the native exports table; exports ds websocket shims.
src/native/libs/System.Native.Browser/native/diagnostics.tsAdds native-side re-exports for ds_rt_websocket_* via diagnostics cross-module exports.
src/native/libs/System.Native.Browser/diagnostics/types.tsIntroduces diagnostics protocol/session/provider types and enums used by the JS diagnostics client.
src/native/libs/System.Native.Browser/diagnostics/index.tsWires diagnostics exports table and installs JS diagnostics client + dotnetApi helpers.
src/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.tsAdds JS helper to collect gcdump trace via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/dotnet-cpu-profiler.tsAdds JS helper to collect CPU samples via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/dotnet-counters.tsAdds JS helper to collect metrics via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/diagnostics.tsImplements browser-side ds_rt_websocket_* transport and DS router reconnection support.
src/native/libs/System.Native.Browser/diagnostics/diagnostics-ws.tsImplements WebSocket-based diagnostic connection wrapper.
src/native/libs/System.Native.Browser/diagnostics/diagnostics-js.tsImplements in-browser “JS diagnostic client” session handling and scenario-based commands.
src/native/libs/System.Native.Browser/diagnostics/common.tsShared base queue/recv logic and trace download helper.
src/native/libs/System.Native.Browser/diagnostics/client-commands.tsImplements serialization for diagnostic IPC commands (advertise, EventPipe commands, etc.).
src/native/libs/System.Native.Browser/ds.hAdds placeholder header for diagnostic server C support.
src/native/libs/System.Native.Browser/ds.cAdds native diagnostic server job queue + callback executor for browser builds.
src/native/libs/System.Native.Browser/CMakeLists.txtLinks ds.c into System.Native.Browser-Static.
src/native/libs/Common/JavaScript/types/public-api.tsUpdates diagnostics public types (providerName).
src/native/libs/Common/JavaScript/types/exchange.tsExtends exchange tables/types for new native browser + diagnostics exports.
src/native/libs/Common/JavaScript/types/ems-ambient.tsAdds ambient symbol + timer id tracking for diagnostic server callback scheduling.
src/native/libs/Common/JavaScript/loader/dotnet.d.tsUpdates generated public type surface (providerName).
src/native/libs/Common/JavaScript/cross-module/index.tsUpdates cross-module table mapping for new native browser + diagnostics exports.
src/native/eventpipe/ds-ipc-pal-websocket.hAdds C linkage guards for websocket PAL APIs.
src/mono/mono/utils/mono-threads.hRenames/aligns DS job queue API name to SystemJS_DiagnosticServerQueueJob.
src/mono/mono/utils/mono-threads-wasm.hRenames DS exec callback export to SystemJS_ExecuteDiagnosticServerCallback.
src/mono/mono/utils/mono-threads-wasm.cRenames DS queue/exec functions for browser single-threaded mode.
src/mono/mono/mini/mini-wasm.cUpdates exported symbol name for DS exec callback.
src/mono/mono/eventpipe/ep-rt-mono.hUpdates DS job rescheduling callsite to new queue function name.
src/mono/browser/runtime/types/internal.tsUpdates runtime helper name for DS exec callback.
src/mono/browser/runtime/exports.tsExposes renamed DS exec callback in runtime exports.
src/mono/browser/runtime/diagnostics/common.tsCalls renamed DS exec callback from mono browser diagnostics event loop.
src/mono/browser/runtime/cwraps.tsUpdates cwrap signature to match renamed DS exec callback export.
src/coreclr/vm/qcallentrypoints.cppGates NativeRuntimeEventSource QCalls behind FEATURE_EVENT_TRACE while keeping EventPipe QCalls under FEATURE_PERFTRACING.
src/coreclr/vm/nativeeventsource.cppAdds non-ETW stubs when FEATURE_PERFTRACING is enabled but FEATURE_EVENT_TRACE is disabled.
src/coreclr/vm/gcenv.ee.cppWraps ETW-only GC analysis events with FEATURE_EVENT_TRACE guards.
src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.hAdds browser single-threaded job queue integration via SystemJS_DiagnosticServerQueueJob; gates ETW-only provider init behind FEATURE_EVENT_TRACE.
src/coreclr/vm/eventing/eventpipe/CMakeLists.txtAdds --noetwcallbacks option for EventPipe codegen when FEATURE_EVENT_TRACE is off.
src/coreclr/vm/eventing/CMakeLists.txtMakes dependency on eventprovider conditional.
src/coreclr/scripts/genEventPipe.pyAdds --noetwcallbacks support to omit ETW callback wiring in generated provider code.
src/coreclr/nativeaot/Runtime/disabledruntimeeventinternal.cppFixes a typo in a comment.
src/coreclr/clrfeatures.cmakeEnables FEATURE_PERFTRACING for browser targets; adjusts feature enablement logic.
src/coreclr/clrdefinitions.cmakeEnsures FEATURE_PERFTRACING defines and avoids creating dummy targets when perftracing is enabled.
src/coreclr/clr.featuredefines.propsEnables perf tracing for browser build configuration.

Comment threadsrc/native/libs/System.Native.Browser/diagnostics/common.ts
Comment threadsrc/native/libs/System.Native.Browser/diagnostics/diagnostics-ws.ts Outdated
Comment threadsrc/native/libs/Common/JavaScript/types/exchange.ts Outdated
Comment threadsrc/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.ts Outdated
Comment threadsrc/native/libs/Common/JavaScript/types/public-api.ts
Comment threadsrc/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h Outdated
CopilotAI review requested due to automatic review settings March 30, 2026 17:05
@pavelsavarapavelsavara changed the title [browser][coreCLR] event pipe[browser][coreCLR] event pipe and browser profilerApr 22, 2026
Comment threadsrc/coreclr/vm/wasm/browserprofiler.cpp Outdated
@pavelsavara

pavelsavara commented Jun 9, 2026

Copy link
Copy Markdown
MemberAuthor

@jkotas@BrzVlad please review

Edit: Let me know if you have further feedback, I'm happy to process it in next PR

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

/ba-g CI failures are unrelated

@pavelsavara
pavelsavara merged commit f867627 into dotnet:mainJun 12, 2026
175 of 183 checks passed
@pavelsavara
pavelsavara deleted the browser_EP_coreclr branch June 12, 2026 20:32
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 18, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-wasmWebAssembly architecturearea-System.Diagnosticsos-browserBrowser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@pavelsavara@akoeplinger@BrzVlad@jkotas@maraf@radekdoulik
, '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" + ' [browser][coreCLR] event pipe and browser profiler by pavelsavara · Pull Request #126324 · dotnet/runtime · GitHub
Skip to content

[browser][coreCLR] event pipe and browser profiler - #126324

Merged
pavelsavara merged 6 commits into
dotnet:mainfrom
pavelsavara:browser_EP_coreclr
Jun 12, 2026
Merged

[browser][coreCLR] event pipe and browser profiler#126324
pavelsavara merged 6 commits into
dotnet:mainfrom
pavelsavara:browser_EP_coreclr

Conversation

@pavelsavara

@pavelsavarapavelsavara commented Mar 30, 2026

Copy link
Copy Markdown
Member

Summary

This change builds on top of EventPipe-for-CoreCLR (#128745) and adds two WASM profiling experiences for the CoreCLR interpreter on single-threaded browser/WASI builds:

  1. EventPipe CPU sampling profiler — a cooperative, single-threaded sampling profiler that produces .nettrace CPU samples consumable by dotnet-trace / the JS collectCpuSamples API.
  2. Browser DevTools profiler — emits performance.measure() calls so managed method execution shows up as a nested flame chart in the browser Performance tab.

Both are opt-in via the DOTNET_WasmPerformanceInstrumentation MethodSet filter and are wired up through the existing WasmPerformanceInstrumentation MSBuild property (CoreCLR-compatible syntax).

Motivation

On the multi-threaded runtime the EventPipe sample profiler runs on a dedicated thread that suspends the target. On single-threaded WASM there is no such thread, so the previous ep_rt_sample_profiler_* hooks were no-ops and CPU sampling was unavailable for CoreCLR. This adds a cooperative sampling mechanism driven by the interpreter, matching the capability Mono already provides on the browser.

How it works

New interpreter opcodes

Three opcodes are added in intops.def:

  • INTOP_PROF_SAMPLEPOINT — emitted at method entry and at backward branches (loop back-edges, alongside the existing INTOP_SAFEPOINT). Drives the EventPipe sampling profiler.
  • INTOP_PROF_ENTER / INTOP_PROF_LEAVE — emitted at method entry/return (and tail-call / exception unwind paths). Drive the browser DevTools profiler.

The interpreter compiler only emits these when the method matches the WasmPerformanceInstrumentation MethodSet filter, and only on PERFTRACING_DISABLE_THREADS (single-threaded) builds. INTOP_PROF_ENTER/INTOP_PROF_LEAVE are additionally gated on TARGET_BROWSER.

EventPipe CPU sampling (single-threaded)

ep-rt-coreclr-wasm-sampling.cpp implements the ep_rt_coreclr_sample_profiler_* callbacks (now wired from ep-rt-coreclr.h instead of being no-ops). SamplingProfiler_OnSamplepoint() is invoked from the interpreter at samplepoints and:

  • Uses a fast skip-counter path to avoid overhead on every samplepoint.
  • Adaptively recomputes the skip count using an exponential-moving-average against the desired sampling interval (the same approach as Mono's ep-rt-mono-runtime-provider.c).
  • Walks the managed stack and writes a managed sample profile event when due.

On multi-threaded builds the callbacks remain no-ops (the threaded profiler is used).

Browser DevTools profiler

browserprofiler.cpp maintains a shadow stack of method enter/leave timings and calls ds_rt_browser_performance_measure() (→ performance.measure()) so methods appear as nested entries in the browser Performance/flame chart. Recording is rate-limited with an adaptive skip counter; the shadow stack always tracks enter/leave for correctness, and a parent frame is marked for recording when a child is recorded so the chart nests properly. Leave only pops when the top frame matches, guarding against mismatched enter/leave for filtered-out methods.

Configuration / MSBuild

  • New RELEASE_CONFIG_METHODSET(WasmPerformanceInstrumentation) in interpconfigvalues.h. jitStartup enables the profilers when the filter is non-empty, before any managed code is compiled.
  • BrowserWasmApp.CoreCLR.targets and Microsoft.NET.Sdk.WebAssembly.Browser.targets translate the Mono-style WasmPerformanceInstrumentation property (e.g. all,interval=0) into CoreCLR env vars (DOTNET_WasmPerformanceInstrumentation, sampling-rate var), with all mapped to the MethodSet wildcard *. Native build is forced on when the property is set.

Tests

  • Wasm.Build.Tests.Blazor.EventPipeDiagnosticsTests is added to BuildWasmAppsJobsListCoreCLR.txt so it runs for CoreCLR.
  • EventPipeDiagnosticsTests.cs: removed the class-level mono category so it runs on CoreCLR; split the AOT (Mono-only) case into its own native-mono[Fact] while the Debug/Release non-AOT cases run for both runtimes.
  • browser-eventpipe sample updated to demonstrate collectCpuSamples / collectGcDump / collectMetrics from the DevTools console.
imageimageimageimage

@pavelsavarapavelsavara added this to the 11.0.0 milestone Mar 30, 2026
@pavelsavarapavelsavara self-assigned this Mar 30, 2026
CopilotAI review requested due to automatic review settings March 30, 2026 16:51
@pavelsavarapavelsavara added arch-wasm WebAssembly architecture area-System.Diagnostics os-browser Browser variant of arch-wasm labels Mar 30, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @dotnet/area-system-diagnostics
See info in area-owners.md if you want to be subscribed.

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

Enables EventPipe/diagnostic-server plumbing for CoreCLR in browser by turning on FEATURE_PERFTRACING while keeping FEATURE_EVENT_TRACE disabled, and adds the browser-side scheduling + WebSocket/JS transport needed to drive the diagnostic server loop.

Changes:

  • Enable FEATURE_PERFTRACING for browser CoreCLR and gate ETW/EventTrace-specific code behind FEATURE_EVENT_TRACE (including EventPipe codegen changes).
  • Add browser-native diagnostic server job queue + scheduler callback wiring (SystemJS_*DiagnosticServer*).
  • Add JS diagnostics client/transport (WebSocket + in-browser “js://” scenarios) and expose ds_rt_websocket_* + dotnetApi.collect* helpers.

Reviewed changes

Copilot reviewed 42 out of 43 changed files in this pull request and generated 14 comments.

Show a summary per file
FileDescription
src/native/libs/System.Native.Browser/utils/scheduling.tsRuns the diagnostic server callback alongside other background callbacks; abort clears pending diagnostic server timer id.
src/native/libs/System.Native.Browser/native/scheduling.tsAdds SystemJS_ScheduleDiagnosticServer scheduling hook using safeSetTimeout.
src/native/libs/System.Native.Browser/native/index.tsExposes diagnostic server scheduler + callback through the native exports table; exports ds websocket shims.
src/native/libs/System.Native.Browser/native/diagnostics.tsAdds native-side re-exports for ds_rt_websocket_* via diagnostics cross-module exports.
src/native/libs/System.Native.Browser/diagnostics/types.tsIntroduces diagnostics protocol/session/provider types and enums used by the JS diagnostics client.
src/native/libs/System.Native.Browser/diagnostics/index.tsWires diagnostics exports table and installs JS diagnostics client + dotnetApi helpers.
src/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.tsAdds JS helper to collect gcdump trace via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/dotnet-cpu-profiler.tsAdds JS helper to collect CPU samples via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/dotnet-counters.tsAdds JS helper to collect metrics via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/diagnostics.tsImplements browser-side ds_rt_websocket_* transport and DS router reconnection support.
src/native/libs/System.Native.Browser/diagnostics/diagnostics-ws.tsImplements WebSocket-based diagnostic connection wrapper.
src/native/libs/System.Native.Browser/diagnostics/diagnostics-js.tsImplements in-browser “JS diagnostic client” session handling and scenario-based commands.
src/native/libs/System.Native.Browser/diagnostics/common.tsShared base queue/recv logic and trace download helper.
src/native/libs/System.Native.Browser/diagnostics/client-commands.tsImplements serialization for diagnostic IPC commands (advertise, EventPipe commands, etc.).
src/native/libs/System.Native.Browser/ds.hAdds placeholder header for diagnostic server C support.
src/native/libs/System.Native.Browser/ds.cAdds native diagnostic server job queue + callback executor for browser builds.
src/native/libs/System.Native.Browser/CMakeLists.txtLinks ds.c into System.Native.Browser-Static.
src/native/libs/Common/JavaScript/types/public-api.tsUpdates diagnostics public types (providerName).
src/native/libs/Common/JavaScript/types/exchange.tsExtends exchange tables/types for new native browser + diagnostics exports.
src/native/libs/Common/JavaScript/types/ems-ambient.tsAdds ambient symbol + timer id tracking for diagnostic server callback scheduling.
src/native/libs/Common/JavaScript/loader/dotnet.d.tsUpdates generated public type surface (providerName).
src/native/libs/Common/JavaScript/cross-module/index.tsUpdates cross-module table mapping for new native browser + diagnostics exports.
src/native/eventpipe/ds-ipc-pal-websocket.hAdds C linkage guards for websocket PAL APIs.
src/mono/mono/utils/mono-threads.hRenames/aligns DS job queue API name to SystemJS_DiagnosticServerQueueJob.
src/mono/mono/utils/mono-threads-wasm.hRenames DS exec callback export to SystemJS_ExecuteDiagnosticServerCallback.
src/mono/mono/utils/mono-threads-wasm.cRenames DS queue/exec functions for browser single-threaded mode.
src/mono/mono/mini/mini-wasm.cUpdates exported symbol name for DS exec callback.
src/mono/mono/eventpipe/ep-rt-mono.hUpdates DS job rescheduling callsite to new queue function name.
src/mono/browser/runtime/types/internal.tsUpdates runtime helper name for DS exec callback.
src/mono/browser/runtime/exports.tsExposes renamed DS exec callback in runtime exports.
src/mono/browser/runtime/diagnostics/common.tsCalls renamed DS exec callback from mono browser diagnostics event loop.
src/mono/browser/runtime/cwraps.tsUpdates cwrap signature to match renamed DS exec callback export.
src/coreclr/vm/qcallentrypoints.cppGates NativeRuntimeEventSource QCalls behind FEATURE_EVENT_TRACE while keeping EventPipe QCalls under FEATURE_PERFTRACING.
src/coreclr/vm/nativeeventsource.cppAdds non-ETW stubs when FEATURE_PERFTRACING is enabled but FEATURE_EVENT_TRACE is disabled.
src/coreclr/vm/gcenv.ee.cppWraps ETW-only GC analysis events with FEATURE_EVENT_TRACE guards.
src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.hAdds browser single-threaded job queue integration via SystemJS_DiagnosticServerQueueJob; gates ETW-only provider init behind FEATURE_EVENT_TRACE.
src/coreclr/vm/eventing/eventpipe/CMakeLists.txtAdds --noetwcallbacks option for EventPipe codegen when FEATURE_EVENT_TRACE is off.
src/coreclr/vm/eventing/CMakeLists.txtMakes dependency on eventprovider conditional.
src/coreclr/scripts/genEventPipe.pyAdds --noetwcallbacks support to omit ETW callback wiring in generated provider code.
src/coreclr/nativeaot/Runtime/disabledruntimeeventinternal.cppFixes a typo in a comment.
src/coreclr/clrfeatures.cmakeEnables FEATURE_PERFTRACING for browser targets; adjusts feature enablement logic.
src/coreclr/clrdefinitions.cmakeEnsures FEATURE_PERFTRACING defines and avoids creating dummy targets when perftracing is enabled.
src/coreclr/clr.featuredefines.propsEnables perf tracing for browser build configuration.

Comment threadsrc/native/libs/System.Native.Browser/diagnostics/common.ts
Comment threadsrc/native/libs/System.Native.Browser/diagnostics/diagnostics-ws.ts Outdated
Comment threadsrc/native/libs/Common/JavaScript/types/exchange.ts Outdated
Comment threadsrc/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.ts Outdated
Comment threadsrc/native/libs/Common/JavaScript/types/public-api.ts
Comment threadsrc/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h Outdated
CopilotAI review requested due to automatic review settings March 30, 2026 17:05
@pavelsavarapavelsavara changed the title [browser][coreCLR] event pipe[browser][coreCLR] event pipe and browser profilerApr 22, 2026
Comment threadsrc/coreclr/vm/wasm/browserprofiler.cpp Outdated
@pavelsavara

pavelsavara commented Jun 9, 2026

Copy link
Copy Markdown
MemberAuthor

@jkotas@BrzVlad please review

Edit: Let me know if you have further feedback, I'm happy to process it in next PR

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

/ba-g CI failures are unrelated

@pavelsavara
pavelsavara merged commit f867627 into dotnet:mainJun 12, 2026
175 of 183 checks passed
@pavelsavara
pavelsavara deleted the browser_EP_coreclr branch June 12, 2026 20:32
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 18, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-wasmWebAssembly architecturearea-System.Diagnosticsos-browserBrowser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@pavelsavara@akoeplinger@BrzVlad@jkotas@maraf@radekdoulik
, '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('^' + ".*" + ' [browser][coreCLR] event pipe and browser profiler by pavelsavara · Pull Request #126324 · dotnet/runtime · GitHub
Skip to content

[browser][coreCLR] event pipe and browser profiler - #126324

Merged
pavelsavara merged 6 commits into
dotnet:mainfrom
pavelsavara:browser_EP_coreclr
Jun 12, 2026
Merged

[browser][coreCLR] event pipe and browser profiler#126324
pavelsavara merged 6 commits into
dotnet:mainfrom
pavelsavara:browser_EP_coreclr

Conversation

@pavelsavara

@pavelsavarapavelsavara commented Mar 30, 2026

Copy link
Copy Markdown
Member

Summary

This change builds on top of EventPipe-for-CoreCLR (#128745) and adds two WASM profiling experiences for the CoreCLR interpreter on single-threaded browser/WASI builds:

  1. EventPipe CPU sampling profiler — a cooperative, single-threaded sampling profiler that produces .nettrace CPU samples consumable by dotnet-trace / the JS collectCpuSamples API.
  2. Browser DevTools profiler — emits performance.measure() calls so managed method execution shows up as a nested flame chart in the browser Performance tab.

Both are opt-in via the DOTNET_WasmPerformanceInstrumentation MethodSet filter and are wired up through the existing WasmPerformanceInstrumentation MSBuild property (CoreCLR-compatible syntax).

Motivation

On the multi-threaded runtime the EventPipe sample profiler runs on a dedicated thread that suspends the target. On single-threaded WASM there is no such thread, so the previous ep_rt_sample_profiler_* hooks were no-ops and CPU sampling was unavailable for CoreCLR. This adds a cooperative sampling mechanism driven by the interpreter, matching the capability Mono already provides on the browser.

How it works

New interpreter opcodes

Three opcodes are added in intops.def:

  • INTOP_PROF_SAMPLEPOINT — emitted at method entry and at backward branches (loop back-edges, alongside the existing INTOP_SAFEPOINT). Drives the EventPipe sampling profiler.
  • INTOP_PROF_ENTER / INTOP_PROF_LEAVE — emitted at method entry/return (and tail-call / exception unwind paths). Drive the browser DevTools profiler.

The interpreter compiler only emits these when the method matches the WasmPerformanceInstrumentation MethodSet filter, and only on PERFTRACING_DISABLE_THREADS (single-threaded) builds. INTOP_PROF_ENTER/INTOP_PROF_LEAVE are additionally gated on TARGET_BROWSER.

EventPipe CPU sampling (single-threaded)

ep-rt-coreclr-wasm-sampling.cpp implements the ep_rt_coreclr_sample_profiler_* callbacks (now wired from ep-rt-coreclr.h instead of being no-ops). SamplingProfiler_OnSamplepoint() is invoked from the interpreter at samplepoints and:

  • Uses a fast skip-counter path to avoid overhead on every samplepoint.
  • Adaptively recomputes the skip count using an exponential-moving-average against the desired sampling interval (the same approach as Mono's ep-rt-mono-runtime-provider.c).
  • Walks the managed stack and writes a managed sample profile event when due.

On multi-threaded builds the callbacks remain no-ops (the threaded profiler is used).

Browser DevTools profiler

browserprofiler.cpp maintains a shadow stack of method enter/leave timings and calls ds_rt_browser_performance_measure() (→ performance.measure()) so methods appear as nested entries in the browser Performance/flame chart. Recording is rate-limited with an adaptive skip counter; the shadow stack always tracks enter/leave for correctness, and a parent frame is marked for recording when a child is recorded so the chart nests properly. Leave only pops when the top frame matches, guarding against mismatched enter/leave for filtered-out methods.

Configuration / MSBuild

  • New RELEASE_CONFIG_METHODSET(WasmPerformanceInstrumentation) in interpconfigvalues.h. jitStartup enables the profilers when the filter is non-empty, before any managed code is compiled.
  • BrowserWasmApp.CoreCLR.targets and Microsoft.NET.Sdk.WebAssembly.Browser.targets translate the Mono-style WasmPerformanceInstrumentation property (e.g. all,interval=0) into CoreCLR env vars (DOTNET_WasmPerformanceInstrumentation, sampling-rate var), with all mapped to the MethodSet wildcard *. Native build is forced on when the property is set.

Tests

  • Wasm.Build.Tests.Blazor.EventPipeDiagnosticsTests is added to BuildWasmAppsJobsListCoreCLR.txt so it runs for CoreCLR.
  • EventPipeDiagnosticsTests.cs: removed the class-level mono category so it runs on CoreCLR; split the AOT (Mono-only) case into its own native-mono[Fact] while the Debug/Release non-AOT cases run for both runtimes.
  • browser-eventpipe sample updated to demonstrate collectCpuSamples / collectGcDump / collectMetrics from the DevTools console.
imageimageimageimage

@pavelsavarapavelsavara added this to the 11.0.0 milestone Mar 30, 2026
@pavelsavarapavelsavara self-assigned this Mar 30, 2026
CopilotAI review requested due to automatic review settings March 30, 2026 16:51
@pavelsavarapavelsavara added arch-wasm WebAssembly architecture area-System.Diagnostics os-browser Browser variant of arch-wasm labels Mar 30, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @dotnet/area-system-diagnostics
See info in area-owners.md if you want to be subscribed.

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

Enables EventPipe/diagnostic-server plumbing for CoreCLR in browser by turning on FEATURE_PERFTRACING while keeping FEATURE_EVENT_TRACE disabled, and adds the browser-side scheduling + WebSocket/JS transport needed to drive the diagnostic server loop.

Changes:

  • Enable FEATURE_PERFTRACING for browser CoreCLR and gate ETW/EventTrace-specific code behind FEATURE_EVENT_TRACE (including EventPipe codegen changes).
  • Add browser-native diagnostic server job queue + scheduler callback wiring (SystemJS_*DiagnosticServer*).
  • Add JS diagnostics client/transport (WebSocket + in-browser “js://” scenarios) and expose ds_rt_websocket_* + dotnetApi.collect* helpers.

Reviewed changes

Copilot reviewed 42 out of 43 changed files in this pull request and generated 14 comments.

Show a summary per file
FileDescription
src/native/libs/System.Native.Browser/utils/scheduling.tsRuns the diagnostic server callback alongside other background callbacks; abort clears pending diagnostic server timer id.
src/native/libs/System.Native.Browser/native/scheduling.tsAdds SystemJS_ScheduleDiagnosticServer scheduling hook using safeSetTimeout.
src/native/libs/System.Native.Browser/native/index.tsExposes diagnostic server scheduler + callback through the native exports table; exports ds websocket shims.
src/native/libs/System.Native.Browser/native/diagnostics.tsAdds native-side re-exports for ds_rt_websocket_* via diagnostics cross-module exports.
src/native/libs/System.Native.Browser/diagnostics/types.tsIntroduces diagnostics protocol/session/provider types and enums used by the JS diagnostics client.
src/native/libs/System.Native.Browser/diagnostics/index.tsWires diagnostics exports table and installs JS diagnostics client + dotnetApi helpers.
src/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.tsAdds JS helper to collect gcdump trace via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/dotnet-cpu-profiler.tsAdds JS helper to collect CPU samples via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/dotnet-counters.tsAdds JS helper to collect metrics via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/diagnostics.tsImplements browser-side ds_rt_websocket_* transport and DS router reconnection support.
src/native/libs/System.Native.Browser/diagnostics/diagnostics-ws.tsImplements WebSocket-based diagnostic connection wrapper.
src/native/libs/System.Native.Browser/diagnostics/diagnostics-js.tsImplements in-browser “JS diagnostic client” session handling and scenario-based commands.
src/native/libs/System.Native.Browser/diagnostics/common.tsShared base queue/recv logic and trace download helper.
src/native/libs/System.Native.Browser/diagnostics/client-commands.tsImplements serialization for diagnostic IPC commands (advertise, EventPipe commands, etc.).
src/native/libs/System.Native.Browser/ds.hAdds placeholder header for diagnostic server C support.
src/native/libs/System.Native.Browser/ds.cAdds native diagnostic server job queue + callback executor for browser builds.
src/native/libs/System.Native.Browser/CMakeLists.txtLinks ds.c into System.Native.Browser-Static.
src/native/libs/Common/JavaScript/types/public-api.tsUpdates diagnostics public types (providerName).
src/native/libs/Common/JavaScript/types/exchange.tsExtends exchange tables/types for new native browser + diagnostics exports.
src/native/libs/Common/JavaScript/types/ems-ambient.tsAdds ambient symbol + timer id tracking for diagnostic server callback scheduling.
src/native/libs/Common/JavaScript/loader/dotnet.d.tsUpdates generated public type surface (providerName).
src/native/libs/Common/JavaScript/cross-module/index.tsUpdates cross-module table mapping for new native browser + diagnostics exports.
src/native/eventpipe/ds-ipc-pal-websocket.hAdds C linkage guards for websocket PAL APIs.
src/mono/mono/utils/mono-threads.hRenames/aligns DS job queue API name to SystemJS_DiagnosticServerQueueJob.
src/mono/mono/utils/mono-threads-wasm.hRenames DS exec callback export to SystemJS_ExecuteDiagnosticServerCallback.
src/mono/mono/utils/mono-threads-wasm.cRenames DS queue/exec functions for browser single-threaded mode.
src/mono/mono/mini/mini-wasm.cUpdates exported symbol name for DS exec callback.
src/mono/mono/eventpipe/ep-rt-mono.hUpdates DS job rescheduling callsite to new queue function name.
src/mono/browser/runtime/types/internal.tsUpdates runtime helper name for DS exec callback.
src/mono/browser/runtime/exports.tsExposes renamed DS exec callback in runtime exports.
src/mono/browser/runtime/diagnostics/common.tsCalls renamed DS exec callback from mono browser diagnostics event loop.
src/mono/browser/runtime/cwraps.tsUpdates cwrap signature to match renamed DS exec callback export.
src/coreclr/vm/qcallentrypoints.cppGates NativeRuntimeEventSource QCalls behind FEATURE_EVENT_TRACE while keeping EventPipe QCalls under FEATURE_PERFTRACING.
src/coreclr/vm/nativeeventsource.cppAdds non-ETW stubs when FEATURE_PERFTRACING is enabled but FEATURE_EVENT_TRACE is disabled.
src/coreclr/vm/gcenv.ee.cppWraps ETW-only GC analysis events with FEATURE_EVENT_TRACE guards.
src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.hAdds browser single-threaded job queue integration via SystemJS_DiagnosticServerQueueJob; gates ETW-only provider init behind FEATURE_EVENT_TRACE.
src/coreclr/vm/eventing/eventpipe/CMakeLists.txtAdds --noetwcallbacks option for EventPipe codegen when FEATURE_EVENT_TRACE is off.
src/coreclr/vm/eventing/CMakeLists.txtMakes dependency on eventprovider conditional.
src/coreclr/scripts/genEventPipe.pyAdds --noetwcallbacks support to omit ETW callback wiring in generated provider code.
src/coreclr/nativeaot/Runtime/disabledruntimeeventinternal.cppFixes a typo in a comment.
src/coreclr/clrfeatures.cmakeEnables FEATURE_PERFTRACING for browser targets; adjusts feature enablement logic.
src/coreclr/clrdefinitions.cmakeEnsures FEATURE_PERFTRACING defines and avoids creating dummy targets when perftracing is enabled.
src/coreclr/clr.featuredefines.propsEnables perf tracing for browser build configuration.

Comment threadsrc/native/libs/System.Native.Browser/diagnostics/common.ts
Comment threadsrc/native/libs/System.Native.Browser/diagnostics/diagnostics-ws.ts Outdated
Comment threadsrc/native/libs/Common/JavaScript/types/exchange.ts Outdated
Comment threadsrc/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.ts Outdated
Comment threadsrc/native/libs/Common/JavaScript/types/public-api.ts
Comment threadsrc/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h Outdated
CopilotAI review requested due to automatic review settings March 30, 2026 17:05
@pavelsavarapavelsavara changed the title [browser][coreCLR] event pipe[browser][coreCLR] event pipe and browser profilerApr 22, 2026
Comment threadsrc/coreclr/vm/wasm/browserprofiler.cpp Outdated
@pavelsavara

pavelsavara commented Jun 9, 2026

Copy link
Copy Markdown
MemberAuthor

@jkotas@BrzVlad please review

Edit: Let me know if you have further feedback, I'm happy to process it in next PR

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

/ba-g CI failures are unrelated

@pavelsavara
pavelsavara merged commit f867627 into dotnet:mainJun 12, 2026
175 of 183 checks passed
@pavelsavara
pavelsavara deleted the browser_EP_coreclr branch June 12, 2026 20:32
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 18, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-wasmWebAssembly architecturearea-System.Diagnosticsos-browserBrowser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@pavelsavara@akoeplinger@BrzVlad@jkotas@maraf@radekdoulik
, '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); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [browser][coreCLR] event pipe and browser profiler by pavelsavara · Pull Request #126324 · dotnet/runtime · GitHub
Skip to content

[browser][coreCLR] event pipe and browser profiler - #126324

Merged
pavelsavara merged 6 commits into
dotnet:mainfrom
pavelsavara:browser_EP_coreclr
Jun 12, 2026
Merged

[browser][coreCLR] event pipe and browser profiler#126324
pavelsavara merged 6 commits into
dotnet:mainfrom
pavelsavara:browser_EP_coreclr

Conversation

@pavelsavara

@pavelsavarapavelsavara commented Mar 30, 2026

Copy link
Copy Markdown
Member

Summary

This change builds on top of EventPipe-for-CoreCLR (#128745) and adds two WASM profiling experiences for the CoreCLR interpreter on single-threaded browser/WASI builds:

  1. EventPipe CPU sampling profiler — a cooperative, single-threaded sampling profiler that produces .nettrace CPU samples consumable by dotnet-trace / the JS collectCpuSamples API.
  2. Browser DevTools profiler — emits performance.measure() calls so managed method execution shows up as a nested flame chart in the browser Performance tab.

Both are opt-in via the DOTNET_WasmPerformanceInstrumentation MethodSet filter and are wired up through the existing WasmPerformanceInstrumentation MSBuild property (CoreCLR-compatible syntax).

Motivation

On the multi-threaded runtime the EventPipe sample profiler runs on a dedicated thread that suspends the target. On single-threaded WASM there is no such thread, so the previous ep_rt_sample_profiler_* hooks were no-ops and CPU sampling was unavailable for CoreCLR. This adds a cooperative sampling mechanism driven by the interpreter, matching the capability Mono already provides on the browser.

How it works

New interpreter opcodes

Three opcodes are added in intops.def:

  • INTOP_PROF_SAMPLEPOINT — emitted at method entry and at backward branches (loop back-edges, alongside the existing INTOP_SAFEPOINT). Drives the EventPipe sampling profiler.
  • INTOP_PROF_ENTER / INTOP_PROF_LEAVE — emitted at method entry/return (and tail-call / exception unwind paths). Drive the browser DevTools profiler.

The interpreter compiler only emits these when the method matches the WasmPerformanceInstrumentation MethodSet filter, and only on PERFTRACING_DISABLE_THREADS (single-threaded) builds. INTOP_PROF_ENTER/INTOP_PROF_LEAVE are additionally gated on TARGET_BROWSER.

EventPipe CPU sampling (single-threaded)

ep-rt-coreclr-wasm-sampling.cpp implements the ep_rt_coreclr_sample_profiler_* callbacks (now wired from ep-rt-coreclr.h instead of being no-ops). SamplingProfiler_OnSamplepoint() is invoked from the interpreter at samplepoints and:

  • Uses a fast skip-counter path to avoid overhead on every samplepoint.
  • Adaptively recomputes the skip count using an exponential-moving-average against the desired sampling interval (the same approach as Mono's ep-rt-mono-runtime-provider.c).
  • Walks the managed stack and writes a managed sample profile event when due.

On multi-threaded builds the callbacks remain no-ops (the threaded profiler is used).

Browser DevTools profiler

browserprofiler.cpp maintains a shadow stack of method enter/leave timings and calls ds_rt_browser_performance_measure() (→ performance.measure()) so methods appear as nested entries in the browser Performance/flame chart. Recording is rate-limited with an adaptive skip counter; the shadow stack always tracks enter/leave for correctness, and a parent frame is marked for recording when a child is recorded so the chart nests properly. Leave only pops when the top frame matches, guarding against mismatched enter/leave for filtered-out methods.

Configuration / MSBuild

  • New RELEASE_CONFIG_METHODSET(WasmPerformanceInstrumentation) in interpconfigvalues.h. jitStartup enables the profilers when the filter is non-empty, before any managed code is compiled.
  • BrowserWasmApp.CoreCLR.targets and Microsoft.NET.Sdk.WebAssembly.Browser.targets translate the Mono-style WasmPerformanceInstrumentation property (e.g. all,interval=0) into CoreCLR env vars (DOTNET_WasmPerformanceInstrumentation, sampling-rate var), with all mapped to the MethodSet wildcard *. Native build is forced on when the property is set.

Tests

  • Wasm.Build.Tests.Blazor.EventPipeDiagnosticsTests is added to BuildWasmAppsJobsListCoreCLR.txt so it runs for CoreCLR.
  • EventPipeDiagnosticsTests.cs: removed the class-level mono category so it runs on CoreCLR; split the AOT (Mono-only) case into its own native-mono[Fact] while the Debug/Release non-AOT cases run for both runtimes.
  • browser-eventpipe sample updated to demonstrate collectCpuSamples / collectGcDump / collectMetrics from the DevTools console.
imageimageimageimage

@pavelsavarapavelsavara added this to the 11.0.0 milestone Mar 30, 2026
@pavelsavarapavelsavara self-assigned this Mar 30, 2026
CopilotAI review requested due to automatic review settings March 30, 2026 16:51
@pavelsavarapavelsavara added arch-wasm WebAssembly architecture area-System.Diagnostics os-browser Browser variant of arch-wasm labels Mar 30, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @dotnet/area-system-diagnostics
See info in area-owners.md if you want to be subscribed.

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

Enables EventPipe/diagnostic-server plumbing for CoreCLR in browser by turning on FEATURE_PERFTRACING while keeping FEATURE_EVENT_TRACE disabled, and adds the browser-side scheduling + WebSocket/JS transport needed to drive the diagnostic server loop.

Changes:

  • Enable FEATURE_PERFTRACING for browser CoreCLR and gate ETW/EventTrace-specific code behind FEATURE_EVENT_TRACE (including EventPipe codegen changes).
  • Add browser-native diagnostic server job queue + scheduler callback wiring (SystemJS_*DiagnosticServer*).
  • Add JS diagnostics client/transport (WebSocket + in-browser “js://” scenarios) and expose ds_rt_websocket_* + dotnetApi.collect* helpers.

Reviewed changes

Copilot reviewed 42 out of 43 changed files in this pull request and generated 14 comments.

Show a summary per file
FileDescription
src/native/libs/System.Native.Browser/utils/scheduling.tsRuns the diagnostic server callback alongside other background callbacks; abort clears pending diagnostic server timer id.
src/native/libs/System.Native.Browser/native/scheduling.tsAdds SystemJS_ScheduleDiagnosticServer scheduling hook using safeSetTimeout.
src/native/libs/System.Native.Browser/native/index.tsExposes diagnostic server scheduler + callback through the native exports table; exports ds websocket shims.
src/native/libs/System.Native.Browser/native/diagnostics.tsAdds native-side re-exports for ds_rt_websocket_* via diagnostics cross-module exports.
src/native/libs/System.Native.Browser/diagnostics/types.tsIntroduces diagnostics protocol/session/provider types and enums used by the JS diagnostics client.
src/native/libs/System.Native.Browser/diagnostics/index.tsWires diagnostics exports table and installs JS diagnostics client + dotnetApi helpers.
src/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.tsAdds JS helper to collect gcdump trace via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/dotnet-cpu-profiler.tsAdds JS helper to collect CPU samples via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/dotnet-counters.tsAdds JS helper to collect metrics via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/diagnostics.tsImplements browser-side ds_rt_websocket_* transport and DS router reconnection support.
src/native/libs/System.Native.Browser/diagnostics/diagnostics-ws.tsImplements WebSocket-based diagnostic connection wrapper.
src/native/libs/System.Native.Browser/diagnostics/diagnostics-js.tsImplements in-browser “JS diagnostic client” session handling and scenario-based commands.
src/native/libs/System.Native.Browser/diagnostics/common.tsShared base queue/recv logic and trace download helper.
src/native/libs/System.Native.Browser/diagnostics/client-commands.tsImplements serialization for diagnostic IPC commands (advertise, EventPipe commands, etc.).
src/native/libs/System.Native.Browser/ds.hAdds placeholder header for diagnostic server C support.
src/native/libs/System.Native.Browser/ds.cAdds native diagnostic server job queue + callback executor for browser builds.
src/native/libs/System.Native.Browser/CMakeLists.txtLinks ds.c into System.Native.Browser-Static.
src/native/libs/Common/JavaScript/types/public-api.tsUpdates diagnostics public types (providerName).
src/native/libs/Common/JavaScript/types/exchange.tsExtends exchange tables/types for new native browser + diagnostics exports.
src/native/libs/Common/JavaScript/types/ems-ambient.tsAdds ambient symbol + timer id tracking for diagnostic server callback scheduling.
src/native/libs/Common/JavaScript/loader/dotnet.d.tsUpdates generated public type surface (providerName).
src/native/libs/Common/JavaScript/cross-module/index.tsUpdates cross-module table mapping for new native browser + diagnostics exports.
src/native/eventpipe/ds-ipc-pal-websocket.hAdds C linkage guards for websocket PAL APIs.
src/mono/mono/utils/mono-threads.hRenames/aligns DS job queue API name to SystemJS_DiagnosticServerQueueJob.
src/mono/mono/utils/mono-threads-wasm.hRenames DS exec callback export to SystemJS_ExecuteDiagnosticServerCallback.
src/mono/mono/utils/mono-threads-wasm.cRenames DS queue/exec functions for browser single-threaded mode.
src/mono/mono/mini/mini-wasm.cUpdates exported symbol name for DS exec callback.
src/mono/mono/eventpipe/ep-rt-mono.hUpdates DS job rescheduling callsite to new queue function name.
src/mono/browser/runtime/types/internal.tsUpdates runtime helper name for DS exec callback.
src/mono/browser/runtime/exports.tsExposes renamed DS exec callback in runtime exports.
src/mono/browser/runtime/diagnostics/common.tsCalls renamed DS exec callback from mono browser diagnostics event loop.
src/mono/browser/runtime/cwraps.tsUpdates cwrap signature to match renamed DS exec callback export.
src/coreclr/vm/qcallentrypoints.cppGates NativeRuntimeEventSource QCalls behind FEATURE_EVENT_TRACE while keeping EventPipe QCalls under FEATURE_PERFTRACING.
src/coreclr/vm/nativeeventsource.cppAdds non-ETW stubs when FEATURE_PERFTRACING is enabled but FEATURE_EVENT_TRACE is disabled.
src/coreclr/vm/gcenv.ee.cppWraps ETW-only GC analysis events with FEATURE_EVENT_TRACE guards.
src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.hAdds browser single-threaded job queue integration via SystemJS_DiagnosticServerQueueJob; gates ETW-only provider init behind FEATURE_EVENT_TRACE.
src/coreclr/vm/eventing/eventpipe/CMakeLists.txtAdds --noetwcallbacks option for EventPipe codegen when FEATURE_EVENT_TRACE is off.
src/coreclr/vm/eventing/CMakeLists.txtMakes dependency on eventprovider conditional.
src/coreclr/scripts/genEventPipe.pyAdds --noetwcallbacks support to omit ETW callback wiring in generated provider code.
src/coreclr/nativeaot/Runtime/disabledruntimeeventinternal.cppFixes a typo in a comment.
src/coreclr/clrfeatures.cmakeEnables FEATURE_PERFTRACING for browser targets; adjusts feature enablement logic.
src/coreclr/clrdefinitions.cmakeEnsures FEATURE_PERFTRACING defines and avoids creating dummy targets when perftracing is enabled.
src/coreclr/clr.featuredefines.propsEnables perf tracing for browser build configuration.

Comment threadsrc/native/libs/System.Native.Browser/diagnostics/common.ts
Comment threadsrc/native/libs/System.Native.Browser/diagnostics/diagnostics-ws.ts Outdated
Comment threadsrc/native/libs/Common/JavaScript/types/exchange.ts Outdated
Comment threadsrc/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.ts Outdated
Comment threadsrc/native/libs/Common/JavaScript/types/public-api.ts
Comment threadsrc/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h Outdated
CopilotAI review requested due to automatic review settings March 30, 2026 17:05
@pavelsavarapavelsavara changed the title [browser][coreCLR] event pipe[browser][coreCLR] event pipe and browser profilerApr 22, 2026
Comment threadsrc/coreclr/vm/wasm/browserprofiler.cpp Outdated
@pavelsavara

pavelsavara commented Jun 9, 2026

Copy link
Copy Markdown
MemberAuthor

@jkotas@BrzVlad please review

Edit: Let me know if you have further feedback, I'm happy to process it in next PR

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

/ba-g CI failures are unrelated

@pavelsavara
pavelsavara merged commit f867627 into dotnet:mainJun 12, 2026
175 of 183 checks passed
@pavelsavara
pavelsavara deleted the browser_EP_coreclr branch June 12, 2026 20:32
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 18, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-wasmWebAssembly architecturearea-System.Diagnosticsos-browserBrowser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

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

[browser][coreCLR] event pipe and browser profiler - #126324

Merged
pavelsavara merged 6 commits into
dotnet:mainfrom
pavelsavara:browser_EP_coreclr
Jun 12, 2026
Merged

[browser][coreCLR] event pipe and browser profiler#126324
pavelsavara merged 6 commits into
dotnet:mainfrom
pavelsavara:browser_EP_coreclr

Conversation

@pavelsavara

@pavelsavarapavelsavara commented Mar 30, 2026

Copy link
Copy Markdown
Member

Summary

This change builds on top of EventPipe-for-CoreCLR (#128745) and adds two WASM profiling experiences for the CoreCLR interpreter on single-threaded browser/WASI builds:

  1. EventPipe CPU sampling profiler — a cooperative, single-threaded sampling profiler that produces .nettrace CPU samples consumable by dotnet-trace / the JS collectCpuSamples API.
  2. Browser DevTools profiler — emits performance.measure() calls so managed method execution shows up as a nested flame chart in the browser Performance tab.

Both are opt-in via the DOTNET_WasmPerformanceInstrumentation MethodSet filter and are wired up through the existing WasmPerformanceInstrumentation MSBuild property (CoreCLR-compatible syntax).

Motivation

On the multi-threaded runtime the EventPipe sample profiler runs on a dedicated thread that suspends the target. On single-threaded WASM there is no such thread, so the previous ep_rt_sample_profiler_* hooks were no-ops and CPU sampling was unavailable for CoreCLR. This adds a cooperative sampling mechanism driven by the interpreter, matching the capability Mono already provides on the browser.

How it works

New interpreter opcodes

Three opcodes are added in intops.def:

  • INTOP_PROF_SAMPLEPOINT — emitted at method entry and at backward branches (loop back-edges, alongside the existing INTOP_SAFEPOINT). Drives the EventPipe sampling profiler.
  • INTOP_PROF_ENTER / INTOP_PROF_LEAVE — emitted at method entry/return (and tail-call / exception unwind paths). Drive the browser DevTools profiler.

The interpreter compiler only emits these when the method matches the WasmPerformanceInstrumentation MethodSet filter, and only on PERFTRACING_DISABLE_THREADS (single-threaded) builds. INTOP_PROF_ENTER/INTOP_PROF_LEAVE are additionally gated on TARGET_BROWSER.

EventPipe CPU sampling (single-threaded)

ep-rt-coreclr-wasm-sampling.cpp implements the ep_rt_coreclr_sample_profiler_* callbacks (now wired from ep-rt-coreclr.h instead of being no-ops). SamplingProfiler_OnSamplepoint() is invoked from the interpreter at samplepoints and:

  • Uses a fast skip-counter path to avoid overhead on every samplepoint.
  • Adaptively recomputes the skip count using an exponential-moving-average against the desired sampling interval (the same approach as Mono's ep-rt-mono-runtime-provider.c).
  • Walks the managed stack and writes a managed sample profile event when due.

On multi-threaded builds the callbacks remain no-ops (the threaded profiler is used).

Browser DevTools profiler

browserprofiler.cpp maintains a shadow stack of method enter/leave timings and calls ds_rt_browser_performance_measure() (→ performance.measure()) so methods appear as nested entries in the browser Performance/flame chart. Recording is rate-limited with an adaptive skip counter; the shadow stack always tracks enter/leave for correctness, and a parent frame is marked for recording when a child is recorded so the chart nests properly. Leave only pops when the top frame matches, guarding against mismatched enter/leave for filtered-out methods.

Configuration / MSBuild

  • New RELEASE_CONFIG_METHODSET(WasmPerformanceInstrumentation) in interpconfigvalues.h. jitStartup enables the profilers when the filter is non-empty, before any managed code is compiled.
  • BrowserWasmApp.CoreCLR.targets and Microsoft.NET.Sdk.WebAssembly.Browser.targets translate the Mono-style WasmPerformanceInstrumentation property (e.g. all,interval=0) into CoreCLR env vars (DOTNET_WasmPerformanceInstrumentation, sampling-rate var), with all mapped to the MethodSet wildcard *. Native build is forced on when the property is set.

Tests

  • Wasm.Build.Tests.Blazor.EventPipeDiagnosticsTests is added to BuildWasmAppsJobsListCoreCLR.txt so it runs for CoreCLR.
  • EventPipeDiagnosticsTests.cs: removed the class-level mono category so it runs on CoreCLR; split the AOT (Mono-only) case into its own native-mono[Fact] while the Debug/Release non-AOT cases run for both runtimes.
  • browser-eventpipe sample updated to demonstrate collectCpuSamples / collectGcDump / collectMetrics from the DevTools console.
imageimageimageimage

@pavelsavarapavelsavara added this to the 11.0.0 milestone Mar 30, 2026
@pavelsavarapavelsavara self-assigned this Mar 30, 2026
CopilotAI review requested due to automatic review settings March 30, 2026 16:51
@pavelsavarapavelsavara added arch-wasm WebAssembly architecture area-System.Diagnostics os-browser Browser variant of arch-wasm labels Mar 30, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @dotnet/area-system-diagnostics
See info in area-owners.md if you want to be subscribed.

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

Enables EventPipe/diagnostic-server plumbing for CoreCLR in browser by turning on FEATURE_PERFTRACING while keeping FEATURE_EVENT_TRACE disabled, and adds the browser-side scheduling + WebSocket/JS transport needed to drive the diagnostic server loop.

Changes:

  • Enable FEATURE_PERFTRACING for browser CoreCLR and gate ETW/EventTrace-specific code behind FEATURE_EVENT_TRACE (including EventPipe codegen changes).
  • Add browser-native diagnostic server job queue + scheduler callback wiring (SystemJS_*DiagnosticServer*).
  • Add JS diagnostics client/transport (WebSocket + in-browser “js://” scenarios) and expose ds_rt_websocket_* + dotnetApi.collect* helpers.

Reviewed changes

Copilot reviewed 42 out of 43 changed files in this pull request and generated 14 comments.

Show a summary per file
FileDescription
src/native/libs/System.Native.Browser/utils/scheduling.tsRuns the diagnostic server callback alongside other background callbacks; abort clears pending diagnostic server timer id.
src/native/libs/System.Native.Browser/native/scheduling.tsAdds SystemJS_ScheduleDiagnosticServer scheduling hook using safeSetTimeout.
src/native/libs/System.Native.Browser/native/index.tsExposes diagnostic server scheduler + callback through the native exports table; exports ds websocket shims.
src/native/libs/System.Native.Browser/native/diagnostics.tsAdds native-side re-exports for ds_rt_websocket_* via diagnostics cross-module exports.
src/native/libs/System.Native.Browser/diagnostics/types.tsIntroduces diagnostics protocol/session/provider types and enums used by the JS diagnostics client.
src/native/libs/System.Native.Browser/diagnostics/index.tsWires diagnostics exports table and installs JS diagnostics client + dotnetApi helpers.
src/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.tsAdds JS helper to collect gcdump trace via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/dotnet-cpu-profiler.tsAdds JS helper to collect CPU samples via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/dotnet-counters.tsAdds JS helper to collect metrics via diagnostic server protocol.
src/native/libs/System.Native.Browser/diagnostics/diagnostics.tsImplements browser-side ds_rt_websocket_* transport and DS router reconnection support.
src/native/libs/System.Native.Browser/diagnostics/diagnostics-ws.tsImplements WebSocket-based diagnostic connection wrapper.
src/native/libs/System.Native.Browser/diagnostics/diagnostics-js.tsImplements in-browser “JS diagnostic client” session handling and scenario-based commands.
src/native/libs/System.Native.Browser/diagnostics/common.tsShared base queue/recv logic and trace download helper.
src/native/libs/System.Native.Browser/diagnostics/client-commands.tsImplements serialization for diagnostic IPC commands (advertise, EventPipe commands, etc.).
src/native/libs/System.Native.Browser/ds.hAdds placeholder header for diagnostic server C support.
src/native/libs/System.Native.Browser/ds.cAdds native diagnostic server job queue + callback executor for browser builds.
src/native/libs/System.Native.Browser/CMakeLists.txtLinks ds.c into System.Native.Browser-Static.
src/native/libs/Common/JavaScript/types/public-api.tsUpdates diagnostics public types (providerName).
src/native/libs/Common/JavaScript/types/exchange.tsExtends exchange tables/types for new native browser + diagnostics exports.
src/native/libs/Common/JavaScript/types/ems-ambient.tsAdds ambient symbol + timer id tracking for diagnostic server callback scheduling.
src/native/libs/Common/JavaScript/loader/dotnet.d.tsUpdates generated public type surface (providerName).
src/native/libs/Common/JavaScript/cross-module/index.tsUpdates cross-module table mapping for new native browser + diagnostics exports.
src/native/eventpipe/ds-ipc-pal-websocket.hAdds C linkage guards for websocket PAL APIs.
src/mono/mono/utils/mono-threads.hRenames/aligns DS job queue API name to SystemJS_DiagnosticServerQueueJob.
src/mono/mono/utils/mono-threads-wasm.hRenames DS exec callback export to SystemJS_ExecuteDiagnosticServerCallback.
src/mono/mono/utils/mono-threads-wasm.cRenames DS queue/exec functions for browser single-threaded mode.
src/mono/mono/mini/mini-wasm.cUpdates exported symbol name for DS exec callback.
src/mono/mono/eventpipe/ep-rt-mono.hUpdates DS job rescheduling callsite to new queue function name.
src/mono/browser/runtime/types/internal.tsUpdates runtime helper name for DS exec callback.
src/mono/browser/runtime/exports.tsExposes renamed DS exec callback in runtime exports.
src/mono/browser/runtime/diagnostics/common.tsCalls renamed DS exec callback from mono browser diagnostics event loop.
src/mono/browser/runtime/cwraps.tsUpdates cwrap signature to match renamed DS exec callback export.
src/coreclr/vm/qcallentrypoints.cppGates NativeRuntimeEventSource QCalls behind FEATURE_EVENT_TRACE while keeping EventPipe QCalls under FEATURE_PERFTRACING.
src/coreclr/vm/nativeeventsource.cppAdds non-ETW stubs when FEATURE_PERFTRACING is enabled but FEATURE_EVENT_TRACE is disabled.
src/coreclr/vm/gcenv.ee.cppWraps ETW-only GC analysis events with FEATURE_EVENT_TRACE guards.
src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.hAdds browser single-threaded job queue integration via SystemJS_DiagnosticServerQueueJob; gates ETW-only provider init behind FEATURE_EVENT_TRACE.
src/coreclr/vm/eventing/eventpipe/CMakeLists.txtAdds --noetwcallbacks option for EventPipe codegen when FEATURE_EVENT_TRACE is off.
src/coreclr/vm/eventing/CMakeLists.txtMakes dependency on eventprovider conditional.
src/coreclr/scripts/genEventPipe.pyAdds --noetwcallbacks support to omit ETW callback wiring in generated provider code.
src/coreclr/nativeaot/Runtime/disabledruntimeeventinternal.cppFixes a typo in a comment.
src/coreclr/clrfeatures.cmakeEnables FEATURE_PERFTRACING for browser targets; adjusts feature enablement logic.
src/coreclr/clrdefinitions.cmakeEnsures FEATURE_PERFTRACING defines and avoids creating dummy targets when perftracing is enabled.
src/coreclr/clr.featuredefines.propsEnables perf tracing for browser build configuration.

Comment threadsrc/native/libs/System.Native.Browser/diagnostics/common.ts
Comment threadsrc/native/libs/System.Native.Browser/diagnostics/diagnostics-ws.ts Outdated
Comment threadsrc/native/libs/Common/JavaScript/types/exchange.ts Outdated
Comment threadsrc/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.ts Outdated
Comment threadsrc/native/libs/Common/JavaScript/types/public-api.ts
Comment threadsrc/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h Outdated
CopilotAI review requested due to automatic review settings March 30, 2026 17:05
@pavelsavarapavelsavara changed the title [browser][coreCLR] event pipe[browser][coreCLR] event pipe and browser profilerApr 22, 2026
Comment threadsrc/coreclr/vm/wasm/browserprofiler.cpp Outdated
@pavelsavara

pavelsavara commented Jun 9, 2026

Copy link
Copy Markdown
MemberAuthor

@jkotas@BrzVlad please review

Edit: Let me know if you have further feedback, I'm happy to process it in next PR

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

/ba-g CI failures are unrelated

@pavelsavara
pavelsavara merged commit f867627 into dotnet:mainJun 12, 2026
175 of 183 checks passed
@pavelsavara
pavelsavara deleted the browser_EP_coreclr branch June 12, 2026 20:32
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 18, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-wasmWebAssembly architecturearea-System.Diagnosticsos-browserBrowser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@pavelsavara@akoeplinger@BrzVlad@jkotas@maraf@radekdoulik