[browser][coreCLR] event pipe and browser profiler#126324
Open
pavelsavara wants to merge 2 commits into
Open
Conversation
Contributor
|
Tagging subscribers to this area: @steveisok, @dotnet/area-system-diagnostics |
Contributor
There was a problem hiding this comment.
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_PERFTRACINGfor browser CoreCLR and gate ETW/EventTrace-specific code behindFEATURE_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
| File | Description |
|---|---|
| src/native/libs/System.Native.Browser/utils/scheduling.ts | Runs the diagnostic server callback alongside other background callbacks; abort clears pending diagnostic server timer id. |
| src/native/libs/System.Native.Browser/native/scheduling.ts | Adds SystemJS_ScheduleDiagnosticServer scheduling hook using safeSetTimeout. |
| src/native/libs/System.Native.Browser/native/index.ts | Exposes diagnostic server scheduler + callback through the native exports table; exports ds websocket shims. |
| src/native/libs/System.Native.Browser/native/diagnostics.ts | Adds native-side re-exports for ds_rt_websocket_* via diagnostics cross-module exports. |
| src/native/libs/System.Native.Browser/diagnostics/types.ts | Introduces diagnostics protocol/session/provider types and enums used by the JS diagnostics client. |
| src/native/libs/System.Native.Browser/diagnostics/index.ts | Wires diagnostics exports table and installs JS diagnostics client + dotnetApi helpers. |
| src/native/libs/System.Native.Browser/diagnostics/dotnet-gcdump.ts | Adds JS helper to collect gcdump trace via diagnostic server protocol. |
| src/native/libs/System.Native.Browser/diagnostics/dotnet-cpu-profiler.ts | Adds JS helper to collect CPU samples via diagnostic server protocol. |
| src/native/libs/System.Native.Browser/diagnostics/dotnet-counters.ts | Adds JS helper to collect metrics via diagnostic server protocol. |
| src/native/libs/System.Native.Browser/diagnostics/diagnostics.ts | Implements browser-side ds_rt_websocket_* transport and DS router reconnection support. |
| src/native/libs/System.Native.Browser/diagnostics/diagnostics-ws.ts | Implements WebSocket-based diagnostic connection wrapper. |
| src/native/libs/System.Native.Browser/diagnostics/diagnostics-js.ts | Implements in-browser “JS diagnostic client” session handling and scenario-based commands. |
| src/native/libs/System.Native.Browser/diagnostics/common.ts | Shared base queue/recv logic and trace download helper. |
| src/native/libs/System.Native.Browser/diagnostics/client-commands.ts | Implements serialization for diagnostic IPC commands (advertise, EventPipe commands, etc.). |
| src/native/libs/System.Native.Browser/ds.h | Adds placeholder header for diagnostic server C support. |
| src/native/libs/System.Native.Browser/ds.c | Adds native diagnostic server job queue + callback executor for browser builds. |
| src/native/libs/System.Native.Browser/CMakeLists.txt | Links ds.c into System.Native.Browser-Static. |
| src/native/libs/Common/JavaScript/types/public-api.ts | Updates diagnostics public types (providerName). |
| src/native/libs/Common/JavaScript/types/exchange.ts | Extends exchange tables/types for new native browser + diagnostics exports. |
| src/native/libs/Common/JavaScript/types/ems-ambient.ts | Adds ambient symbol + timer id tracking for diagnostic server callback scheduling. |
| src/native/libs/Common/JavaScript/loader/dotnet.d.ts | Updates generated public type surface (providerName). |
| src/native/libs/Common/JavaScript/cross-module/index.ts | Updates cross-module table mapping for new native browser + diagnostics exports. |
| src/native/eventpipe/ds-ipc-pal-websocket.h | Adds C linkage guards for websocket PAL APIs. |
| src/mono/mono/utils/mono-threads.h | Renames/aligns DS job queue API name to SystemJS_DiagnosticServerQueueJob. |
| src/mono/mono/utils/mono-threads-wasm.h | Renames DS exec callback export to SystemJS_ExecuteDiagnosticServerCallback. |
| src/mono/mono/utils/mono-threads-wasm.c | Renames DS queue/exec functions for browser single-threaded mode. |
| src/mono/mono/mini/mini-wasm.c | Updates exported symbol name for DS exec callback. |
| src/mono/mono/eventpipe/ep-rt-mono.h | Updates DS job rescheduling callsite to new queue function name. |
| src/mono/browser/runtime/types/internal.ts | Updates runtime helper name for DS exec callback. |
| src/mono/browser/runtime/exports.ts | Exposes renamed DS exec callback in runtime exports. |
| src/mono/browser/runtime/diagnostics/common.ts | Calls renamed DS exec callback from mono browser diagnostics event loop. |
| src/mono/browser/runtime/cwraps.ts | Updates cwrap signature to match renamed DS exec callback export. |
| src/coreclr/vm/qcallentrypoints.cpp | Gates NativeRuntimeEventSource QCalls behind FEATURE_EVENT_TRACE while keeping EventPipe QCalls under FEATURE_PERFTRACING. |
| src/coreclr/vm/nativeeventsource.cpp | Adds non-ETW stubs when FEATURE_PERFTRACING is enabled but FEATURE_EVENT_TRACE is disabled. |
| src/coreclr/vm/gcenv.ee.cpp | Wraps ETW-only GC analysis events with FEATURE_EVENT_TRACE guards. |
| src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h | Adds browser single-threaded job queue integration via SystemJS_DiagnosticServerQueueJob; gates ETW-only provider init behind FEATURE_EVENT_TRACE. |
| src/coreclr/vm/eventing/eventpipe/CMakeLists.txt | Adds --noetwcallbacks option for EventPipe codegen when FEATURE_EVENT_TRACE is off. |
| src/coreclr/vm/eventing/CMakeLists.txt | Makes dependency on eventprovider conditional. |
| src/coreclr/scripts/genEventPipe.py | Adds --noetwcallbacks support to omit ETW callback wiring in generated provider code. |
| src/coreclr/nativeaot/Runtime/disabledruntimeeventinternal.cpp | Fixes a typo in a comment. |
| src/coreclr/clrfeatures.cmake | Enables FEATURE_PERFTRACING for browser targets; adjusts feature enablement logic. |
| src/coreclr/clrdefinitions.cmake | Ensures FEATURE_PERFTRACING defines and avoids creating dummy targets when perftracing is enabled. |
| src/coreclr/clr.featuredefines.props | Enables perf tracing for browser build configuration. |
This was referenced Mar 31, 2026
Open
089bc8e to
5a6b525
Compare
ad57e47 to
5480a5e
Compare
5480a5e to
49c1282
Compare
49c1282 to
b1cbc7b
Compare
This was referenced Apr 23, 2026
c64c45f to
4f71c7d
Compare
This was referenced May 6, 2026
This was referenced May 25, 2026
7dd94aa to
27c4d9a
Compare
3 tasks
This was referenced May 28, 2026
Member
Author
9e9a25b to
6b7dc62
Compare
This was referenced May 29, 2026
de598c6 to
31be2f2
Compare
pavelsavara
commented
Jun 3, 2026
| if (frame->shouldRecord) | ||
| { | ||
| SString methodName; | ||
| TypeString::AppendMethodInternal(methodName, frame->pMethod, TypeString::FormatNamespace); |
Member
Author
There was a problem hiding this comment.
I would appreciate advice about this for CoreCLR VM. This is possibly expensive call and possibly breaching VM contract, I don't know. Is there better way ?
| EventPipeStackContents stackContents; | ||
| EventPipeStackContents *pStackContents = ep_stack_contents_init(&stackContents); | ||
|
|
||
| if (ep_rt_coreclr_walk_managed_stack_for_thread(s_currentSamplingThread, pStackContents) |
Member
Author
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


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:
.nettraceCPU samples consumable bydotnet-trace/ the JScollectCpuSamplesAPI.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_WasmPerformanceInstrumentationMethodSet filter and are wired up through the existingWasmPerformanceInstrumentationMSBuild property (Mono-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 existingINTOP_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
WasmPerformanceInstrumentationMethodSet filter, and only onPERFTRACING_DISABLE_THREADS(single-threaded) builds.INTOP_PROF_ENTER/INTOP_PROF_LEAVEare additionally gated onTARGET_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:ep-rt-mono-runtime-provider.c).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
RELEASE_CONFIG_METHODSET(WasmPerformanceInstrumentation)in interpconfigvalues.h.jitStartupenables the profilers when the filter is non-empty, before any managed code is compiled.WasmPerformanceInstrumentationproperty (e.g.all,interval=0) into CoreCLR env vars (DOTNET_WasmPerformanceInstrumentation, sampling-rate var), withallmapped to the MethodSet wildcard*. Native build is forced on when the property is set.Tests
Wasm.Build.Tests.Blazor.EventPipeDiagnosticsTestsis added to BuildWasmAppsJobsListCoreCLR.txt so it runs for CoreCLR.monocategory so it runs on CoreCLR; split the AOT (Mono-only) case into its ownnative-mono[Fact]while the Debug/Release non-AOT cases run for both runtimes.collectCpuSamples/collectGcDump/collectMetricsfrom the DevTools console.