Conversation
Enable FEATURE_EVENT_TRACE/FEATURE_PERFTRACING for CoreCLR WASI using threadless EventPipe, matching browser CoreCLR, and turn FeaturePerfTracing back on in CoreLib. - Build the TCP flavor of the diagnostic server PAL (WASI has no AF_UNIX) and disable all listen/connect ports until a WASI transport is validated. - ep_rt_queue_job returns false instead of hitting EP_UNREACHABLE when the host has no job queue; ep_session_start_streaming drops the job's session reference in that case. Streaming sessions are flushed on disable. - Exclude the out-of-process EventPipeListener test harness on WASI, as on browser. Fixes EventSource activity-id tracking on WASI. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Azure Pipelines: Successfully started running 4 pipeline(s). 12 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara |
|
In browser there is JS setTimeout that is pumping the EP "loop". What is pumping it here ? |
Browser runs EventPipe jobs (session streaming, diagnostic server) from a JS setTimeout loop. WASI has no host event loop, so keep the jobs on a native list and drain it from managed WasiEventLoop via two QCalls, re-polling every 100ms with Task.Delay (which blocks in wasi:io/poll rather than spinning). Jobs only run while the event loop is pumped; otherwise streaming sessions still flush when they are disabled. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
@pavelsavara In the first commit, nothing pumped it on WASI. File and IPC streaming sessions just kept buffering up to 5f33b10 adds the WASI counterpart of the
Jobs only run while the event loop is pumped (async To verify, I ran the tracing test suite under wasmtime with Note This comment was generated with the help of GitHub Copilot. |
- Run queued WASI EventPipe jobs once from ep_rt_shutdown. A queued streaming job holds a session reference, and the event loop no longer runs after shutdown, so the session was never freed and its trace never got the end-of-stream tag. - Start the job pump before ThreadPoolWorkQueue.Dispatch, which can block in wasi:io/poll, and skip it in multithreaded builds where the pump is not compiled. - Restore EP_UNREACHABLE for single-threaded CoreCLR hosts other than browser and WASI. - On a streaming write failure, keep the job so the next tick releases the session reference instead of leaking it. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CoreCLR WASI was built with
FEATURE_EVENT_TRACE/FEATURE_PERFTRACINGoff, so anything that goes through EventPipe didn't work. Most visibly,EventSource.CurrentThreadActivityIdalways returnedGuid.Emptyon WASI. This enables EventPipe the same way browser CoreCLR does, using threadless EventPipe (FEATURE_PERFTRACING_DISABLE_THREADS).Changes
src/coreclr/CMakeLists.txtand theFeaturePerfTracing=falseoverride inclr.featuredefines.props, so the native runtime and CoreLib agree again.AF_UNIX(sockaddr_unhas nosun_path), so build the TCP flavor (FEATURE_PERFTRACING_PAL_TCP) and link it intodebug-pal. That link was disabled for WASI and tracked by [wasm][wasi] CoreCLR-WASI follow-up TODOs from #130051 (PERFTRACING, exit-code marker, getexepath synth) #130383. All listen and connect ports are disabled (DISABLE_PERFTRACING_LISTEN_PORTS/DEFAULT_LISTEN_PORT/CONNECT_PORTS, the same set Mono WASI uses). So EventPipe works in-process only, and out-of-process tools can't attach yet.setTimeoutloop. WASI has no host event loop, so:ep_rt_queue_jobputs jobs on a native list (eventpipeinternal.cpp).ThreadPoolWorkQueue.Dispatch(), which can block inwasi:io/poll,WasiEventLoopchecks for pending jobs throughEventPipeInternal_WasiHasPendingJobs. If there are any, it starts a managed pump (WasiEventPipeJobs.cs) that callsEventPipeInternal_WasiRunJobsand re-polls every 100 ms withTask.Delay. The pump stops once no jobs remain.Mainor waiting on tasks), as with timers and finalizers on WASI.ep_rt_shutdownruns the queued jobs once. The disabled streaming sessions then release their references, and freeing the session writes the trace's end-of-stream tag and closes the file.ep-session.c):ep_rt_queue_jobfails (on WASI, only on allocation failure),ep_session_start_streamingdrops the reference it took for the job.streaming_loop_tickkeeps the job, so the next tick releases the session reference instead of leaking it. This also changes browser's behavior on that path.EventPipeListenerharness on WASI, as on browser. It usesDiagnosticsClientIPC, which needsProcessand a diagnostic port.What happens when nothing drains
A session's buffer manager allocates buffers on demand up to its cap:
DOTNET_EventPipeCircularMB(default 1024 MB) for the startup file session, and 10 MB for in-processEventListenersessions. In the default Drop mode, events written past the cap are discarded; buffered data is never overwritten. Block mode needs a drain thread, so single-threaded builds reject it. In-processEventListenersessions were already drained by the managedTask.Delay(100)loop inEventPipeEventDispatcher.Wasm.cs. The pump above covers file and IPC streaming sessions. With a synchronousMain, the pump never runs; events buffer up to the cap and are written when the session is disabled at shutdown.Validation
Local WASI build on macOS arm64, Debug runtime, Release libraries, wasmtime 45:
./build.sh -s clr+libs -os wasi -arch wasm -c Debug -lc Release /p:TestAssemblies=false: passed./build.sh -s host+packs+tasks -os wasi -arch wasm -c Debug -lc Release /p:RuntimeFlavor=CoreCLR: passeddotnet build src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj /t:Test /p:TargetOS=wasi /p:TargetArchitecture=wasm /p:RuntimeFlavor=CoreCLR /p:Configuration=Release /p:RuntimeConfiguration=Debug /p:TasksConfiguration=Debug: 39 run, 37 passed, 0 failed, 2 skipped.ActivityTracking.StartStopCreatesActivity,ActivityFlowsAsync,SetCurrentActivityIdBeforeEventFlowsAsyncandSetCurrentActivityIdAfterEventDoesNotFlowAsyncnow pass.DOTNET_EnableEventPipe=1,DOTNET_EventPipeCircularMB=1, and verboseMicrosoft-Windows-DotNETRuntime+TplEventSourceproviders..nettracewas 5.2 MB, more than the 1 MB cap could hold without draining during the run.0x01), and so does a single-test run. Before the shutdown fix, traces ended with0x06.Not validated locally:
ep-session.cchanges.WasmEnableThreadsbuild. The pump is excluded there viaFEATURE_MULTITHREADING, the same condition as itsprojitemsinclude.Follow-ups (not in this PR)
wasi:socketsTCP. The job pump already handles its server loop once ports are enabled.ETW::GCLog::ForceGCdefers through the JS job queue on browser but runs synchronously on WASI. It's only reachable through the GCHeapCollect keyword.ds-portable-rid.cchecksTARGET_UNIXbeforeTARGET_WASI, so WASI reports aunix-wasmRID. It's only sent over diagnostic IPC, which is disabled here.Resolves #134963
Note
This PR description was generated with the help of GitHub Copilot.