-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[wasm] Don't use SyncTextWriter in single-threaded wasm builds #101221
Conversation
Tagging subscribers to 'arch-wasm': @lewing |
The fast path should always be taken in ST builds and everything should inline. Why is this necessary? Also, monitor.isentered will always return false this way |
A sizable percentage of startup time is interp codegen, so I've been seeing how many subtrees of useless methods I can prune out easily. The monitor.isentered thing is a good point, I guess that rules this optimization out. |
ah ok. so actually rewriting this part in managed was a bad idea for startup perf. we only measured benchmark (steady state) perf once the interpreter was tiering up the callers. (so Monitor.Enter/Exit loops without contention on ST interp were the same as or a bit faster than the old JIT icall monitor implementation) |
Do you think it makes sense to use a simpler lockword representation for ST? (for example we don't have to use Interlocked ops to increment/decrement the count - we can just use normal reads/writes). possibly hand-inline more code from ObjectHeader into Monitor.Enter/Exit? |
I think that makes sense, we could just provide simple implementations of the primitives for that configuration which would prune out most of the dependencies without breaking it. I'll make a note to try that. |
It only gets triggered if you write to the console, yes, but don't we write to the console at least once during startup? I thought I recalled seeing a console message |
This wrapper overhead applies to any synchronized method that is in the startup path, yes |
…hronization code during startup when console is touched
// Browser bypasses SyncTextWriter for faster startup | ||
if (!OperatingSystem.IsBrowser()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should use PlatformDetection.IsThreadingSupported
too instead of checking for browser so it applies to single-threaded wasi too
@@ -22,6 +22,8 @@ | |||
<IsBigEndian Condition="'$(Platform)' == 's390x'">true</IsBigEndian> | |||
<Is64Bit Condition="'$(Platform)' == 'arm64' or '$(Platform)' == 'x64' or '$(Platform)' == 's390x' or '$(Platform)' == 'loongarch64' or '$(Platform)' == 'ppc64le' or '$(Platform)' == 'riscv64'">true</Is64Bit> | |||
<UseMinimalGlobalizationData Condition="'$(TargetsBrowser)' == 'true' or '$(TargetsWasi)' == 'true'">true</UseMinimalGlobalizationData> | |||
<FeatureWasmManagedThreads Condition="'$(WasmEnableThreads)' == 'true'">true</FeatureWasmManagedThreads> | |||
<DefineConstants Condition="'$(FeatureWasmManagedThreads)' == 'true'">$(DefineConstants);FEATURE_WASM_MANAGED_THREADS</DefineConstants> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this duplicates the conditions from src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj, I don't think we need them here
@@ -759,7 +759,11 @@ public static TextWriter Synchronized(TextWriter writer) | |||
{ | |||
ArgumentNullException.ThrowIfNull(writer); | |||
|
|||
#if !TARGET_BROWSER || FEATURE_WASM_MANAGED_THREADS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should also check for WASI
Follow-up to dotnet#101221 so we match behavior between single-threaded Browser and WASI.
Follow-up to #101221 so we match behavior between single-threaded Browser and WASI.
(New description, PR was revised)
We normally wrap custom console streams with SyncTextWriter, which forces the mono interpreter/jit/aot compiler to use synchronized wrappers for all calls through the class. Wrappers have optimization force-enabled, which means all the methods they call get inlined into the wrapper every time, increasing the size of the wrapper's code and the amount of time we spend in codegen for it.
The default wasm configuration right now is single-threaded, so we can skip using SyncTextWriter and as a result skip the synchronized wrapper. While this doesn't fully prevent monitors from becoming involved in startup, it removes a bunch of inlined monitor API calls, which should be an improvement to startup time for any wasm application that touches the console.