From b331283da9ca30a47bd96b16e388f1b2217abfc8 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 8 Dec 2023 16:44:05 +0100 Subject: [PATCH 1/4] - mono_wasm_init_finalizer_thread for MT - -backgroundExec for Wasm test runner triggered via --- eng/testing/tests.browser.targets | 2 ++ .../Common/tests/WasmTestRunner/WasmTestRunner.cs | 9 ++++++++- ...time.InteropServices.JavaScript.Legacy.Tests.csproj | 1 + ...tem.Runtime.InteropServices.JavaScript.Tests.csproj | 1 + .../InteropServices/JavaScript/JavaScriptTestHelper.cs | 1 + src/libraries/tests.proj | 1 + src/mono/wasm/runtime/cwraps.ts | 2 ++ src/mono/wasm/runtime/driver.c | 8 ++------ src/mono/wasm/runtime/exports-binding.ts | 4 ++-- src/mono/wasm/runtime/startup.ts | 6 ++++-- src/mono/wasm/test-main.js | 10 +++++----- 11 files changed, 29 insertions(+), 16 deletions(-) diff --git a/eng/testing/tests.browser.targets b/eng/testing/tests.browser.targets index 16a80cea267019..7c0a0f86f0d6e8 100644 --- a/eng/testing/tests.browser.targets +++ b/eng/testing/tests.browser.targets @@ -105,6 +105,8 @@ <_AppArgs Condition="'$(IsFunctionalTest)' != 'true' and '$(WasmMainAssemblyFileName)' != ''">--run $(WasmMainAssemblyFileName) <_AppArgs Condition="'$(IsFunctionalTest)' == 'true'">--run $(AssemblyName).dll + <_XUnitBackgroundExec Condition="'$(_XUnitBackgroundExec)' == '' and '$(MonoWasmBuildVariant)' == 'multithread'">true + $(WasmTestAppArgs) -backgroundExec <_AppArgs Condition="'$(WasmTestAppArgs)' != ''">$(_AppArgs) $(WasmTestAppArgs) $(WasmXHarnessMonoArgs) --setenv=XHARNESS_LOG_TEST_START=1 diff --git a/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs index 0134102a042045..9fb129d825d742 100644 --- a/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs +++ b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs @@ -23,6 +23,7 @@ public static async Task Main(string[] args) var includedNamespaces = new List(); var includedClasses = new List(); var includedMethods = new List(); + var backgroundExec = false; for (int i = 1; i < args.Length; i++) { @@ -49,6 +50,9 @@ public static async Task Main(string[] args) includedMethods.Add (args[i + 1]); i++; break; + case "-backgroundExec": + backgroundExec = true; + break; default: throw new ArgumentException($"Invalid argument '{option}'."); } @@ -68,7 +72,10 @@ public static async Task Main(string[] args) { await Task.Yield(); } - + if (backgroundExec) + { + return await Task.Run(() => runner.Run()); + } return await runner.Run(); } } diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.Legacy.UnitTests/System.Runtime.InteropServices.JavaScript.Legacy.Tests.csproj b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.Legacy.UnitTests/System.Runtime.InteropServices.JavaScript.Legacy.Tests.csproj index 41aaf18747b027..ac1952858fad6f 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.Legacy.UnitTests/System.Runtime.InteropServices.JavaScript.Legacy.Tests.csproj +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.Legacy.UnitTests/System.Runtime.InteropServices.JavaScript.Legacy.Tests.csproj @@ -8,6 +8,7 @@ true $(DefineConstants);DISABLE_LEGACY_JS_INTEROP WasmTestOnBrowser + <_XUnitBackgroundExec>false diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj index 13a08edcbf23b8..69d88e7e7a991b 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj @@ -10,6 +10,7 @@ $(DefineConstants);DISABLE_LEGACY_JS_INTEROP true + <_XUnitBackgroundExec>false diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs index 18b53e61d920cf..4c3aaa9ed1923c 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs @@ -1004,6 +1004,7 @@ public static async Task InitializeAsync() await Setup(); // Log("JavaScriptTestHelper.mjs imported"); } + await Task.Yield(); } public static Task DisposeAsync() diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 05605d51f70069..102d910e7fd0fd 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -592,6 +592,7 @@ --> + diff --git a/src/mono/wasm/runtime/cwraps.ts b/src/mono/wasm/runtime/cwraps.ts index 4026be432c3004..847c0e5c0fd627 100644 --- a/src/mono/wasm/runtime/cwraps.ts +++ b/src/mono/wasm/runtime/cwraps.ts @@ -41,6 +41,7 @@ const threading_cwraps: SigLine[] = MonoWasmThreads ? [ [true, "mono_wasm_diagnostic_server_thread_attach_to_runtime", "void", []], [true, "mono_wasm_diagnostic_server_post_resume_runtime", "void", []], [true, "mono_wasm_diagnostic_server_create_stream", "number", []], + [false, "mono_wasm_init_finalizer_thread", null, []], ] : []; // when the method is assigned/cached at usage, instead of being invoked directly from cwraps, it can't be marked lazy, because it would be re-bound on each call @@ -181,6 +182,7 @@ export interface t_ThreadingCwraps { mono_wasm_diagnostic_server_thread_attach_to_runtime(): void; mono_wasm_diagnostic_server_post_resume_runtime(): void; mono_wasm_diagnostic_server_create_stream(): VoidPtr; + mono_wasm_init_finalizer_thread(): void; } export interface t_ProfilerCwraps { diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c index d7e729e669b62a..0eec13611fb22c 100644 --- a/src/mono/wasm/runtime/driver.c +++ b/src/mono/wasm/runtime/driver.c @@ -58,7 +58,6 @@ char *mono_method_get_full_name (MonoMethod *method); extern void mono_register_timezones_bundle (void); #endif /* INVARIANT_TIMEZONE */ extern void mono_wasm_set_entrypoint_breakpoint (const char* assembly_name, int method_token); -static void mono_wasm_init_finalizer_thread (void); extern void mono_bundled_resources_add_assembly_resource (const char *id, const char *name, const uint8_t *data, uint32_t size, void (*free_func)(void *, void*), void *free_data); extern void mono_bundled_resources_add_assembly_symbol_resource (const char *id, const uint8_t *data, uint32_t size, void (*free_func)(void *, void *), void *free_data); @@ -542,9 +541,6 @@ mono_wasm_load_runtime (const char *unused, int debug_level) mono_thread_set_main (mono_thread_current ()); - // TODO: we can probably delay starting the finalizer thread even longer - maybe from JS - // once we're done with loading and are about to begin running some managed code. - mono_wasm_init_finalizer_thread (); } EMSCRIPTEN_KEEPALIVE MonoAssembly* @@ -1296,12 +1292,12 @@ mono_wasm_profiler_init_browser (const char *desc) #endif -static void +EMSCRIPTEN_KEEPALIVE void mono_wasm_init_finalizer_thread (void) { // At this time we don't use a dedicated thread for finalization even if threading is enabled. // Finalizers periodically run on the main thread -#if 0 +#ifndef DISABLE_THREADS mono_gc_init_finalizer_thread (); #endif } diff --git a/src/mono/wasm/runtime/exports-binding.ts b/src/mono/wasm/runtime/exports-binding.ts index e4f2b1fd0ea143..67fc34fa36e53d 100644 --- a/src/mono/wasm/runtime/exports-binding.ts +++ b/src/mono/wasm/runtime/exports-binding.ts @@ -19,7 +19,7 @@ import { mono_wasm_asm_loaded } from "./startup"; import { mono_wasm_diagnostic_server_on_server_thread_created } from "./diagnostics/server_pthread"; import { mono_wasm_diagnostic_server_on_runtime_server_init, mono_wasm_event_pipe_early_startup_callback } from "./diagnostics"; import { mono_wasm_diagnostic_server_stream_signal_work_available } from "./diagnostics/server_pthread/stream-queue"; -import { mono_log_debug, mono_log_warn, mono_wasm_trace_logger } from "./logging"; +import { mono_log_warn, mono_wasm_trace_logger } from "./logging"; import { mono_wasm_profiler_leave, mono_wasm_profiler_enter } from "./profiler"; import { mono_wasm_change_case, mono_wasm_change_case_invariant } from "./hybrid-globalization/change-case"; import { mono_wasm_compare_string, mono_wasm_ends_with, mono_wasm_starts_with, mono_wasm_index_of } from "./hybrid-globalization/collations"; @@ -163,7 +163,7 @@ export function replace_linker_placeholders(imports: WebAssembly.Imports) { const stubFn = env[shortName]; if (typeof stubFn !== "function") throw new Error(`Expected ${shortName} to be a function`); env[shortName] = realFn; - mono_log_debug(`Replaced WASM import ${shortName} stub ${stubFn.name} with ${realFn.name || "minified implementation"}`); + // mono_log_debug(`Replaced WASM import ${shortName} stub ${stubFn.name} with ${realFn.name || "minified implementation"}`); } } diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index f59dbabbe57999..93a9bd9ece0ad3 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.ts @@ -6,7 +6,7 @@ import WasmEnableLegacyJsInterop from "consts:wasmEnableLegacyJsInterop"; import { DotnetModuleInternal, CharPtrNull } from "./types/internal"; import { linkerDisableLegacyJsInterop, ENVIRONMENT_IS_PTHREAD, ENVIRONMENT_IS_NODE, exportedRuntimeAPI, INTERNAL, loaderHelpers, Module, runtimeHelpers, createPromiseController, mono_assert, linkerWasmEnableSIMD, linkerWasmEnableEH, ENVIRONMENT_IS_WORKER } from "./globals"; -import cwraps, { init_c_exports } from "./cwraps"; +import cwraps, { init_c_exports, threads_c_functions as tcwraps } from "./cwraps"; import { mono_wasm_raise_debug_event, mono_wasm_runtime_ready } from "./debug"; import { toBase64StringImpl } from "./base64"; import { mono_wasm_init_aot_profiler, mono_wasm_init_browser_profiler } from "./profiler"; @@ -334,6 +334,8 @@ async function postRunAsync(userpostRun: (() => void)[]) { Module["FS_createPath"]("/", "usr", true, true); Module["FS_createPath"]("/", "usr/share", true, true); + if (MonoWasmThreads) tcwraps.mono_wasm_init_finalizer_thread(); + // all user Module.postRun callbacks userpostRun.map(fn => fn()); endMeasure(mark, MeasuredBlock.postRun); @@ -561,7 +563,7 @@ async function mono_wasm_before_memory_snapshot() { endMeasure(mark, MeasuredBlock.memorySnapshot); } -async function maybeSaveInterpPgoTable () { +async function maybeSaveInterpPgoTable() { // If the application exited abnormally, don't save the table. It probably doesn't contain useful data, // and saving would overwrite any existing table from a previous successful run. // We treat exiting with a code of 0 as equivalent to if the app is still running - it's perfectly fine diff --git a/src/mono/wasm/test-main.js b/src/mono/wasm/test-main.js index 4467dc20ce204e..a8cd689ae0c32f 100644 --- a/src/mono/wasm/test-main.js +++ b/src/mono/wasm/test-main.js @@ -350,11 +350,11 @@ async function run() { if (ENVIRONMENT_IS_WEB && runArgs.memorySnapshot) { if (globalThis.isSecureContext) { - const dryOk = await dry_run(runArgs); - if (!dryOk) { - mono_exit(1, "Failed during dry run"); - return; - } + const dryOk = await dry_run(runArgs); + if (!dryOk) { + mono_exit(1, "Failed during dry run"); + return; + } } else { console.log("Skipping dry run as the context is not secure and the snapshot would be not trusted."); } From a5beec9242bb754577ce4f6097eaa506fdfbc98c Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 8 Dec 2023 16:54:10 +0100 Subject: [PATCH 2/4] wip --- src/mono/wasm/runtime/driver.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c index 0eec13611fb22c..3ebaa52edfdf18 100644 --- a/src/mono/wasm/runtime/driver.c +++ b/src/mono/wasm/runtime/driver.c @@ -1295,8 +1295,7 @@ mono_wasm_profiler_init_browser (const char *desc) EMSCRIPTEN_KEEPALIVE void mono_wasm_init_finalizer_thread (void) { - // At this time we don't use a dedicated thread for finalization even if threading is enabled. - // Finalizers periodically run on the main thread + // in the single threaded build, finalizers periodically run on the main thread instead. #ifndef DISABLE_THREADS mono_gc_init_finalizer_thread (); #endif From 0ff0025e1282460bc2ca20b1dcbd905d554ec735 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 8 Dec 2023 18:24:11 +0100 Subject: [PATCH 3/4] issue # 95795 --- src/libraries/tests.proj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 102d910e7fd0fd..1fb4d6f1a6c123 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -390,6 +390,9 @@ + + + From 75900c39def78409af788ed53bd6bb6192a2016e Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 12 Dec 2023 08:49:13 +0100 Subject: [PATCH 4/4] feedback --- ...tem.Runtime.InteropServices.JavaScript.Legacy.Tests.csproj | 1 + .../System.Runtime.InteropServices.JavaScript.Tests.csproj | 1 + .../InteropServices/JavaScript/JavaScriptTestHelper.cs | 2 ++ src/mono/wasm/runtime/exports-binding.ts | 2 -- src/mono/wasm/runtime/startup.ts | 4 +++- 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.Legacy.UnitTests/System.Runtime.InteropServices.JavaScript.Legacy.Tests.csproj b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.Legacy.UnitTests/System.Runtime.InteropServices.JavaScript.Legacy.Tests.csproj index ac1952858fad6f..80bdbabd3b1d8b 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.Legacy.UnitTests/System.Runtime.InteropServices.JavaScript.Legacy.Tests.csproj +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.Legacy.UnitTests/System.Runtime.InteropServices.JavaScript.Legacy.Tests.csproj @@ -8,6 +8,7 @@ true $(DefineConstants);DISABLE_LEGACY_JS_INTEROP WasmTestOnBrowser + <_XUnitBackgroundExec>false diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj index 69d88e7e7a991b..c4d5494f93718f 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj @@ -10,6 +10,7 @@ $(DefineConstants);DISABLE_LEGACY_JS_INTEROP true + <_XUnitBackgroundExec>false diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs index 4c3aaa9ed1923c..26227d1f00549c 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs @@ -1004,6 +1004,8 @@ public static async Task InitializeAsync() await Setup(); // Log("JavaScriptTestHelper.mjs imported"); } + + // this gives browser chance to serve UI thread event loop before every test await Task.Yield(); } diff --git a/src/mono/wasm/runtime/exports-binding.ts b/src/mono/wasm/runtime/exports-binding.ts index 67fc34fa36e53d..50f3c14c0a313c 100644 --- a/src/mono/wasm/runtime/exports-binding.ts +++ b/src/mono/wasm/runtime/exports-binding.ts @@ -163,8 +163,6 @@ export function replace_linker_placeholders(imports: WebAssembly.Imports) { const stubFn = env[shortName]; if (typeof stubFn !== "function") throw new Error(`Expected ${shortName} to be a function`); env[shortName] = realFn; - // mono_log_debug(`Replaced WASM import ${shortName} stub ${stubFn.name} with ${realFn.name || "minified implementation"}`); } } - } diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index 93a9bd9ece0ad3..556dd158c9700c 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.ts @@ -334,7 +334,9 @@ async function postRunAsync(userpostRun: (() => void)[]) { Module["FS_createPath"]("/", "usr", true, true); Module["FS_createPath"]("/", "usr/share", true, true); - if (MonoWasmThreads) tcwraps.mono_wasm_init_finalizer_thread(); + if (MonoWasmThreads) { + tcwraps.mono_wasm_init_finalizer_thread(); + } // all user Module.postRun callbacks userpostRun.map(fn => fn());