From 3cd951fc832ecdef0ea0af13d3990eb3a0841fe0 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 28 Jan 2025 17:21:56 +0100 Subject: [PATCH 1/8] wip --- .../nativeaot/Runtime/eventpipe/ep-rt-aot.h | 20 + .../vm/eventing/eventpipe/ep-rt-coreclr.h | 20 + .../System.Private.CoreLib.csproj | 4 +- src/mono/browser/browser.proj | 4 + src/mono/browser/build/BrowserWasmApp.targets | 3 + src/mono/browser/build/WasmApp.InTree.props | 2 +- src/mono/browser/runtime/corebindings.c | 1 + src/mono/browser/runtime/cwraps.ts | 2 + .../browser/runtime/es6/dotnet.es6.lib.js | 2 + src/mono/browser/runtime/exports-binding.ts | 9 +- src/mono/browser/runtime/profiler.ts | 23 + src/mono/browser/runtime/rollup.config.js | 2 + src/mono/browser/runtime/types/internal.ts | 1 + src/mono/mono.proj | 8 +- .../eventpipe/ep-rt-mono-runtime-provider.c | 95 +++ src/mono/mono/eventpipe/ep-rt-mono.c | 1 + src/mono/mono/eventpipe/ep-rt-mono.h | 53 ++ src/mono/mono/mini/mini-wasm.c | 1 + src/mono/mono/utils/mono-threads-wasm.c | 38 +- src/mono/mono/utils/mono-threads-wasm.h | 2 +- src/mono/mono/utils/mono-threads.h | 2 + .../WorkloadManifest.targets.in | 1 - src/native/eventpipe/CMakeLists.txt | 13 +- src/native/eventpipe/ds-ipc-pal-websocket.c | 556 ++++++++++++++++++ src/native/eventpipe/ds-ipc-pal-websocket.h | 63 ++ src/native/eventpipe/ds-ipc.c | 9 +- src/native/eventpipe/ds-rt-config.h | 4 + src/native/eventpipe/ds-server.c | 114 ++-- src/native/eventpipe/ep-rt.h | 8 + src/native/eventpipe/ep-sample-profiler.c | 13 + src/native/eventpipe/ep-session.c | 39 +- src/native/eventpipe/ep-shared-config.h.in | 12 + src/native/libs/System.Native/pal_time.c | 2 +- 33 files changed, 1049 insertions(+), 78 deletions(-) create mode 100644 src/native/eventpipe/ds-ipc-pal-websocket.c create mode 100644 src/native/eventpipe/ds-ipc-pal-websocket.h diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h index 9c0a120531003a..ef2e6039dbe67f 100644 --- a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h +++ b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h @@ -512,6 +512,26 @@ ep_rt_sample_profiler_write_sampling_event_for_threads ( ep_rt_aot_sample_profiler_write_sampling_event_for_threads (sampling_thread, sampling_event); } +static +inline +void +ep_rt_sample_profiler_enabled (void) +{ + STATIC_CONTRACT_NOTHROW; + + // no-op +} + +static +inline +void +ep_rt_sample_profiler_disabled (void) +{ + STATIC_CONTRACT_NOTHROW; + + // no-op +} + static inline void diff --git a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h index b45e9770a1c4e9..762b6295bb7e2f 100644 --- a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h +++ b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h @@ -567,6 +567,26 @@ ep_rt_sample_profiler_write_sampling_event_for_threads ( ep_rt_coreclr_sample_profiler_write_sampling_event_for_threads (sampling_thread, sampling_event); } +static +inline +void +ep_rt_sample_profiler_enabled (void) +{ + STATIC_CONTRACT_NOTHROW; + + // no-op +} + +static +inline +void +ep_rt_sample_profiler_disabled (void) +{ + STATIC_CONTRACT_NOTHROW; + + // no-op +} + static inline void diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index 59edf88cf7e4f4..c444ac1488c2f3 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -114,7 +114,7 @@ true true true - true + true true @@ -135,7 +135,7 @@ - + diff --git a/src/mono/browser/browser.proj b/src/mono/browser/browser.proj index 95f56cea27e8cc..b9e72bdf650f36 100644 --- a/src/mono/browser/browser.proj +++ b/src/mono/browser/browser.proj @@ -424,6 +424,8 @@ <_CmakeEnvironmentVariable Include="ENABLE_JS_INTEROP_BY_VALUE=0" Condition="'$(WasmEnableJsInteropByValue)' == 'false'"/> <_CmakeEnvironmentVariable Include="WASM_ENABLE_SIMD=1" Condition="'$(WasmEnableSIMD)' != 'false'" /> <_CmakeEnvironmentVariable Include="WASM_ENABLE_SIMD=0" Condition="'$(WasmEnableSIMD)' == 'false'" /> + <_CmakeEnvironmentVariable Include="FEATURE_PERFTRACING=1" Condition="'$(FeaturePerfTracing)' != 'false'" /> + <_CmakeEnvironmentVariable Include="FEATURE_PERFTRACING=0" Condition="'$(FeaturePerfTracing)' == 'false'" /> <_CmakeEnvironmentVariable Include="WASM_ENABLE_EH=1" Condition="'$(WasmEnableExceptionHandling)' != 'false'" /> <_CmakeEnvironmentVariable Include="WASM_ENABLE_EH=0" Condition="'$(WasmEnableExceptionHandling)' == 'false'" /> <_CmakeEnvironmentVariable Include="RUN_AOT_COMPILATION=1" Condition="'$(RunAOTCompilation)' == 'true'" /> @@ -568,6 +570,8 @@ <_MonoRollupEnvironmentVariable Include="WasmEnableThreads:$(WasmEnableThreads)" /> <_MonoRollupEnvironmentVariable Include="WASM_ENABLE_SIMD:1" Condition="'$(WasmEnableSIMD)' != 'false'" /> <_MonoRollupEnvironmentVariable Include="WASM_ENABLE_SIMD:0" Condition="'$(WasmEnableSIMD)' == 'false'" /> + <_MonoRollupEnvironmentVariable Include="FEATURE_PERFTRACING:1" Condition="'$(FeaturePerfTracing)' != 'false'" /> + <_MonoRollupEnvironmentVariable Include="FEATURE_PERFTRACING:0" Condition="'$(FeaturePerfTracing)' == 'false'" /> <_MonoRollupEnvironmentVariable Include="WASM_ENABLE_EH:1" Condition="'$(WasmEnableExceptionHandling)' != 'false'" /> <_MonoRollupEnvironmentVariable Include="WASM_ENABLE_EH:0" Condition="'$(WasmEnableExceptionHandling)' == 'false'" /> <_MonoRollupEnvironmentVariable Include="ENABLE_JS_INTEROP_BY_VALUE:1" Condition="'$(WasmEnableJsInteropByValue)' == 'true'" /> diff --git a/src/mono/browser/build/BrowserWasmApp.targets b/src/mono/browser/build/BrowserWasmApp.targets index ac43cf31e1d11f..bc54470ba2df3d 100644 --- a/src/mono/browser/build/BrowserWasmApp.targets +++ b/src/mono/browser/build/BrowserWasmApp.targets @@ -3,6 +3,7 @@ true $(WasmEnableExceptionHandling) + true @@ -362,6 +363,8 @@ + + diff --git a/src/mono/browser/build/WasmApp.InTree.props b/src/mono/browser/build/WasmApp.InTree.props index b53cc29cbc9880..5833c9eff7cb0d 100644 --- a/src/mono/browser/build/WasmApp.InTree.props +++ b/src/mono/browser/build/WasmApp.InTree.props @@ -28,7 +28,7 @@ <_MonoRuntimeComponentDontLink Include="libmono-component-debugger-stub-static.a" /> - <_MonoRuntimeComponentDontLink Include="libmono-component-diagnostics_tracing-static.a"/> + <_MonoRuntimeComponentDontLink Include="libmono-component-diagnostics_tracing-stub-static.a" /> <_MonoRuntimeComponentDontLink Include="libmono-component-hot_reload-stub-static.a" /> <_MonoRuntimeComponentDontLink Include="libmono-component-marshal-ilgen-stub-static.a" /> diff --git a/src/mono/browser/runtime/corebindings.c b/src/mono/browser/runtime/corebindings.c index e64c5f6d2d81a9..29db5546f09948 100644 --- a/src/mono/browser/runtime/corebindings.c +++ b/src/mono/browser/runtime/corebindings.c @@ -32,6 +32,7 @@ extern void mono_wasm_invoke_js_function (int function_js_handle, void *args); extern int mono_runtime_run_module_cctor (MonoImage *image, MonoError *error); typedef void (*background_job_cb)(void); +typedef int (*ds_job_cb)(void* data); void mono_wasm_bind_assembly_exports (char *assembly_name); void mono_wasm_assembly_get_entry_point (char *assembly_name, int auto_insert_breakpoint, MonoMethod **method_out); diff --git a/src/mono/browser/runtime/cwraps.ts b/src/mono/browser/runtime/cwraps.ts index 19a24b08a11b13..b90143b89dad0d 100644 --- a/src/mono/browser/runtime/cwraps.ts +++ b/src/mono/browser/runtime/cwraps.ts @@ -42,6 +42,7 @@ const fn_signatures: SigLine[] = [ [true, "mono_wasm_parse_runtime_options", null, ["number", "number"]], [true, "mono_wasm_strdup", "number", ["string"]], [true, "mono_background_exec", null, []], + [true, "mono_wasm_ds_exec", null, []], [true, "mono_wasm_execute_timer", null, []], [true, "mono_wasm_load_icu_data", "number", ["number"]], [false, "mono_wasm_add_assembly", "number", ["string", "number", "number"]], @@ -166,6 +167,7 @@ export interface t_Cwraps { mono_wasm_strdup(value: string): number; mono_wasm_parse_runtime_options(length: number, argv: VoidPtr): void; mono_background_exec(): void; + mono_wasm_ds_exec(): void; mono_wasm_execute_timer(): void; mono_wasm_load_icu_data(offset: VoidPtr): number; mono_wasm_add_assembly(name: string, data: VoidPtr, size: number): number; diff --git a/src/mono/browser/runtime/es6/dotnet.es6.lib.js b/src/mono/browser/runtime/es6/dotnet.es6.lib.js index ad8b0303bbb12d..bf5ceabaf44afd 100644 --- a/src/mono/browser/runtime/es6/dotnet.es6.lib.js +++ b/src/mono/browser/runtime/es6/dotnet.es6.lib.js @@ -8,6 +8,7 @@ // because we can't pass custom define symbols to acorn optimizer, we use environment variables to pass other build options const WASM_ENABLE_SIMD = process.env.WASM_ENABLE_SIMD === "1"; +const FEATURE_PERFTRACING = process.env.FEATURE_PERFTRACING === "1"; const WASM_ENABLE_EH = process.env.WASM_ENABLE_EH === "1"; const ENABLE_BROWSER_PROFILER = process.env.ENABLE_BROWSER_PROFILER === "1"; const ENABLE_AOT_PROFILER = process.env.ENABLE_AOT_PROFILER === "1"; @@ -86,6 +87,7 @@ function injectDependencies() { DotnetSupportLib["$DOTNET__postset"] = `DOTNET.setup({ ` + `wasmEnableSIMD: ${WASM_ENABLE_SIMD ? "true" : "false"},` + `wasmEnableEH: ${WASM_ENABLE_EH ? "true" : "false"},` + + `enablePerfTracing: ${FEATURE_PERFTRACING ? "true" : "false"}, ` + `enableAotProfiler: ${ENABLE_AOT_PROFILER ? "true" : "false"}, ` + `enableBrowserProfiler: ${ENABLE_BROWSER_PROFILER ? "true" : "false"}, ` + `enableLogProfiler: ${ENABLE_LOG_PROFILER ? "true" : "false"}, ` + diff --git a/src/mono/browser/runtime/exports-binding.ts b/src/mono/browser/runtime/exports-binding.ts index 03879c4381de0f..8e819c48f93c7f 100644 --- a/src/mono/browser/runtime/exports-binding.ts +++ b/src/mono/browser/runtime/exports-binding.ts @@ -13,7 +13,7 @@ import { mono_wasm_resolve_or_reject_promise } from "./marshal-to-js"; import { mono_wasm_schedule_timer, schedule_background_exec } from "./scheduling"; import { mono_wasm_asm_loaded } from "./startup"; import { mono_log_warn, mono_wasm_console_clear, mono_wasm_trace_logger } from "./logging"; -import { mono_wasm_profiler_leave, mono_wasm_profiler_enter } from "./profiler"; +import { mono_wasm_profiler_leave, mono_wasm_profiler_enter, ds_rt_websocket_close, ds_rt_websocket_create, ds_rt_websocket_poll, ds_rt_websocket_recv, ds_rt_websocket_send } from "./profiler"; import { mono_wasm_browser_entropy } from "./crypto"; import { mono_wasm_cancel_promise } from "./cancelable-promise"; @@ -88,6 +88,13 @@ export const mono_wasm_imports = [ mono_wasm_invoke_jsimport_ST, mono_wasm_resolve_or_reject_promise, mono_wasm_cancel_promise, + + //event pipe + ds_rt_websocket_create, + ds_rt_websocket_send, + ds_rt_websocket_poll, + ds_rt_websocket_recv, + ds_rt_websocket_close, ]; diff --git a/src/mono/browser/runtime/profiler.ts b/src/mono/browser/runtime/profiler.ts index 0829b3ec71a66a..0b6c93af31e2ff 100644 --- a/src/mono/browser/runtime/profiler.ts +++ b/src/mono/browser/runtime/profiler.ts @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +import type { CharPtr, VoidPtr } from "./types/emscripten"; + import { ENVIRONMENT_IS_WEB, mono_assert, runtimeHelpers } from "./globals"; import { MonoMethod, AOTProfilerOptions, BrowserProfilerOptions, LogProfilerOptions } from "./types/internal"; import { profiler_c_functions as cwraps } from "./cwraps"; @@ -105,3 +107,24 @@ export function mono_wasm_profiler_leave (method: MonoMethod): void { globalThis.performance.measure(methodName, options); } } + +/* eslint-disable @typescript-eslint/no-unused-vars */ +export function ds_rt_websocket_create (urlPtr :CharPtr):number { + throw new Error("TODO"); +} + +export function ds_rt_websocket_send (client_socket :number, buffer:VoidPtr, bytes_to_write:number):number { + throw new Error("TODO"); +} + +export function ds_rt_websocket_poll (client_socket :number):number { + throw new Error("TODO"); +} + +export function ds_rt_websocket_recv (client_socket :number, buffer:VoidPtr, bytes_to_read:number):number { + throw new Error("TODO"); +} + +export function ds_rt_websocket_close (client_socket :number):number { + throw new Error("TODO"); +} diff --git a/src/mono/browser/runtime/rollup.config.js b/src/mono/browser/runtime/rollup.config.js index e50d79fd09a93c..c1e3874c052766 100644 --- a/src/mono/browser/runtime/rollup.config.js +++ b/src/mono/browser/runtime/rollup.config.js @@ -20,6 +20,7 @@ const nativeBinDir = process.env.NativeBinDir ? process.env.NativeBinDir.replace const wasmObjDir = process.env.WasmObjDir ? process.env.WasmObjDir.replace(/"/g, "") : "obj"; const wasmEnableThreads = process.env.WasmEnableThreads === "true" ? true : false; const wasmEnableSIMD = process.env.WASM_ENABLE_SIMD === "1" ? true : false; +const wasmEnablePerfTracing = process.env.FEATURE_PERFTRACING === "1" ? true : false; const wasmEnableExceptionHandling = process.env.WASM_ENABLE_EH === "1" ? true : false; const wasmEnableJsInteropByValue = process.env.ENABLE_JS_INTEROP_BY_VALUE == "1" ? true : false; // because of stack walk at src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs @@ -108,6 +109,7 @@ const envConstants = { configuration, wasmEnableThreads, wasmEnableSIMD, + wasmEnablePerfTracing, wasmEnableExceptionHandling, gitHash, wasmEnableJsInteropByValue, diff --git a/src/mono/browser/runtime/types/internal.ts b/src/mono/browser/runtime/types/internal.ts index 54f11256806273..2af269d1b226df 100644 --- a/src/mono/browser/runtime/types/internal.ts +++ b/src/mono/browser/runtime/types/internal.ts @@ -283,6 +283,7 @@ export type EmscriptenBuildOptions = { enableAotProfiler: boolean, enableBrowserProfiler: boolean, enableLogProfiler: boolean, + enablePerfTracing: boolean, runAOTCompilation: boolean, wasmEnableThreads: boolean, gitHash: string, diff --git a/src/mono/mono.proj b/src/mono/mono.proj index 5b133202f4076b..3b2b7fc88222ef 100644 --- a/src/mono/mono.proj +++ b/src/mono/mono.proj @@ -698,12 +698,18 @@ JS_ENGINES = [NODE_JS] <_MonoCMakeArgs Include="-DFEATURE_PERFTRACING_DISABLE_DEFAULT_LISTEN_PORT=1"/> - + <_MonoCMakeArgs Include="-DFEATURE_PERFTRACING_DISABLE_PERFTRACING_LISTEN_PORTS=1"/> <_MonoCMakeArgs Include="-DFEATURE_PERFTRACING_DISABLE_DEFAULT_LISTEN_PORT=1"/> <_MonoCMakeArgs Include="-DFEATURE_PERFTRACING_DISABLE_CONNECT_PORTS=1" /> + + <_MonoCMakeArgs Include="-DFEATURE_PERFTRACING_PAL_WS=1"/> + <_MonoCMakeArgs Include="-DFEATURE_PERFTRACING_DISABLE_PERFTRACING_LISTEN_PORTS=1"/> + <_MonoCMakeArgs Include="-DFEATURE_PERFTRACING_DISABLE_DEFAULT_LISTEN_PORT=1"/> + + <_MonoCMakeArgs Include="-DSTATIC_COMPONENTS=1" /> diff --git a/src/mono/mono/eventpipe/ep-rt-mono-runtime-provider.c b/src/mono/mono/eventpipe/ep-rt-mono-runtime-provider.c index 379b7bde8a1cae..05a762c6d362a4 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono-runtime-provider.c +++ b/src/mono/mono/eventpipe/ep-rt-mono-runtime-provider.c @@ -25,8 +25,14 @@ extern EVENTPIPE_TRACE_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_ #define NUM_NANOSECONDS_IN_1_MS 1000000 // Sample profiler. +#if defined(PERFTRACING_MULTI_THREADED) static GArray * _sampled_thread_callstacks = NULL; static uint32_t _max_sampled_thread_count = 32; +#else +MonoProfilerHandle _ep_rt_mono_sampling_profiler_provider; +static EventPipeEvent *current_sampling_event = NULL; +static ep_rt_thread_handle_t current_sampling_thread = NULL; +#endif // Mono profilers. extern MonoProfilerHandle _ep_rt_mono_default_profiler_provider; @@ -1207,6 +1213,7 @@ ep_rt_mono_walk_managed_stack_for_thread ( return true; } +#if defined(PERFTRACING_MULTI_THREADED) bool ep_rt_mono_sample_profiler_write_sampling_event_for_threads ( ep_rt_thread_handle_t sampling_thread, @@ -1306,6 +1313,94 @@ ep_rt_mono_sample_profiler_write_sampling_event_for_threads ( return true; } +#else // !PERFTRACING_MULTI_THREADED + +bool +ep_rt_mono_sample_profiler_write_sampling_event_for_threads ( + ep_rt_thread_handle_t sampling_thread, + EventPipeEvent *sampling_event) +{ + // here we just store the context for later + current_sampling_event = sampling_event; + current_sampling_thread = sampling_thread; + + return true; +} + +static void +method_enter (MonoProfiler *prof, MonoMethod *method, MonoProfilerCallContext *ctx) +{ + MonoThreadInfo *thread_info = mono_thread_info_current (); + SampleProfileStackWalkData stack_walk_data; + SampleProfileStackWalkData *data= &stack_walk_data; + THREAD_INFO_TYPE adapter = { { 0 } }; + + data->thread_id = ep_rt_thread_id_t_to_uint64_t (mono_thread_info_get_tid (thread_info)); + data->thread_ip = (uintptr_t)MONO_CONTEXT_GET_IP (&ctx->context); + data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR; + data->stack_walk_data.stack_contents = &data->stack_contents; + data->stack_walk_data.top_frame = true; + data->stack_walk_data.async_frame = false; + data->stack_walk_data.safe_point_frame = false; + data->stack_walk_data.runtime_invoke_frame = false; + ep_stack_contents_reset (&data->stack_contents); + + mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (sample_profiler_walk_managed_stack_for_thread_callback, &ctx->context, MONO_UNWIND_SIGNAL_SAFE, &stack_walk_data); + if (data->payload_data == EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL && (data->stack_walk_data.safe_point_frame || data->stack_walk_data.runtime_invoke_frame)) { + data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED; + } + if (data->stack_walk_data.top_frame && ep_stack_contents_get_length (&data->stack_contents) == 0) { + data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL; + } + + if ((data->stack_walk_data.top_frame && data->payload_data == EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL) || (data->payload_data != EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR && ep_stack_contents_get_length (&data->stack_contents) > 0)) { + if (data->stack_walk_data.async_frame) { + for (uint32_t frame_count = 0; frame_count < data->stack_contents.next_available_frame; ++frame_count) + mono_jit_info_table_find_internal ((gpointer)data->stack_contents.stack_frames [frame_count], TRUE, FALSE); + } + mono_thread_info_set_tid (&adapter, ep_rt_uint64_t_to_thread_id_t (data->thread_id)); + uint32_t payload_data = ep_rt_val_uint32_t (data->payload_data); + ep_write_sample_profile_event (current_sampling_thread, current_sampling_event, &adapter, &data->stack_contents, (uint8_t *)&payload_data, sizeof (payload_data)); + } +} + +static MonoProfilerCallInstrumentationFlags +method_filter (MonoProfiler *prof, MonoMethod *method) +{ + // TODO add more instrumentation, something like MINT_SDB_SEQ_POINT + return MONO_PROFILER_CALL_INSTRUMENTATION_ENTER; +} + +#endif // PERFTRACING_MULTI_THREADED + +void +ep_rt_mono_sampling_provider_component_init (void) +{ +#if defined(PERFTRACING_SINGLE_THREADED) + // in single-threaded mode, we install instrumentation callbacks on the mono profiler, instead of stop-the-world + _ep_rt_mono_sampling_profiler_provider = mono_profiler_create (NULL); + // this has negative performance impact even when the EP client is not connected! + // but it has to be enabled before managed code starts running, because the instrumentation needs to be in place + mono_profiler_set_call_instrumentation_filter_callback (_ep_rt_mono_sampling_profiler_provider, method_filter); +#endif +} + +void +ep_rt_mono_sample_profiler_enabled (void) +{ +#if defined(PERFTRACING_SINGLE_THREADED) + mono_profiler_set_method_enter_callback (_ep_rt_mono_sampling_profiler_provider, method_enter); +#endif +} + +void +ep_rt_mono_sample_profiler_disabled (void) +{ +#if defined(PERFTRACING_SINGLE_THREADED) + mono_profiler_set_method_enter_callback (_ep_rt_mono_sampling_profiler_provider, NULL); +#endif +} + void ep_rt_mono_execute_rundown (dn_vector_ptr_t *execution_checkpoints) { diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index f07f5c6d263411..75851bc0503214 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -789,6 +789,7 @@ ep_rt_mono_component_init (void) g_free (diag_env); ep_rt_mono_runtime_provider_component_init (); + ep_rt_mono_sampling_provider_component_init (); ep_rt_mono_profiler_provider_component_init (); } diff --git a/src/mono/mono/eventpipe/ep-rt-mono.h b/src/mono/mono/eventpipe/ep-rt-mono.h index 94ca5bb94f7e59..4baf1ff502443a 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.h +++ b/src/mono/mono/eventpipe/ep-rt-mono.h @@ -69,6 +69,8 @@ extern void ep_rt_mono_provider_config_init (EventPipeProviderConfiguration *pro extern void ep_rt_mono_init_providers_and_events (void); extern bool ep_rt_mono_providers_validate_all_disabled (void); extern bool ep_rt_mono_sample_profiler_write_sampling_event_for_threads (ep_rt_thread_handle_t sampling_thread, EventPipeEvent *sampling_event); +extern void ep_rt_mono_sample_profiler_enabled (void); +extern void ep_rt_mono_sample_profiler_disabled (void); extern void ep_rt_mono_execute_rundown (dn_vector_ptr_t *execution_checkpoints); extern int64_t ep_rt_mono_perf_counter_query (void); extern int64_t ep_rt_mono_perf_frequency_query (void); @@ -637,6 +639,22 @@ ep_rt_sample_profiler_write_sampling_event_for_threads (ep_rt_thread_handle_t sa ep_rt_mono_sample_profiler_write_sampling_event_for_threads (sampling_thread, sampling_event); } +static +inline +void +ep_rt_sample_profiler_enabled (void) +{ + ep_rt_mono_sample_profiler_enabled (); +} + +static +inline +void +ep_rt_sample_profiler_disabled (void) +{ + ep_rt_mono_sample_profiler_disabled (); +} + static void ep_rt_notify_profiler_provider_created (EventPipeProvider *provider) @@ -714,7 +732,11 @@ ep_rt_wait_event_wait ( { //TODO, replace with low level PAL implementation. EP_ASSERT (wait_event != NULL && wait_event->event != NULL); +#if defined(PERFTRACING_MULTI_THREADED) return (int32_t)mono_w32handle_wait_one (wait_event->event, timeout, alertable); +#else + return (int32_t)0; +#endif } static @@ -830,6 +852,7 @@ typedef struct _rt_mono_thread_params_internal_t { #undef EP_RT_DEFINE_THREAD_FUNC #define EP_RT_DEFINE_THREAD_FUNC(name) static mono_thread_start_return_t WINAPI name (gpointer data) +#if defined(PERFTRACING_MULTI_THREADED) EP_RT_DEFINE_THREAD_FUNC (ep_rt_thread_mono_start_func) { rt_mono_thread_params_internal_t *thread_params = (rt_mono_thread_params_internal_t *)data; @@ -845,6 +868,26 @@ EP_RT_DEFINE_THREAD_FUNC (ep_rt_thread_mono_start_func) return result; } +#else // PERFTRACING_MULTI_THREADED +// in single-threaded OS like browser, this is not wrapper for long running method +// it's rather self sustaining callback, called from browser event loop +EP_RT_DEFINE_THREAD_FUNC (ep_rt_thread_mono_start_func) +{ + rt_mono_thread_params_internal_t *thread_params = (rt_mono_thread_params_internal_t *)data; + + mono_thread_start_return_t result = thread_params->thread_params.thread_func (thread_params); + + if (result == 0) { + // self schedule again + mono_main_thread_schedule_ds_job ((ds_job_cb)ep_rt_thread_mono_start_func, (void*)thread_params); + } + else { + g_free (thread_params); + } + + return result; +} +#endif // PERFTRACING_MULTI_THREADED static inline @@ -861,7 +904,13 @@ ep_rt_thread_create ( thread_params->thread_params.thread_func = (ep_rt_thread_start_func)thread_func; thread_params->thread_params.thread_params = params; thread_params->background_thread = true; +#if defined(PERFTRACING_MULTI_THREADED) return (mono_thread_platform_create_thread (ep_rt_thread_mono_start_func, thread_params, NULL, (ep_rt_thread_id_t *)id) == TRUE) ? true : false; +#else + // in single-threaded, it will run the callback inline and re-schedule itself if necessary + ep_rt_thread_mono_start_func (thread_params); + return true; +#endif } return false; @@ -880,6 +929,7 @@ inline void ep_rt_thread_sleep (uint64_t ns) { +#if defined(PERFTRACING_MULTI_THREADED) MONO_REQ_GC_UNSAFE_MODE; if (ns == 0) { mono_thread_info_yield (); @@ -888,6 +938,7 @@ ep_rt_thread_sleep (uint64_t ns) g_usleep ((gulong)(ns / 1000)); MONO_EXIT_GC_SAFE; } +#endif } static @@ -1970,6 +2021,8 @@ extern void ep_rt_mono_runtime_provider_fini (void); extern void ep_rt_mono_runtime_provider_thread_started_callback (MonoProfiler *prof, uintptr_t tid); extern void ep_rt_mono_runtime_provider_thread_stopped_callback (MonoProfiler *prof, uintptr_t tid); +extern void ep_rt_mono_sampling_provider_component_init (void); + extern void ep_rt_mono_profiler_provider_component_init (void); extern void ep_rt_mono_profiler_provider_init (void); extern void ep_rt_mono_profiler_provider_fini (void); diff --git a/src/mono/mono/mini/mini-wasm.c b/src/mono/mono/mini/mini-wasm.c index 4a9eb21b137adb..c9d5521a8b6708 100644 --- a/src/mono/mono/mini/mini-wasm.c +++ b/src/mono/mono/mini/mini-wasm.c @@ -453,6 +453,7 @@ G_BEGIN_DECLS #ifdef DISABLE_THREADS EMSCRIPTEN_KEEPALIVE void mono_wasm_execute_timer (void); EMSCRIPTEN_KEEPALIVE void mono_background_exec (void); +EMSCRIPTEN_KEEPALIVE void mono_wasm_ds_exec (void); extern void mono_wasm_schedule_timer (int shortestDueTimeMs); #else extern void mono_target_thread_schedule_synchronization_context(MonoNativeThreadId target_thread); diff --git a/src/mono/mono/utils/mono-threads-wasm.c b/src/mono/mono/utils/mono-threads-wasm.c index c1e6d9144e7b30..b0c01df8498f7e 100644 --- a/src/mono/mono/utils/mono-threads-wasm.c +++ b/src/mono/mono/utils/mono-threads-wasm.c @@ -322,6 +322,9 @@ extern void schedule_background_exec (void); // when this is called from sgen it would be wrapper of sgen_perform_collection_inner // when this is called from gc, it would be mono_runtime_do_background_work #ifdef DISABLE_THREADS +GSList *jobs; +GSList *jobs_ds; + void mono_main_thread_schedule_background_job (background_job_cb cb) { @@ -335,7 +338,20 @@ mono_main_thread_schedule_background_job (background_job_cb cb) jobs = g_slist_prepend (jobs, (gpointer)cb); } -GSList *jobs; +typedef struct { + ds_job_cb cb; + void* data; +} DsJobRegistration; + +void +mono_main_thread_schedule_ds_job (ds_job_cb cb, void* data) +{ + g_assert (cb); + DsJobRegistration* reg = g_new0 (DsJobRegistration, 1); + reg->cb = cb; + reg->data = data; + jobs_ds = g_slist_prepend (jobs_ds, (gpointer)reg); +} G_EXTERN_C EMSCRIPTEN_KEEPALIVE void @@ -356,6 +372,26 @@ mono_background_exec (void) MONO_EXIT_GC_UNSAFE; } +G_EXTERN_C +EMSCRIPTEN_KEEPALIVE void +mono_wasm_ds_exec (void) +{ + MONO_ENTER_GC_UNSAFE; + GSList *j1 = jobs_ds, *cur1; + jobs_ds = NULL; + + for (cur1 = j1; cur1; cur1 = cur1->next) { + DsJobRegistration* reg = (DsJobRegistration*)cur1->data; + g_assert (reg->cb); + THREADS_DEBUG ("mono_wasm_ds_exec running job %p \n", (gpointer)cb); + reg->cb (reg->data); + THREADS_DEBUG ("mono_wasm_ds_exec done job %p \n", (gpointer)cb); + g_free (reg); + } + g_slist_free (j1); + MONO_EXIT_GC_UNSAFE; +} + #else /*DISABLE_THREADS*/ extern void mono_wasm_schedule_synchronization_context (); diff --git a/src/mono/mono/utils/mono-threads-wasm.h b/src/mono/mono/utils/mono-threads-wasm.h index 927c5b0eb0ea54..64fbd11a20ba5f 100644 --- a/src/mono/mono/utils/mono-threads-wasm.h +++ b/src/mono/mono/utils/mono-threads-wasm.h @@ -88,8 +88,8 @@ mono_wasm_atomic_wait_i32 (volatile int32_t *addr, int32_t expected, int32_t tim } #else /* DISABLE_THREADS */ -extern GSList *jobs; void mono_background_exec (void); +void mono_wasm_ds_exec (void); #endif /* DISABLE_THREADS */ void diff --git a/src/mono/mono/utils/mono-threads.h b/src/mono/mono/utils/mono-threads.h index 8410e43ef9301a..1a8886ff333e3f 100644 --- a/src/mono/mono/utils/mono-threads.h +++ b/src/mono/mono/utils/mono-threads.h @@ -845,8 +845,10 @@ void mono_threads_join_unlock (void); #ifdef HOST_WASM typedef void (*background_job_cb)(void); +typedef int (*ds_job_cb)(void* data); #ifdef DISABLE_THREADS void mono_main_thread_schedule_background_job (background_job_cb cb); +void mono_main_thread_schedule_ds_job (ds_job_cb cb, void* data); #else void mono_target_thread_schedule_synchronization_context(MonoNativeThreadId target_thread); #endif // DISABLE_THREADS diff --git a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.net7.Manifest/WorkloadManifest.targets.in b/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.net7.Manifest/WorkloadManifest.targets.in index 39288d158b1181..3d9c3b75d162c8 100644 --- a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.net7.Manifest/WorkloadManifest.targets.in +++ b/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.net7.Manifest/WorkloadManifest.targets.in @@ -67,7 +67,6 @@ $(_MonoWorkloadRuntimePackPackageVersion) Microsoft.NETCore.App.Runtime.Mono.multithread.**RID** - Microsoft.NETCore.App.Runtime.Mono.perftrace.**RID** diff --git a/src/native/eventpipe/CMakeLists.txt b/src/native/eventpipe/CMakeLists.txt index 311293ca5f45cc..867f76f7795f42 100644 --- a/src/native/eventpipe/CMakeLists.txt +++ b/src/native/eventpipe/CMakeLists.txt @@ -17,6 +17,13 @@ if (CLR_CMAKE_HOST_IOS OR CLR_CMAKE_HOST_TVOS OR CLR_CMAKE_HOST_ANDROID) set(FEATURE_PERFTRACING_DISABLE_DEFAULT_LISTEN_PORT 1) endif() +# Use WebSocket for EventPipe on mobile browser +if (CLR_CMAKE_HOST_BROWSER) + set(FEATURE_PERFTRACING_PAL_WS 1) + set(FEATURE_PERFTRACING_SINGLE_THREADED 1) + set(FEATURE_PERFTRACING_DISABLE_DEFAULT_LISTEN_PORT 1) +endif() + configure_file(${CLR_SRC_NATIVE_DIR}/eventpipe/ep-shared-config.h.in ${CMAKE_CURRENT_BINARY_DIR}/ep-shared-config.h) # Define the DiagnosticsServer and EventPipe as interface libraries. @@ -44,7 +51,11 @@ add_library(dn-diagnosticserver-pal INTERFACE) target_include_directories(dn-diagnosticserver-pal INTERFACE ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries(dn-diagnosticserver-pal INTERFACE dn-containers) -if (FEATURE_PERFTRACING_PAL_TCP) +if (FEATURE_PERFTRACING_PAL_WS) + target_sources(dn-diagnosticserver-pal INTERFACE + ds-ipc-pal-websocket.c + ) +elseif (FEATURE_PERFTRACING_PAL_TCP) target_sources(dn-diagnosticserver-pal INTERFACE ds-ipc-pal-socket.c ) diff --git a/src/native/eventpipe/ds-ipc-pal-websocket.c b/src/native/eventpipe/ds-ipc-pal-websocket.c new file mode 100644 index 00000000000000..0fe5c7d61aa2b7 --- /dev/null +++ b/src/native/eventpipe/ds-ipc-pal-websocket.c @@ -0,0 +1,556 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifdef FEATURE_PERFTRACING_STANDALONE_PAL +#define EP_NO_RT_DEPENDENCY +#endif + +#include "ds-rt-config.h" + +#ifdef ENABLE_PERFTRACING + +#define DS_IMPL_IPC_PAL_SOCKET_GETTER_SETTER +#include "ds-ipc-pal-websocket.h" + +#define DS_IPC_INVALID_SOCKET -1 + +#ifndef EP_NO_RT_DEPENDENCY +#include "ds-rt.h" +#else +#ifdef FEATURE_CORECLR +#include +#include "processdescriptor.h" +#endif + +#ifndef ep_return_null_if_nok +#define ep_return_null_if_nok(expr) do { if (!(expr)) return NULL; } while (0) +#endif + +#ifndef ep_raise_error_if_nok +#define ep_raise_error_if_nok(expr) do { if (!(expr)) goto ep_on_error; } while (0) +#endif + +#ifndef ep_raise_error +#define ep_raise_error() do { goto ep_on_error; } while (0) +#endif + +#ifndef ep_exit_error_handler +#define ep_exit_error_handler() do { goto ep_on_exit; } while (0) +#endif + +#ifndef EP_ASSERT +#define EP_ASSERT assert +#endif + +#ifndef DS_ENTER_BLOCKING_PAL_SECTION +#define DS_ENTER_BLOCKING_PAL_SECTION +#endif + +#ifndef DS_EXIT_BLOCKING_PAL_SECTION +#define DS_EXIT_BLOCKING_PAL_SECTION +#endif + +#undef ep_rt_object_alloc +#define ep_rt_object_alloc(obj_type) ((obj_type *)calloc(1, sizeof(obj_type))) + +static +inline +void +ep_rt_object_free (void *ptr) +{ + if (ptr) + free (ptr); +} + +#undef ep_rt_object_array_alloc +#define ep_rt_object_array_alloc(obj_type,size) ((obj_type *)calloc (size, sizeof(obj_type))) + +static +inline +void +ep_rt_object_array_free (void *ptr) +{ + if (ptr) + free (ptr); +} +#endif + +static bool _ipc_pal_socket_init = false; + +/* + * Forward declares of all static functions. + */ + +static +bool +ipc_socket_recv ( + ds_ipc_websocket_t s, + uint8_t * buffer, + ssize_t bytes_to_read, + ssize_t *bytes_read); + +static +bool +ipc_socket_send ( + ds_ipc_websocket_t s, + const uint8_t *buffer, + ssize_t bytes_to_write, + ssize_t *bytes_written); + +static +bool +ipc_transport_get_default_name ( + ep_char8_t *name, + int32_t name_len); + +static +bool +ipc_init_listener ( + DiagnosticsIpc *ipc, + ds_ipc_error_callback_func callback); + +static +DiagnosticsIpc * +ipc_alloc_ws_address ( + DiagnosticsIpc *ipc, + DiagnosticsIpcConnectionMode mode, + const ep_char8_t *ipc_name); + +static +void +ipc_stream_free_func (void *object); + +static +bool +ipc_stream_read_func ( + void *object, + uint8_t *buffer, + uint32_t bytes_to_read, + uint32_t *bytes_read, + uint32_t timeout_ms); + +static +bool +ipc_stream_write_func ( + void *object, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written, + uint32_t timeout_ms); + +static +bool +ipc_stream_flush_func (void *object); + +static +bool +ipc_stream_close_func (void *object); + +static +DiagnosticsIpcStream * +ipc_stream_alloc ( + int client_socket); +/* + * Implementation + */ + + +static +DiagnosticsIpc * +ipc_alloc_ws_address ( + DiagnosticsIpc *ipc, + DiagnosticsIpcConnectionMode mode, + const ep_char8_t *ipc_name) +{ + EP_ASSERT (ipc != NULL); + ep_return_null_if_nok (ipc_name != NULL); + + ipc->server_url = ep_rt_utf8_string_dup (ipc_name); + + ep_raise_error_if_nok (ipc->server_url != NULL); + +ep_on_exit: + return ipc; + +ep_on_error: + ipc = NULL; + ep_exit_error_handler (); +} + + +/* + * DiagnosticsIpc Socket PAL. + */ + +bool +ds_ipc_pal_init (void) +{ + return true; +} + +bool +ds_ipc_pal_shutdown (void) +{ + return true; +} + +DiagnosticsIpc * +ds_ipc_alloc ( + const ep_char8_t *ipc_name, + DiagnosticsIpcConnectionMode mode, + ds_ipc_error_callback_func callback) +{ + DiagnosticsIpc *instance = NULL; + + instance = ep_rt_object_alloc (DiagnosticsIpc); + ep_raise_error_if_nok (instance != NULL); + + instance->server_socket = DS_IPC_INVALID_SOCKET; + instance->is_closed = false; + + ep_raise_error_if_nok (ipc_alloc_ws_address (instance, mode, ipc_name) != NULL); + +ep_on_exit: + return instance; + +ep_on_error: + ds_ipc_free (instance); + instance = NULL; + ep_exit_error_handler (); +} + +void +ds_ipc_free (DiagnosticsIpc *ipc) +{ + if (!ipc) + return; + + ds_ipc_close (ipc, false, NULL); + + ep_rt_object_free (ipc); +} + +void +ds_ipc_reset (DiagnosticsIpc *ipc) +{ +} + +int32_t +ds_ipc_poll ( + DiagnosticsIpcPollHandle *poll_handles_data, + size_t poll_handles_data_len, + uint32_t timeout_ms, + ds_ipc_error_callback_func callback) +{ + for (uint32_t i = 0; i < poll_handles_data_len; ++i) { + // CLIENT + EP_ASSERT (poll_handles_data [i].stream != NULL); + int client_socket = poll_handles_data [i].stream->client_socket; + int pending = ds_rt_websocket_poll (client_socket); + if (pending < 0){ + poll_handles_data [i].events = (uint8_t)DS_IPC_POLL_EVENTS_ERR; + return 1; + } + if (pending > 0){ + poll_handles_data [i].events = (uint8_t)DS_IPC_POLL_EVENTS_SIGNALED; + return 1; + } + } + + return 0; +} + +bool +ds_ipc_listen ( + DiagnosticsIpc *ipc, + ds_ipc_error_callback_func callback) +{ + // NOT SUPPORTED + return false; +} + +DiagnosticsIpcStream * +ds_ipc_accept ( + DiagnosticsIpc *ipc, + ds_ipc_error_callback_func callback) +{ + // NOT SUPPORTED + return NULL; +} + +DiagnosticsIpcStream * +ds_ipc_connect ( + DiagnosticsIpc *ipc, + uint32_t timeout_ms, + ds_ipc_error_callback_func callback, + bool *timed_out) +{ + EP_ASSERT (ipc != NULL); + EP_ASSERT (timed_out != NULL); + + + DiagnosticsIpcStream *stream = NULL; + + bool success = false; + *timed_out = false; + int client_socket = ds_rt_websocket_create (ipc->server_url); + + success = client_socket > 0; + ep_raise_error_if_nok (success == true); + + stream = ipc_stream_alloc ((ds_ipc_websocket_t)client_socket); + +ep_on_exit: + return stream; + +ep_on_error: + ds_ipc_stream_free (stream); + stream = NULL; + + ep_exit_error_handler (); +} + +void +ds_ipc_close ( + DiagnosticsIpc *ipc, + bool is_shutdown, + ds_ipc_error_callback_func callback) +{ + EP_ASSERT (ipc != NULL); + if (ipc->is_closed) + return; + + ipc->is_closed = true; +} + +int32_t +ds_ipc_to_string ( + DiagnosticsIpc *ipc, + ep_char8_t *buffer, + uint32_t buffer_len) +{ + EP_ASSERT (ipc != NULL); + EP_ASSERT (buffer != NULL); + EP_ASSERT (buffer_len <= DS_IPC_MAX_TO_STRING_LEN); + + int32_t result = snprintf (buffer, buffer_len, "{ server_socket = %d }", (int32_t)(size_t)ipc->server_socket); + return (result > 0 && result < (int32_t)buffer_len) ? result : 0; +} + +/* + * DiagnosticsIpcStream. + */ + +static +void +ipc_stream_free_func (void *object) +{ + EP_ASSERT (object != NULL); + DiagnosticsIpcStream *ipc_stream = (DiagnosticsIpcStream *)object; + ds_ipc_stream_free (ipc_stream); +} + +static +bool +ipc_stream_read_func ( + void *object, + uint8_t *buffer, + uint32_t bytes_to_read, + uint32_t *bytes_read, + uint32_t timeout_ms) +{ + EP_ASSERT (object != NULL); + EP_ASSERT (buffer != NULL); + EP_ASSERT (bytes_read != NULL); + + bool success = false; + DiagnosticsIpcStream *ipc_stream = (DiagnosticsIpcStream *)object; + int total_bytes_read = ds_rt_websocket_recv (ipc_stream->client_socket, buffer, bytes_to_read); + + success = total_bytes_read >= 0; + ep_raise_error_if_nok (success == true); + +ep_on_exit: + *bytes_read = (uint32_t)total_bytes_read; + return success; + +ep_on_error: + total_bytes_read = 0; + success = false; + ep_exit_error_handler (); +} + +static +bool +ipc_stream_write_func ( + void *object, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written, + uint32_t timeout_ms) +{ + EP_ASSERT (object != NULL); + EP_ASSERT (buffer != NULL); + EP_ASSERT (bytes_written != NULL); + + bool success = false; + DiagnosticsIpcStream *ipc_stream = (DiagnosticsIpcStream *)object; + + int total_bytes_written = ds_rt_websocket_send (ipc_stream->client_socket, buffer, bytes_to_write); + success = total_bytes_written >= 0; + + ep_raise_error_if_nok (success == true); + +ep_on_exit: + *bytes_written = (uint32_t)total_bytes_written; + return success; + +ep_on_error: + total_bytes_written = 0; + success = false; + ep_exit_error_handler (); +} + +static +bool +ipc_stream_flush_func (void *object) +{ + return true; +} + +static +bool +ipc_stream_close_func (void *object) +{ + EP_ASSERT (object != NULL); + DiagnosticsIpcStream *ipc_stream = (DiagnosticsIpcStream *)object; + return ds_ipc_stream_close (ipc_stream, NULL); +} + +static IpcStreamVtable ipc_stream_vtable = { + ipc_stream_free_func, + ipc_stream_read_func, + ipc_stream_write_func, + ipc_stream_flush_func, + ipc_stream_close_func }; + +static +DiagnosticsIpcStream * +ipc_stream_alloc ( + int client_socket) +{ + DiagnosticsIpcStream *instance = ep_rt_object_alloc (DiagnosticsIpcStream); + ep_raise_error_if_nok (instance != NULL); + + instance->stream.vtable = &ipc_stream_vtable; + instance->client_socket = client_socket; + +ep_on_exit: + return instance; + +ep_on_error: + ds_ipc_stream_free (instance); + instance = NULL; + ep_exit_error_handler (); +} + +IpcStream * +ds_ipc_stream_get_stream_ref (DiagnosticsIpcStream *ipc_stream) +{ + return &ipc_stream->stream; +} + +int32_t +ds_ipc_stream_get_handle_int32_t (DiagnosticsIpcStream *ipc_stream) +{ + return (int32_t)ipc_stream->client_socket; +} + +void +ds_ipc_stream_free (DiagnosticsIpcStream *ipc_stream) +{ + if(!ipc_stream) + return; + + ds_ipc_stream_close (ipc_stream, NULL); + ep_rt_object_free (ipc_stream); +} + +bool +ds_ipc_stream_read ( + DiagnosticsIpcStream *ipc_stream, + uint8_t *buffer, + uint32_t bytes_to_read, + uint32_t *bytes_read, + uint32_t timeout_ms) +{ + return ipc_stream_read_func ( + ipc_stream, + buffer, + bytes_to_read, + bytes_read, + timeout_ms); +} + +bool +ds_ipc_stream_write ( + DiagnosticsIpcStream *ipc_stream, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written, + uint32_t timeout_ms) +{ + return ipc_stream_write_func ( + ipc_stream, + buffer, + bytes_to_write, + bytes_written, + timeout_ms); +} + +bool +ds_ipc_stream_flush (DiagnosticsIpcStream *ipc_stream) +{ + return ipc_stream_flush_func (ipc_stream); +} + +bool +ds_ipc_stream_close ( + DiagnosticsIpcStream *ipc_stream, + ds_ipc_error_callback_func callback) +{ + EP_ASSERT (ipc_stream != NULL); + + if (ipc_stream->client_socket != DS_IPC_INVALID_SOCKET) { + ds_ipc_stream_flush (ipc_stream); + + int res = ds_rt_websocket_close (ipc_stream->client_socket); + + ipc_stream->client_socket = DS_IPC_INVALID_SOCKET; + + return res == 0; + } + + return true; +} + +int32_t +ds_ipc_stream_to_string ( + DiagnosticsIpcStream *ipc_stream, + ep_char8_t *buffer, + uint32_t buffer_len) +{ + EP_ASSERT (ipc_stream != NULL); + EP_ASSERT (buffer != NULL); + EP_ASSERT (buffer_len <= DS_IPC_MAX_TO_STRING_LEN); + + int32_t result = snprintf (buffer, buffer_len, "{ client_socket = %d }", (int32_t)(size_t)ipc_stream->client_socket); + return (result > 0 && result < (int32_t)buffer_len) ? result : 0; +} + +#endif /* ENABLE_PERFTRACING */ + +#ifndef DS_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_diagnostics_ipc_pal_socket; +const char quiet_linker_empty_file_warning_diagnostics_ipc_pal_socket = 0; +#endif diff --git a/src/native/eventpipe/ds-ipc-pal-websocket.h b/src/native/eventpipe/ds-ipc-pal-websocket.h new file mode 100644 index 00000000000000..1273d9367c9d41 --- /dev/null +++ b/src/native/eventpipe/ds-ipc-pal-websocket.h @@ -0,0 +1,63 @@ +#ifndef __DIAGNOSTICS_IPC_PAL_WEB_SOCKET_H__ +#define __DIAGNOSTICS_IPC_PAL_WEB_SOCKET_H__ + +#include "ds-rt-config.h" + +#ifdef ENABLE_PERFTRACING +#include "ds-ipc-pal.h" + +#undef DS_IMPL_GETTER_SETTER +#ifdef DS_IMPL_IPC_PAL_SOCKET_GETTER_SETTER +#define DS_IMPL_GETTER_SETTER +#endif +#include "ds-getter-setter.h" + +typedef int ds_ipc_websocket_t; + +/* + * DiagnosticsIpc. + */ + +#if defined(DS_INLINE_GETTER_SETTER) || defined(DS_IMPL_IPC_PAL_SOCKET_GETTER_SETTER) +struct _DiagnosticsIpc { +#else +struct _DiagnosticsIpc_Internal { +#endif + ep_char8_t *server_url; + ds_ipc_websocket_t server_socket; + bool is_closed; +}; + +#if !defined(DS_INLINE_GETTER_SETTER) && !defined(DS_IMPL_IPC_PAL_SOCKET_GETTER_SETTER) +struct _DiagnosticsIpc { + uint8_t _internal [sizeof (struct _DiagnosticsIpc_Internal)]; +}; +#endif + +/* + * DiagnosticsIpcStream. + */ + +#if defined(DS_INLINE_GETTER_SETTER) || defined(DS_IMPL_IPC_PAL_SOCKET_GETTER_SETTER) +struct _DiagnosticsIpcStream { +#else +struct _DiagnosticsIpcStream_Internal { +#endif + IpcStream stream; + ds_ipc_websocket_t client_socket; +}; + +#if !defined(DS_INLINE_GETTER_SETTER) && !defined(DS_IMPL_IPC_PAL_SOCKET_GETTER_SETTER) +struct _DiagnosticsIpcStream { + uint8_t _internal [sizeof (struct _DiagnosticsIpcStream_Internal)]; +}; +#endif + +extern int ds_rt_websocket_poll (int client_socket); +extern int ds_rt_websocket_create (const char* url); +extern int ds_rt_websocket_recv (int client_socket, const uint8_t* buffer, uint32_t bytes_to_read); +extern int ds_rt_websocket_send (int client_socket, const uint8_t* buffer, uint32_t bytes_to_write); +extern int ds_rt_websocket_close(int client_socket); + +#endif /* ENABLE_PERFTRACING */ +#endif /* __DIAGNOSTICS_IPC_PAL_WEB_SOCKET_H__ */ diff --git a/src/native/eventpipe/ds-ipc.c b/src/native/eventpipe/ds-ipc.c index 7d3c56ee28d452..f172f6b9b96788 100644 --- a/src/native/eventpipe/ds-ipc.c +++ b/src/native/eventpipe/ds-ipc.c @@ -371,7 +371,7 @@ ds_ipc_stream_factory_get_next_available_stream (ds_ipc_error_callback_func call dn_vector_t ipc_poll_handles; ep_raise_error_if_nok (dn_vector_custom_init_t (&ipc_poll_handles, ¶ms, DiagnosticsIpcPollHandle)); - while (!stream) { + do { connect_success = true; DN_VECTOR_PTR_FOREACH_BEGIN (DiagnosticsPort *, port, _ds_port_array) { DiagnosticsIpcPollHandle ipc_poll_handle; @@ -455,6 +455,13 @@ ds_ipc_stream_factory_get_next_available_stream (ds_ipc_error_callback_func call // clear the view. dn_vector_clear (&ipc_poll_handles); } +#if defined(PERFTRACING_MULTI_THREADED) + while (!stream); +#else + // in single-threaded mode, we only do one poll + // we can't loop here, that would block the browser event loop + while (false); +#endif ep_on_exit: DS_LOG_DEBUG_2 ("ds_ipc_stream_factory_get_next_available_stream - EXIT :: Poll attempt: %d, stream using handle %d.", poll_attempts, stream ? ds_ipc_stream_get_handle_int32_t (stream) : -1); diff --git a/src/native/eventpipe/ds-rt-config.h b/src/native/eventpipe/ds-rt-config.h index 89237313362fb8..f3feaa4211275d 100644 --- a/src/native/eventpipe/ds-rt-config.h +++ b/src/native/eventpipe/ds-rt-config.h @@ -11,6 +11,9 @@ #define DS_INCLUDE_SOURCE_FILES #endif +#ifdef ENABLE_PERFTRACING_PAL_WS +#define DS_IPC_PAL_WS +#else #ifdef ENABLE_PERFTRACING_PAL_TCP #define DS_IPC_PAL_TCP #else @@ -20,6 +23,7 @@ #define DS_IPC_PAL_NAMEDPIPES #endif #endif +#endif #ifdef DISABLE_PERFTRACING_CONNECT_PORTS #define DS_IPC_DISABLE_CONNECT_PORTS diff --git a/src/native/eventpipe/ds-server.c b/src/native/eventpipe/ds-server.c index b3cf9f3b27e032..0865180a174ecd 100644 --- a/src/native/eventpipe/ds-server.c +++ b/src/native/eventpipe/ds-server.c @@ -112,6 +112,61 @@ server_warning_callback ( DS_LOG_WARNING_2 ("warning (%d): %s.", code, message); } +static size_t server_loop_tick () { + if (server_volatile_load_shutting_down_state ()) + return 1; // done + DiagnosticsIpcStream *stream = ds_ipc_stream_factory_get_next_available_stream (server_warning_callback); + if (!stream) + return 0; // continue + + ds_rt_auto_trace_signal (); + + DiagnosticsIpcMessage message; + if (!ds_ipc_message_init (&message)) + return 0; // continue + + if (!ds_ipc_message_initialize_stream (&message, stream)) { + ds_ipc_message_send_error (stream, DS_IPC_E_BAD_ENCODING); + ds_ipc_stream_free (stream); + ds_ipc_message_fini (&message); + return 0; // continue + } + + if (ep_rt_utf8_string_compare ( + (const ep_char8_t *)ds_ipc_header_get_magic_ref (ds_ipc_message_get_header_ref (&message)), + (const ep_char8_t *)DOTNET_IPC_V1_MAGIC) != 0) { + + ds_ipc_message_send_error (stream, DS_IPC_E_UNKNOWN_MAGIC); + ds_ipc_stream_free (stream); + ds_ipc_message_fini (&message); + return 0; // continue + } + + DS_LOG_INFO_2 ("DiagnosticServer - received IPC message with command set (%d) and command id (%d)", ds_ipc_header_get_commandset (ds_ipc_message_get_header_ref (&message)), ds_ipc_header_get_commandid (ds_ipc_message_get_header_ref (&message))); + + switch ((DiagnosticsServerCommandSet)ds_ipc_header_get_commandset (ds_ipc_message_get_header_ref (&message))) { + case DS_SERVER_COMMANDSET_EVENTPIPE: + ds_eventpipe_protocol_helper_handle_ipc_message (&message, stream); + break; + case DS_SERVER_COMMANDSET_DUMP: + ds_dump_protocol_helper_handle_ipc_message (&message, stream); + break; + case DS_SERVER_COMMANDSET_PROCESS: + ds_process_protocol_helper_handle_ipc_message (&message, stream); + break; + case DS_SERVER_COMMANDSET_PROFILER: + ds_profiler_protocol_helper_handle_ipc_message (&message, stream); + break; + default: + server_protocol_helper_unknown_command (&message, stream); + break; + } + + ds_ipc_message_fini (&message); + + return 0; // continue +} + EP_RT_DEFINE_THREAD_FUNC (server_thread) { EP_ASSERT (server_volatile_load_shutting_down_state () || ds_ipc_stream_factory_has_active_ports ()); @@ -125,58 +180,12 @@ EP_RT_DEFINE_THREAD_FUNC (server_thread) return 1; } - while (!server_volatile_load_shutting_down_state ()) { - DiagnosticsIpcStream *stream = ds_ipc_stream_factory_get_next_available_stream (server_warning_callback); - if (!stream) - continue; - - ds_rt_auto_trace_signal (); - - DiagnosticsIpcMessage message; - if (!ds_ipc_message_init (&message)) - continue; - - if (!ds_ipc_message_initialize_stream (&message, stream)) { - ds_ipc_message_send_error (stream, DS_IPC_E_BAD_ENCODING); - ds_ipc_stream_free (stream); - ds_ipc_message_fini (&message); - continue; - } - - if (ep_rt_utf8_string_compare ( - (const ep_char8_t *)ds_ipc_header_get_magic_ref (ds_ipc_message_get_header_ref (&message)), - (const ep_char8_t *)DOTNET_IPC_V1_MAGIC) != 0) { - - ds_ipc_message_send_error (stream, DS_IPC_E_UNKNOWN_MAGIC); - ds_ipc_stream_free (stream); - ds_ipc_message_fini (&message); - continue; - } - - DS_LOG_INFO_2 ("DiagnosticServer - received IPC message with command set (%d) and command id (%d)", ds_ipc_header_get_commandset (ds_ipc_message_get_header_ref (&message)), ds_ipc_header_get_commandid (ds_ipc_message_get_header_ref (&message))); - - switch ((DiagnosticsServerCommandSet)ds_ipc_header_get_commandset (ds_ipc_message_get_header_ref (&message))) { - case DS_SERVER_COMMANDSET_EVENTPIPE: - ds_eventpipe_protocol_helper_handle_ipc_message (&message, stream); - break; - case DS_SERVER_COMMANDSET_DUMP: - ds_dump_protocol_helper_handle_ipc_message (&message, stream); - break; - case DS_SERVER_COMMANDSET_PROCESS: - ds_process_protocol_helper_handle_ipc_message (&message, stream); - break; - case DS_SERVER_COMMANDSET_PROFILER: - ds_profiler_protocol_helper_handle_ipc_message (&message, stream); - break; - default: - server_protocol_helper_unknown_command (&message, stream); - break; - } - - ds_ipc_message_fini (&message); - } - +#if defined(PERFTRACING_MULTI_THREADED) + while (server_loop_tick () == 1) { } return (ep_rt_thread_start_func_return_t)0; +#else // !PERFTRACING_MULTI_THREADED + return (ep_rt_thread_start_func_return_t)server_loop_tick (); +#endif // PERFTRACING_MULTI_THREADED } void @@ -258,6 +267,8 @@ ds_server_shutdown (void) void ds_server_pause_for_diagnostics_monitor (void) { +// pause is not implemented for single-threaded +#if defined(PERFTRACING_MULTI_THREADED) _is_paused_for_startup = true; if (ds_ipc_stream_factory_any_suspended_ports ()) { @@ -272,6 +283,7 @@ ds_server_pause_for_diagnostics_monitor (void) } // allow wait failures to fall through and the runtime to continue coming up +#endif } void diff --git a/src/native/eventpipe/ep-rt.h b/src/native/eventpipe/ep-rt.h index 060bb71503befc..80a84387c8ef21 100644 --- a/src/native/eventpipe/ep-rt.h +++ b/src/native/eventpipe/ep-rt.h @@ -204,6 +204,14 @@ static void ep_rt_sample_profiler_write_sampling_event_for_threads (ep_rt_thread_handle_t sampling_thread, EventPipeEvent *sampling_event); +static +void +ep_rt_sample_profiler_enabled (void); + +static +void +ep_rt_sample_profiler_disabled (void); + static void ep_rt_notify_profiler_provider_created (EventPipeProvider *provider); diff --git a/src/native/eventpipe/ep-sample-profiler.c b/src/native/eventpipe/ep-sample-profiler.c index b1c10d76a9deb3..38f2e2eece56f4 100644 --- a/src/native/eventpipe/ep-sample-profiler.c +++ b/src/native/eventpipe/ep-sample-profiler.c @@ -84,6 +84,7 @@ sample_profiler_store_can_start_sampling (bool start_sampling) ep_rt_volatile_store_uint32_t (&_can_start_sampling, start_sampling ? 1 : 0); } +#if defined(PERFTRACING_MULTI_THREADED) EP_RT_DEFINE_THREAD_FUNC (sampling_thread) { EP_ASSERT (data != NULL); @@ -108,6 +109,7 @@ EP_RT_DEFINE_THREAD_FUNC (sampling_thread) return (ep_rt_thread_start_func_return_t)0; } +#endif static void @@ -192,6 +194,9 @@ sample_profiler_enable (void) if (!sample_profiler_load_profiling_enabled ()) { sample_profiler_store_profiling_enabled (true); + ep_rt_sample_profiler_enabled (); + +#if defined(PERFTRACING_MULTI_THREADED) EP_ASSERT (!ep_rt_wait_event_is_valid (&_thread_shutdown_event)); ep_rt_wait_event_alloc (&_thread_shutdown_event, true, false); if (!ep_rt_wait_event_is_valid (&_thread_shutdown_event)) @@ -200,6 +205,10 @@ sample_profiler_enable (void) ep_rt_thread_id_t thread_id = ep_rt_uint64_t_to_thread_id_t (0); if (!ep_rt_thread_create ((void *)sampling_thread, NULL, EP_THREAD_TYPE_SAMPLING, &thread_id)) EP_UNREACHABLE ("Unable to create sample profiler thread."); +#else + // once + ep_rt_sample_profiler_write_sampling_event_for_threads (ep_rt_thread_get_handle (), _thread_time_event); +#endif sample_profiler_set_time_granularity (); } @@ -288,9 +297,13 @@ ep_sample_profiler_disable (void) // when profiling is disabled. sample_profiler_store_profiling_enabled (false); + ep_rt_sample_profiler_disabled (); + // Wait for the sampling thread to clean itself up. +#if defined(PERFTRACING_MULTI_THREADED) ep_rt_wait_event_wait (&_thread_shutdown_event, EP_INFINITE_WAIT, false); ep_rt_wait_event_free (&_thread_shutdown_event); +#endif if (_time_period_is_set) sample_profiler_reset_time_granularity (); diff --git a/src/native/eventpipe/ep-session.c b/src/native/eventpipe/ep-session.c index c79d3972cd5587..a7586672acdde6 100644 --- a/src/native/eventpipe/ep-session.c +++ b/src/native/eventpipe/ep-session.c @@ -34,6 +34,20 @@ ep_session_remove_dangling_session_states (EventPipeSession *session); * EventPipeSession. */ +static size_t streaming_loop_tick(EventPipeSession *const session) { + if (!ep_session_get_streaming_enabled (session)){ + session->streaming_thread = NULL; + return 1; // done + } + bool events_written = false; + if (!ep_session_write_all_buffers_to_file (session, &events_written)) { + session->streaming_thread = NULL; + ep_disable ((EventPipeSessionID)session); + return 1; // done + } + return 0; // try again +} + EP_RT_DEFINE_THREAD_FUNC (streaming_thread) { EP_ASSERT (data != NULL); @@ -46,24 +60,20 @@ EP_RT_DEFINE_THREAD_FUNC (streaming_thread) if (session->session_type != EP_SESSION_TYPE_IPCSTREAM && session->session_type != EP_SESSION_TYPE_FILESTREAM) return 1; +#if defined(PERFTRACING_MULTI_THREADED) if (!thread_params->thread || !ep_rt_thread_has_started (thread_params->thread)) return 1; +#endif session->streaming_thread = thread_params->thread; - bool success = true; - ep_rt_wait_event_handle_t *wait_event = ep_session_get_wait_event (session); - ep_rt_volatile_store_uint32_t (&session->started, 1); - EP_GCX_PREEMP_ENTER - while (ep_session_get_streaming_enabled (session)) { - bool events_written = false; - if (!ep_session_write_all_buffers_to_file (session, &events_written)) { - success = false; - break; - } +#if defined(PERFTRACING_MULTI_THREADED) + ep_rt_wait_event_handle_t *wait_event = ep_session_get_wait_event (session); + EP_GCX_PREEMP_ENTER + while (streaming_loop_tick(session) == 0) { if (!events_written) { // No events were available, sleep until more are available ep_rt_wait_event_wait (wait_event, EP_INFINITE_WAIT, false); @@ -73,15 +83,12 @@ EP_RT_DEFINE_THREAD_FUNC (streaming_thread) const uint32_t timeout_ns = 100000000; // 100 msec. ep_rt_thread_sleep (timeout_ns); } - - session->streaming_thread = NULL; ep_rt_wait_event_set (&session->rt_thread_shutdown_event); EP_GCX_PREEMP_EXIT - - if (!success) - ep_disable ((EventPipeSessionID)session); - return (ep_rt_thread_start_func_return_t)0; +#else // !PERFTRACING_MULTI_THREADED + return (ep_rt_thread_start_func_return_t) streaming_loop_tick(session); +#endif // PERFTRACING_MULTI_THREADED } static diff --git a/src/native/eventpipe/ep-shared-config.h.in b/src/native/eventpipe/ep-shared-config.h.in index 5b60e03427603e..7748da024ecf6b 100644 --- a/src/native/eventpipe/ep-shared-config.h.in +++ b/src/native/eventpipe/ep-shared-config.h.in @@ -10,6 +10,18 @@ #define ENABLE_PERFTRACING_PAL_TCP #endif +#cmakedefine FEATURE_PERFTRACING_PAL_WS +#ifdef FEATURE_PERFTRACING_PAL_WS +#define ENABLE_PERFTRACING_PAL_WS +#endif + +#cmakedefine FEATURE_PERFTRACING_SINGLE_THREADED +#ifdef FEATURE_PERFTRACING_SINGLE_THREADED +#define PERFTRACING_SINGLE_THREADED +#else +#define PERFTRACING_MULTI_THREADED +#endif + #cmakedefine FEATURE_PERFTRACING_DISABLE_PERFTRACING_LISTEN_PORTS #ifdef FEATURE_PERFTRACING_DISABLE_PERFTRACING_LISTEN_PORTS #define DISABLE_PERFTRACING_LISTEN_PORTS diff --git a/src/native/libs/System.Native/pal_time.c b/src/native/libs/System.Native/pal_time.c index a249fe653be1c0..488c49776fd9f3 100644 --- a/src/native/libs/System.Native/pal_time.c +++ b/src/native/libs/System.Native/pal_time.c @@ -121,7 +121,7 @@ int64_t SystemNative_GetBootTimeTicks(void) double SystemNative_GetCpuUtilization(ProcessCpuInformation* previousCpuInfo) { -#if defined(HAVE_GETRUSAGE) && !defined(HOST_BROWSER) +#if defined(HAVE_GETRUSAGE) uint64_t kernelTime = 0; uint64_t userTime = 0; From 3bbee717b93d7c504ad407a0167c149f68596013 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 28 Jan 2025 17:59:40 +0100 Subject: [PATCH 2/8] fix --- src/native/eventpipe/ep-session.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/native/eventpipe/ep-session.c b/src/native/eventpipe/ep-session.c index a7586672acdde6..406c207f5ba829 100644 --- a/src/native/eventpipe/ep-session.c +++ b/src/native/eventpipe/ep-session.c @@ -34,13 +34,12 @@ ep_session_remove_dangling_session_states (EventPipeSession *session); * EventPipeSession. */ -static size_t streaming_loop_tick(EventPipeSession *const session) { +static size_t streaming_loop_tick(EventPipeSession *const session, bool *events_written) { if (!ep_session_get_streaming_enabled (session)){ session->streaming_thread = NULL; return 1; // done } - bool events_written = false; - if (!ep_session_write_all_buffers_to_file (session, &events_written)) { + if (!ep_session_write_all_buffers_to_file (session, events_written)) { session->streaming_thread = NULL; ep_disable ((EventPipeSessionID)session); return 1; // done @@ -65,6 +64,7 @@ EP_RT_DEFINE_THREAD_FUNC (streaming_thread) return 1; #endif + bool events_written = false; session->streaming_thread = thread_params->thread; ep_rt_volatile_store_uint32_t (&session->started, 1); @@ -73,7 +73,7 @@ EP_RT_DEFINE_THREAD_FUNC (streaming_thread) ep_rt_wait_event_handle_t *wait_event = ep_session_get_wait_event (session); EP_GCX_PREEMP_ENTER - while (streaming_loop_tick(session) == 0) { + while (streaming_loop_tick(session, &events_written) == 0) { if (!events_written) { // No events were available, sleep until more are available ep_rt_wait_event_wait (wait_event, EP_INFINITE_WAIT, false); @@ -82,12 +82,14 @@ EP_RT_DEFINE_THREAD_FUNC (streaming_thread) // Wait until it's time to sample again. const uint32_t timeout_ns = 100000000; // 100 msec. ep_rt_thread_sleep (timeout_ns); + + events_written = false; } ep_rt_wait_event_set (&session->rt_thread_shutdown_event); EP_GCX_PREEMP_EXIT return (ep_rt_thread_start_func_return_t)0; #else // !PERFTRACING_MULTI_THREADED - return (ep_rt_thread_start_func_return_t) streaming_loop_tick(session); + return (ep_rt_thread_start_func_return_t) streaming_loop_tick(session, &events_written); #endif // PERFTRACING_MULTI_THREADED } From fe063def1d45e33909aebb70041caa2083d276c1 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 28 Jan 2025 18:38:10 +0100 Subject: [PATCH 3/8] fix --- src/mono/mono/component/CMakeLists.txt | 9 +++++++++ src/native/eventpipe/CMakeLists.txt | 6 ++++-- src/native/eventpipe/ds-server.c | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/component/CMakeLists.txt b/src/mono/mono/component/CMakeLists.txt index 0e663e690fc4fd..53c0f1974ea836 100644 --- a/src/mono/mono/component/CMakeLists.txt +++ b/src/mono/mono/component/CMakeLists.txt @@ -216,6 +216,15 @@ endif() if (ENABLE_PERFTRACING AND "${MONO_DIAGNOSTICS_TRACING_COMPONENT_NAME}" IN_LIST components_to_build) # Build EventPipe and DiagnosticServer with the Mono runtime implementation as unity-builds. add_library(eventpipe-mono-objects OBJECT) + + if (DISABLE_THREADS) + set_target_properties( + eventpipe-mono-objects + PROPERTIES + DISABLE_THREADS ON + ) + endif() + set_target_properties( eventpipe-mono-objects PROPERTIES diff --git a/src/native/eventpipe/CMakeLists.txt b/src/native/eventpipe/CMakeLists.txt index 867f76f7795f42..fe32de8f64661c 100644 --- a/src/native/eventpipe/CMakeLists.txt +++ b/src/native/eventpipe/CMakeLists.txt @@ -20,8 +20,10 @@ endif() # Use WebSocket for EventPipe on mobile browser if (CLR_CMAKE_HOST_BROWSER) set(FEATURE_PERFTRACING_PAL_WS 1) - set(FEATURE_PERFTRACING_SINGLE_THREADED 1) set(FEATURE_PERFTRACING_DISABLE_DEFAULT_LISTEN_PORT 1) + if (DISABLE_THREADS) + set(FEATURE_PERFTRACING_SINGLE_THREADED 1) + endif() endif() configure_file(${CLR_SRC_NATIVE_DIR}/eventpipe/ep-shared-config.h.in ${CMAKE_CURRENT_BINARY_DIR}/ep-shared-config.h) @@ -67,7 +69,7 @@ else() target_sources(dn-diagnosticserver-pal INTERFACE ds-ipc-pal-socket.c ) -endif (FEATURE_PERFTRACING_PAL_TCP) +endif (FEATURE_PERFTRACING_PAL_WS) add_library(dn-eventpipe INTERFACE) diff --git a/src/native/eventpipe/ds-server.c b/src/native/eventpipe/ds-server.c index 0865180a174ecd..f2edcfccabd636 100644 --- a/src/native/eventpipe/ds-server.c +++ b/src/native/eventpipe/ds-server.c @@ -112,7 +112,7 @@ server_warning_callback ( DS_LOG_WARNING_2 ("warning (%d): %s.", code, message); } -static size_t server_loop_tick () { +static size_t server_loop_tick (void) { if (server_volatile_load_shutting_down_state ()) return 1; // done DiagnosticsIpcStream *stream = ds_ipc_stream_factory_get_next_available_stream (server_warning_callback); From d6c58218bc58af86d0544e66951809562ac04e65 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 28 Jan 2025 21:06:43 +0100 Subject: [PATCH 4/8] chmod a+rw --- .../CoreclrTestWrapperLib.cs | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs b/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs index 89601399b5b04f..7dc086ae58b48f 100644 --- a/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs +++ b/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs @@ -391,25 +391,21 @@ public static bool TryPrintStackTraceFromCrashReport(string crashReportJsonFile, } Console.WriteLine("========================================="); - string? userName = Environment.GetEnvironmentVariable("USER"); - if (!string.IsNullOrEmpty(userName)) + if (!RunProcess("sudo", $"chmod a+rw {crashReportJsonFile}", Console.Out)) { - if (!RunProcess("sudo", $"chown {userName} {crashReportJsonFile}", Console.Out)) - { - return false; - } + return false; + } - Console.WriteLine("========================================="); - if (!RunProcess("sudo", $"ls -l {crashReportJsonFile}", Console.Out)) - { - return false; - } + Console.WriteLine("========================================="); + if (!RunProcess("sudo", $"ls -l {crashReportJsonFile}", Console.Out)) + { + return false; + } - Console.WriteLine("========================================="); - if (!RunProcess("ls", $"-l {crashReportJsonFile}", Console.Out)) - { - return false; - } + Console.WriteLine("========================================="); + if (!RunProcess("ls", $"-l {crashReportJsonFile}", Console.Out)) + { + return false; } } From cdad8b2723a4b2a9c6dac7c8c82f88ed286599d8 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 29 Jan 2025 11:47:51 +0100 Subject: [PATCH 5/8] fix --- src/native/eventpipe/ds-server.c | 2 +- .../Coreclr.TestWrapper/CoreclrTestWrapperLib.cs | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/native/eventpipe/ds-server.c b/src/native/eventpipe/ds-server.c index f2edcfccabd636..348dd1ad81a8dd 100644 --- a/src/native/eventpipe/ds-server.c +++ b/src/native/eventpipe/ds-server.c @@ -181,7 +181,7 @@ EP_RT_DEFINE_THREAD_FUNC (server_thread) } #if defined(PERFTRACING_MULTI_THREADED) - while (server_loop_tick () == 1) { } + while (server_loop_tick () == 0) { } return (ep_rt_thread_start_func_return_t)0; #else // !PERFTRACING_MULTI_THREADED return (ep_rt_thread_start_func_return_t)server_loop_tick (); diff --git a/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs b/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs index 7dc086ae58b48f..7f147d05f16622 100644 --- a/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs +++ b/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs @@ -391,11 +391,22 @@ public static bool TryPrintStackTraceFromCrashReport(string crashReportJsonFile, } Console.WriteLine("========================================="); + string? userName = Environment.GetEnvironmentVariable("USER"); + if (string.IsNullOrEmpty(userName)) + { + userName="helixbot"; + } + if (!RunProcess("sudo", $"chmod a+rw {crashReportJsonFile}", Console.Out)) { return false; } + if (!RunProcess("sudo", $"chown {userName} {crashReportJsonFile}", Console.Out)) + { + return false; + } + Console.WriteLine("========================================="); if (!RunProcess("sudo", $"ls -l {crashReportJsonFile}", Console.Out)) { From 3b711be90cdedf31ce63bef608b48088b23bdab7 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 29 Jan 2025 14:26:26 +0100 Subject: [PATCH 6/8] revert chmod --- .../CoreclrTestWrapperLib.cs | 37 ++++++++----------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs b/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs index 7f147d05f16622..89601399b5b04f 100644 --- a/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs +++ b/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs @@ -392,31 +392,24 @@ public static bool TryPrintStackTraceFromCrashReport(string crashReportJsonFile, Console.WriteLine("========================================="); string? userName = Environment.GetEnvironmentVariable("USER"); - if (string.IsNullOrEmpty(userName)) + if (!string.IsNullOrEmpty(userName)) { - userName="helixbot"; - } - - if (!RunProcess("sudo", $"chmod a+rw {crashReportJsonFile}", Console.Out)) - { - return false; - } - - if (!RunProcess("sudo", $"chown {userName} {crashReportJsonFile}", Console.Out)) - { - return false; - } + if (!RunProcess("sudo", $"chown {userName} {crashReportJsonFile}", Console.Out)) + { + return false; + } - Console.WriteLine("========================================="); - if (!RunProcess("sudo", $"ls -l {crashReportJsonFile}", Console.Out)) - { - return false; - } + Console.WriteLine("========================================="); + if (!RunProcess("sudo", $"ls -l {crashReportJsonFile}", Console.Out)) + { + return false; + } - Console.WriteLine("========================================="); - if (!RunProcess("ls", $"-l {crashReportJsonFile}", Console.Out)) - { - return false; + Console.WriteLine("========================================="); + if (!RunProcess("ls", $"-l {crashReportJsonFile}", Console.Out)) + { + return false; + } } } From 685f663542e3dfacadf580f03fb9ccb310c42bfe Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 29 Jan 2025 17:07:54 +0100 Subject: [PATCH 7/8] put it back --- .../CoreclrTestWrapperLib.cs | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs b/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs index 89601399b5b04f..7f147d05f16622 100644 --- a/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs +++ b/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs @@ -392,24 +392,31 @@ public static bool TryPrintStackTraceFromCrashReport(string crashReportJsonFile, Console.WriteLine("========================================="); string? userName = Environment.GetEnvironmentVariable("USER"); - if (!string.IsNullOrEmpty(userName)) + if (string.IsNullOrEmpty(userName)) { - if (!RunProcess("sudo", $"chown {userName} {crashReportJsonFile}", Console.Out)) - { - return false; - } + userName="helixbot"; + } - Console.WriteLine("========================================="); - if (!RunProcess("sudo", $"ls -l {crashReportJsonFile}", Console.Out)) - { - return false; - } + if (!RunProcess("sudo", $"chmod a+rw {crashReportJsonFile}", Console.Out)) + { + return false; + } - Console.WriteLine("========================================="); - if (!RunProcess("ls", $"-l {crashReportJsonFile}", Console.Out)) - { - return false; - } + if (!RunProcess("sudo", $"chown {userName} {crashReportJsonFile}", Console.Out)) + { + return false; + } + + Console.WriteLine("========================================="); + if (!RunProcess("sudo", $"ls -l {crashReportJsonFile}", Console.Out)) + { + return false; + } + + Console.WriteLine("========================================="); + if (!RunProcess("ls", $"-l {crashReportJsonFile}", Console.Out)) + { + return false; } } From 2af88c32ee127963a0d9a549ae2b9fe1a4f24f95 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 31 Jan 2025 12:55:49 +0100 Subject: [PATCH 8/8] feedback --- src/mono/browser/build/BrowserWasmApp.targets | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mono/browser/build/BrowserWasmApp.targets b/src/mono/browser/build/BrowserWasmApp.targets index bc54470ba2df3d..08df4ce7c3c85a 100644 --- a/src/mono/browser/build/BrowserWasmApp.targets +++ b/src/mono/browser/build/BrowserWasmApp.targets @@ -4,6 +4,7 @@ true $(WasmEnableExceptionHandling) true + false