Repository navigation
Optimize EventSource.GetGuid (NetEventSource) #120352
Description
Activity
- addeduntriagedNew issue has not been triaged by the area ownerNew issue has not been triaged by the area owner
on Oct 3, 2025 - addedneeds-area-labelAn area label is needed to ensure this gets routed to the appropriate area ownersAn area label is needed to ensure this gets routed to the appropriate area owners
on Oct 3, 2025 Duplicate of #28290
- marked this as a duplicate of Add EventSource guid ctors for non-reflection creation #28290
on Oct 3, 2025 - addedtenet-performancePerformance related issuePerformance related issueand removedneeds-area-labelAn area label is needed to ensure this gets routed to the appropriate area ownersAn area label is needed to ensure this gets routed to the appropriate area owners
on Oct 3, 2025 dotnet-policy-service commented
on Oct 3, 2025 ContributorMore actionsTagging subscribers to this area: @tarekgh, @tommcdon, @steveisok, @pjanotti
See info in area-owners.md if you want to be subscribed.Ah, indeed!
cc @MihaZupan in case if you're interested in duplicates where your bot didn't mark it as suchLooks like it flagged these as candidates, but all fell below the confidence heuristics.
- EventSource use of EventAttribute triggers dynamic methods in attribute usage #90405
- NativeRuntimeEventSource is too slow initialized #60963
- Add EventSource guid ctors for non-reflection creation #28290
Could be something to improve in the prompts
Reacted by Egor Bogatov- removeduntriagedNew issue has not been triaged by the area ownerNew issue has not been triaged by the area owner
on Oct 3, 2025 I wonder if we can avoid it for ASCII-only type names
It would be safe to avoid it only if IsAsciiCasingSameAsInvariant returns true. IsAsciiCasingSameAsInvariant requires ICU...
ICU will most likely be loaded during the startup anyway for most apps
Right.
I think it is more interesting to figure out what needs to happen to generate this guid at build time.
Reacted by Egor BogatovAnother bottleneck (unrelated): https://github.com/dotnet/runtime/blob/main/src/libraries/Common/src/System/Net/Sockets/SocketErrorPal.Unix.cs#L34-L130
Such static Dictionary initializations lead to a slow
cctorwith tons ofAdd()calls.
It's not the first time I see this problem, perhaps, we can do something for it e.g. on the Roslyn side?I wonder if we can avoid it for ASCII-only type names
It would be safe to avoid it only if IsAsciiCasingSameAsInvariant returns true. IsAsciiCasingSameAsInvariant requires ICU...
IsAsciiCasingSameAsInvariantis unconditionally "true" for invariant operations like this
but
CultureData.Invarianttriggers ICU, rightI'm not sure it's worth creating an issue but seems like we might want to expect the following code snippet to produce less JIT compilations?
using System.Net; using System.Net.Sockets; using Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); listener.Bind(new IPEndPoint(IPAddress.Loopback, 7878)); listener.Listen(1); listener.Close();
Linux-x64
DOTNET_JitDisasmSummary=1:1: JIT compiled Program:<Main>$(System.String[]) [Tier0, IL size=56, code size=246] 2: JIT compiled System.RuntimeType+IGenericCacheEntry`1[System.__Canon]:CreateAndCache(System.RuntimeType) [Instrumented Tier0, IL size=165, code size=1066] 3: JIT compiled (dynamicClass):InvokeStub_EventSourceAttribute.set_Name(System.Object,System.Object,ptr) [FullOpts, IL size=25, code size=25] 4: JIT compiled System.Collections.Concurrent.ConcurrentQueue`1[System.Net.Sockets.SocketAsyncEngine+SocketIOEvent]:.ctor() [Tier0, IL size=44, code size=169] 5: JIT compiled System.Collections.Concurrent.ConcurrentQueueSegment`1[System.Net.Sockets.SocketAsyncEngine+SocketIOEvent]:.ctor(int) [Instrumented Tier0, IL size=65, code size=215] 6: JIT compiled System.Net.IPAddress:.ctor(System.ReadOnlySpan`1[byte]) [Tier0, IL size=69, code size=220] 7: JIT compiled System.Net.IPAddress:.ctor(System.ReadOnlySpan`1[byte],long) [Tier0, IL size=67, code size=215] 8: JIT compiled System.Net.IPAddress:ReadUInt16NumbersFromBytes(System.ReadOnlySpan`1[byte]) [Instrumented Tier0, IL size=96, code size=161] 9: JIT compiled System.Collections.Generic.Dictionary`2[int,int]:.ctor(int) [Tier0, IL size=9, code size=39] 10: JIT compiled System.Collections.Generic.Dictionary`2[int,int]:.ctor(int,System.Collections.Generic.IEqualityComparer`1[int]) [Tier0, IL size=136, code size=116] 11: JIT compiled System.Collections.Generic.Dictionary`2[int,int]:Initialize(int) [Tier0, IL size=56, code size=156] 12: JIT compiled System.Collections.Generic.Dictionary`2[int,int]:Add(int,int) [Tier0, IL size=11, code size=48] 13: JIT compiled System.Collections.Generic.Dictionary`2[int,int]:TryInsert(int,int,byte) [Instrumented Tier0, IL size=565, code size=1502] 14: JIT compiled System.Collections.Generic.Dictionary`2[int,int]:GetBucket(uint) [Tier0, IL size=29, code size=90] 15: JIT compiled System.Collections.Generic.Dictionary`2[int,int]:.ctor(int) [Tier0, IL size=9, code size=39] 16: JIT compiled System.Collections.Generic.Dictionary`2[int,int]:.ctor(int,System.Collections.Generic.IEqualityComparer`1[int]) [Tier0, IL size=136, code size=116] 17: JIT compiled System.Collections.Generic.Dictionary`2[int,int]:Initialize(int) [Tier0, IL size=56, code size=156] 18: JIT compiled System.Collections.Generic.Dictionary`2[int,int]:Add(int,int) [Tier0, IL size=11, code size=48] 19: JIT compiled System.Collections.Generic.Dictionary`2[int,int]:TryInsert(int,int,byte) [Instrumented Tier0, IL size=565, code size=1502] 20: JIT compiled System.Collections.Generic.Dictionary`2[int,int]:GetBucket(uint) [Tier0, IL size=29, code size=90] 21: JIT compiled System.Collections.Generic.Dictionary`2[int,int]:TryGetValue(int,byref) [Tier0, IL size=39, code size=90] 22: JIT compiled System.Collections.Generic.Dictionary`2[int,int]:FindValue(int) [Instrumented Tier0, IL size=297, code size=1079] 23: JIT compiled System.Collections.Generic.EqualityComparer`1[int]:get_Default() [Tier0, IL size=6, code size=35] 24: JIT compiled System.Collections.Generic.EqualityComparer`1[int]:.cctor() [Tier0, IL size=26, code size=81] 25: JIT compiled System.Collections.Generic.EnumEqualityComparer`1[int]:.ctor() [Tier0, IL size=7, code size=31] 26: JIT compiled System.Collections.Generic.EqualityComparer`1[int]:.ctor() [Tier0, IL size=7, code size=31] 27: JIT compiled System.Collections.Generic.EnumEqualityComparer`1[int]:GetHashCode(int) [Tier0, IL size=14, code size=34] 28: JIT compiled System.Collections.Generic.EnumEqualityComparer`1[int]:Equals(int,int) [Tier0, IL size=8, code size=39] 29: JIT compiled System.Runtime.CompilerServices.RuntimeHelpers:EnumEquals[int](int,int) [Tier0, IL size=5, code size=34] 30: JIT compiled System.Threading.Thread:GetThreadStaticsBase() [Tier0, IL size=18, code size=24]I guess these [int,int] in fact are cross-module (SPC-System.Net.Sockets) enums.
It's not clear whyIPAddressis not prejitted but it's not VectorT relatedSuch static Dictionary initializations lead to a slow cctor with tons of Add() calls.
It's not the first time I see this problem, perhaps, we can do something for it e.g. on the Roslyn side?I am not sure what can be done about this on Roslyn side. It is part of the Linq family of convenience features that are known to have less than ideal performance characteristics.
This specific case should better be a switch statement: #120364
It's not clear why IPAddress is not prejitted but it's not VectorT related
My guess is that the SIMD intrinsics use in
ReadUInt16NumbersFromBytesderails use of R2R code. We seem to be more defensive than we need to be. I think it may be worth opening issue about this since this does not appear to be one-off problem.I'm not sure it's worth creating an issue
We may want to create a user issue to track all startup improvement issues.
System.RuntimeType+IGenericCacheEntry`
This looks like a bug in prejiting interface static methods.
(dynamicClass):InvokeStub_EventSourceAttribute
This know issue that was expected to be fixed by #115345
IsAsciiCasingSameAsInvariant is unconditionally "true" for invariant operations like this
Ok, I have missed that. If it the case, we may be able to short-circuit ICU loading by duplicating TextInfo.ToUpperInvariant into string.ToUpperInvariant. I am not sure whether it is worth the trouble...
My guess is that the SIMD intrinsics use in ReadUInt16NumbersFromBytes derails use of R2R code. We seem to be more defensive than we need to be. I think it may be worth opening issue about this since this does not appear to be one-off problem.
Filed #120367 with a minimal repro
I think it is more interesting to figure out what needs to happen to generate this guid at build time.
Something like
[GeneratedEventSource]which would generate GUID object at build-time, like[GeneratedRegex]andEnvironment.Version? 🙂Something like [GeneratedEventSource] which would generate GUID object at build-time, like [GeneratedRegex] and Environment.Version?
#28290 has discussion about it. I think would need to a combination of a new public API and a source generator.
Reacted by Paulus Pärssinen- locked and limited conversation to collaborators
on Nov 3, 2025

When I was looking at #120288 rerpo which is just a simple console app with some Socket server & listener, I noticed a huge chunk of time is spent in
NetEventSource::.cctor(Linux-x64 and I run the app withoutdotnet-traceor any env.vars). In that cctor most of the time is spent insideEventSource.GetGuidthat is obtaining custom attributes (presumably over this type)Here is the GetGuid impl:
runtime/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
Lines 367 to 379 in a2dc727
Is this something we can avoid "GetCustomAttributes" for and replace with some static map for BCL types?
PS: this is not the root cause of #120288