Open AndyAyersMS opened 1 year ago
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis See info in area-owners.md if you want to be subscribed.
Author: | AndyAyersMS |
---|---|
Assignees: | - |
Labels: | `area-System.Text.Json` |
Milestone: | - |
cc @EgorBo
While looking at dumps for #85349 I've noticed that a lot of autoproperties weren't inlined in System.Text.Json, would it make sense to always inline really small methods like autoproperties and maybe not count them into the inliner budget?
While looking at dumps for #85349 I've noticed that a lot of autoproperties weren't inlined in System.Text.Json, would it make sense to always inline really small methods like autoproperties and maybe not count them into the inliner budget?
Can you give a more specific example?
Really small methods should already be bypassing budget checks.
Can you give a more specific example?
Here, note all the set_
calls. Since that PR let the jit inline more, a few of those were inlined and turned into a single mov
like this:
These look small in C#, but can you verify they're small in IL?
These look small in C#, but can you verify they're small in IL?
Well they're autoproperties, won't those be always compiled as ldarg.0+ldfld
/ldarg.0+ldarg.1+stfld
?
These look small in C#, but can you verify they're small in IL?
Well they're autoproperties, won't those be always compiled as
ldarg.0+ldfld
/ldarg.0+ldarg.1+stfld
?
I don't know about always, but it looks like these are indeed small:
.method public hidebysig specialname instance void modreq([System.Runtime]System.Runtime.CompilerServices.IsExternalInit)
set_IsPublic(bool 'value') cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld bool class System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues`1<!T>::'<IsPublic>k__BackingField'
IL_0007: ret
} // end of method JsonPropertyInfoValues`1::set_IsPublic
Now, do you know for sure why these didn't get inlined?
I guess when we run out of budget (or too many locals?) we give up even on "below ALWAYS_INLINE" stuff
Now, do you know for sure why these didn't get inlined?
I haven't checked thoroughly, but the change from the PR made the assignments to delegate typed properties take less of the budget, so that's why I assume it's more budget being available that let it inline more.
Now, do you know for sure why these didn't get inlined?
I haven't checked thoroughly, but the change from the PR made the assignments to delegate typed properties take less of the budget, so that's why I assume it's more budget being available that let it inline more.
I think it's more likely that we hit the local var limit, and since your change creates fewer local vars, we can inline more.
The only way to know for sure is to look at the jit dump or at least the inline summary tree.
Call graph for GetByte
benchmark:
Inlines into Program+Perf_Get:GetByte():ubyte:this:
[INLINED: below ALWAYS_INLINE size] System.ReadOnlySpan`1[ubyte]:op_Implicit(ubyte[]):System.ReadOnlySpan`1[ubyte]
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ubyte]:.ctor(ubyte[]):this
[INLINED: below ALWAYS_INLINE size] System.Text.Json.Utf8JsonReader:.ctor(System.ReadOnlySpan`1[ubyte],System.Text.Json.JsonReaderOptions):this
[INLINED: profitable inline] System.Text.Json.JsonReaderState:.ctor(System.Text.Json.JsonReaderOptions):this
[FAILED: too many il bytes] System.Text.Json.Utf8JsonReader:.ctor(System.ReadOnlySpan`1[ubyte],bool,System.Text.Json.JsonReaderState):this
[INLINED: profitable inline] System.Text.Json.Utf8JsonReader:Read():bool:this
[INLINED: profitable inline] System.Text.Json.Utf8JsonReader:ReadSingleSegment():bool:this
[INLINED: below ALWAYS_INLINE size] System.Text.Json.Utf8JsonReader:set_ValueSpan(System.ReadOnlySpan`1[ubyte]):this
[INLINED: below ALWAYS_INLINE size] System.Text.Json.Utf8JsonReader:set_ValueIsEscaped(bool):this
[INLINED: aggressive inline attribute] System.Text.Json.Utf8JsonReader:HasMoreData():bool:this
[FAILED: unprofitable inline] System.Text.Json.Utf8JsonReader:get_IsLastSpan():bool:this
[INLINED: below ALWAYS_INLINE size] System.Text.Json.BitStack:get_CurrentDepth():int:this
[FAILED: does not return] System.Text.Json.ThrowHelper:ThrowJsonReaderException(byref,int,ubyte,System.ReadOnlySpan`1[ubyte])
[INLINED: below ALWAYS_INLINE size] System.Text.Json.JsonReaderOptions:get_CommentHandling():ubyte:this
[FAILED: does not return] System.Text.Json.ThrowHelper:ThrowJsonReaderException(byref,int,ubyte,System.ReadOnlySpan`1[ubyte])
[FAILED: unprofitable inline] System.Text.Json.Utf8JsonReader:SkipWhiteSpace():this
[INLINED: aggressive inline attribute] System.Text.Json.Utf8JsonReader:HasMoreData():bool:this
[FAILED: unprofitable inline] System.Text.Json.Utf8JsonReader:get_IsLastSpan():bool:this
[INLINED: below ALWAYS_INLINE size] System.Text.Json.BitStack:get_CurrentDepth():int:this
[FAILED: does not return] System.Text.Json.ThrowHelper:ThrowJsonReaderException(byref,int,ubyte,System.ReadOnlySpan`1[ubyte])
[INLINED: below ALWAYS_INLINE size] System.Text.Json.JsonReaderOptions:get_CommentHandling():ubyte:this
[FAILED: does not return] System.Text.Json.ThrowHelper:ThrowJsonReaderException(byref,int,ubyte,System.ReadOnlySpan`1[ubyte])
[INLINED: below ALWAYS_INLINE size] System.Text.Json.Utf8JsonReader:set_TokenStartIndex(long):this
[FAILED: unprofitable inline] System.Text.Json.Utf8JsonReader:ConsumeNextTokenOrRollback(ubyte):bool:this
[FAILED: unprofitable inline] System.Text.Json.Utf8JsonReader:EndObject():this
[FAILED: does not return] System.Text.Json.ThrowHelper:ThrowJsonReaderException(byref,int,ubyte,System.ReadOnlySpan`1[ubyte])
[FAILED: unprofitable inline] System.Text.Json.Utf8JsonReader:ConsumePropertyName():bool:this
[FAILED: unprofitable inline] System.Text.Json.Utf8JsonReader:EndArray():this
[FAILED: unprofitable inline] System.Text.Json.Utf8JsonReader:ConsumeValue(ubyte):bool:this
[FAILED: unprofitable inline] System.Text.Json.Utf8JsonReader:ConsumeValue(ubyte):bool:this
[FAILED: unprofitable inline] System.Text.Json.Utf8JsonReader:ConsumeNextTokenOrRollback(ubyte):bool:this
[INLINED: profitable inline] System.Text.Json.Utf8JsonReader:ReadFirstToken(ubyte):bool:this
[INLINED: profitable inline] System.Text.Json.BitStack:SetFirstBit():this
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ubyte]:Slice(int,int):System.ReadOnlySpan`1[ubyte]:this
[FAILED: does not return] System.ThrowHelper:ThrowArgumentOutOfRangeException()
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ubyte]:.ctor(byref,int):this
[FAILED: unprofitable inline] System.Diagnostics.Debug:Assert(bool)
[INLINED: below ALWAYS_INLINE size] System.Text.Json.Utf8JsonReader:set_ValueSpan(System.ReadOnlySpan`1[ubyte]):this
[INLINED: profitable inline] System.Text.Json.BitStack:ResetFirstBit():this
[FAILED: inline exceeds budget] System.ReadOnlySpan`1[ubyte]:Slice(int,int):System.ReadOnlySpan`1[ubyte]:this
[INLINED: below ALWAYS_INLINE size] System.Text.Json.Utf8JsonReader:set_ValueSpan(System.ReadOnlySpan`1[ubyte]):this
[INLINED: below ALWAYS_INLINE size] System.Text.Json.JsonHelpers:IsDigit(ubyte):bool
[FAILED: inline exceeds budget] System.ReadOnlySpan`1[ubyte]:Slice(int):System.ReadOnlySpan`1[ubyte]:this
[FAILED: inline exceeds budget] System.Text.Json.Utf8JsonReader:TryGetNumber(System.ReadOnlySpan`1[ubyte],byref):bool:this
[FAILED: inline exceeds budget] System.Text.Json.Utf8JsonReader:ConsumeValue(ubyte):bool:this
[FAILED: inline exceeds budget] System.Text.Json.Utf8JsonReader:ReadMultiSegment():bool:this
[INLINED: below ALWAYS_INLINE size] System.Text.Json.Utf8JsonReader:get_TokenType():ubyte:this
[FAILED: does not return] System.Text.Json.ThrowHelper:ThrowJsonReaderException(byref,int,ubyte,System.ReadOnlySpan`1[ubyte])
[INLINED: profitable inline] System.Text.Json.Utf8JsonReader:GetByte():ubyte:this
[INLINED: profitable inline] System.Text.Json.Utf8JsonReader:TryGetByte(byref):bool:this
[FAILED: inline exceeds budget] System.Text.Json.Utf8JsonReader:get_TokenType():ubyte:this
[FAILED: inline exceeds budget] System.Text.Json.Utf8JsonReader:get_TokenType():ubyte:this
[FAILED: inline exceeds budget] System.Text.Json.ThrowHelper:ThrowInvalidOperationException_ExpectedNumber(ubyte)
[FAILED: inline exceeds budget] System.Text.Json.Utf8JsonReader:get_HasValueSequence():bool:this
[FAILED: inline exceeds budget] System.Text.Json.Utf8JsonReader:get_ValueSpan():System.ReadOnlySpan`1[ubyte]:this
[FAILED: inline exceeds budget] System.Text.Json.Utf8JsonReader:get_ValueSequence():System.Buffers.ReadOnlySequence`1[ubyte]:this
[FAILED: inline exceeds budget] System.Buffers.BuffersExtensions:ToArray[ubyte](byref):ubyte[]
[FAILED: inline exceeds budget] System.ReadOnlySpan`1[ubyte]:op_Implicit(ubyte[]):System.ReadOnlySpan`1[ubyte]
[FAILED: inline exceeds budget] System.Text.Json.Utf8JsonReader:TryGetByteCore(byref,System.ReadOnlySpan`1[ubyte]):bool
[FAILED: inline exceeds budget] System.Text.Json.ThrowHelper:ThrowFormatException(int)
Tested the 1P web service we usually test:
Default mode: 40 "exceeds budget" decisions, among them in BCL:
System.Reflection.RuntimeAssembly:GetType(System.String,bool,bool)
System.Type:GetType(System.String)
System.Type:GetType(System.String)
System.Reflection.TypeNameParser:GetType(System.String,System.Reflection.Assembly,bool,bool)
System.Enum:TryParse[int](System.String,byref)
(these are root methods where some of their inlinees refused to inlined due to the budge thing)
PGO=1: 2350 "exceeds budget" decisions or ~60X more than in the no-PGO mode.
I tried to play with various knobs, e.g. limitted the max IL size for PGO mode (it helped but still a lot), tried to play with various benefit multipliers trying to add additional friction for inlining in big methods (or of big inlinees) - didn't help.
The only simple thing we can do is just to bump the budget now, proper changes definitely require a lot of re-thinking E.g. this change: https://github.com/EgorBo/runtime-1/commit/bb4deca3ded19a69492b1fb09edc7e602c90a7b3 reduced number of "exceeds budget" decisions to 202 (5X more than non-PGO mode instead of 60X).
I changed EstimateRootTime
to return a fixed constant because we used calculate our time budget based on current root's method size. Also, slightly decreased the estimated time budget for callees.
Tested a couple of apps and didn't notice startup regressions from this change.
UPD: I probably overdramatized the numbers, once we hit an "exceed budget" problem we start label all callees with it in the current root, even those we would never inline anyway. So the real number of inlinees we should have inlined but we didn't is way lower.
cc @AndyAyersMS
https://github.com/dotnet/runtime/pull/85322 @stephentoub e.g. this change seems to regressed guid parsing with PGO. A rarely taken path (I assume we can say that for the hex guid format) was marked as always inline: Actually, I might be wrong, I don't see HexsToChars
here. But still, Guid parsing hits the problem too:
Inlines into System.Guid:TryParseGuid(System.ReadOnlySpan`1[ushort],byref):bool:
[INLINED: aggressive inline attribute] System.MemoryExtensions:Trim(System.ReadOnlySpan`1[ushort]):System.ReadOnlySpan`1[ushort]
[INLINED: profitable inline] System.Char:IsWhiteSpace(ushort):bool
[INLINED: profitable inline] System.Char:IsLatin1(ushort):bool
[INLINED: below ALWAYS_INLINE size] System.Char:get_Latin1CharInfo():System.ReadOnlySpan`1[ubyte]
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ubyte]:.ctor(ulong,int):this
[INLINED: below ALWAYS_INLINE size] System.Runtime.CompilerServices.RuntimeHelpers:IsReferenceOrContainsReferences[ubyte]():bool
[FAILED: unprofitable inline] System.ThrowHelper:ThrowInvalidTypeWithPointersNotSupported(System.Type)
[INLINED: profitable inline] System.Char:IsWhiteSpaceLatin1(ushort):bool
[INLINED: profitable inline] System.Char:IsLatin1(ushort):bool
[INLINED: below ALWAYS_INLINE size] System.Char:get_Latin1CharInfo():System.ReadOnlySpan`1[ubyte]
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ubyte]:.ctor(ulong,int):this
[INLINED: below ALWAYS_INLINE size] System.Runtime.CompilerServices.RuntimeHelpers:IsReferenceOrContainsReferences[ubyte]():bool
[FAILED: unprofitable inline] System.ThrowHelper:ThrowInvalidTypeWithPointersNotSupported(System.Type)
[INLINED: profitable inline] System.Diagnostics.Debug:Assert(bool)
[INLINED: below ALWAYS_INLINE size] System.Diagnostics.Debug:Assert(bool,System.String,System.String)
[FAILED: noinline per IL/cached result] System.Diagnostics.Debug:Fail(System.String,System.String)
[INLINED: below ALWAYS_INLINE size] System.Char:get_Latin1CharInfo():System.ReadOnlySpan`1[ubyte]
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ubyte]:.ctor(ulong,int):this
[INLINED: below ALWAYS_INLINE size] System.Runtime.CompilerServices.RuntimeHelpers:IsReferenceOrContainsReferences[ubyte]():bool
[FAILED: unprofitable inline] System.ThrowHelper:ThrowInvalidTypeWithPointersNotSupported(System.Type)
[FAILED: unprofitable inline] System.Globalization.CharUnicodeInfo:GetIsWhiteSpace(ushort):bool
[INLINED: profitable inline] System.Char:IsWhiteSpace(ushort):bool
[INLINED: profitable inline] System.Char:IsLatin1(ushort):bool
[INLINED: below ALWAYS_INLINE size] System.Char:get_Latin1CharInfo():System.ReadOnlySpan`1[ubyte]
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ubyte]:.ctor(ulong,int):this
[INLINED: below ALWAYS_INLINE size] System.Runtime.CompilerServices.RuntimeHelpers:IsReferenceOrContainsReferences[ubyte]():bool
[FAILED: unprofitable inline] System.ThrowHelper:ThrowInvalidTypeWithPointersNotSupported(System.Type)
[INLINED: profitable inline] System.Char:IsWhiteSpaceLatin1(ushort):bool
[INLINED: profitable inline] System.Char:IsLatin1(ushort):bool
[INLINED: below ALWAYS_INLINE size] System.Char:get_Latin1CharInfo():System.ReadOnlySpan`1[ubyte]
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ubyte]:.ctor(ulong,int):this
[INLINED: below ALWAYS_INLINE size] System.Runtime.CompilerServices.RuntimeHelpers:IsReferenceOrContainsReferences[ubyte]():bool
[FAILED: unprofitable inline] System.ThrowHelper:ThrowInvalidTypeWithPointersNotSupported(System.Type)
[INLINED: profitable inline] System.Diagnostics.Debug:Assert(bool)
[INLINED: below ALWAYS_INLINE size] System.Diagnostics.Debug:Assert(bool,System.String,System.String)
[FAILED: noinline per IL/cached result] System.Diagnostics.Debug:Fail(System.String,System.String)
[INLINED: below ALWAYS_INLINE size] System.Char:get_Latin1CharInfo():System.ReadOnlySpan`1[ubyte]
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ubyte]:.ctor(ulong,int):this
[INLINED: below ALWAYS_INLINE size] System.Runtime.CompilerServices.RuntimeHelpers:IsReferenceOrContainsReferences[ubyte]():bool
[FAILED: unprofitable inline] System.ThrowHelper:ThrowInvalidTypeWithPointersNotSupported(System.Type)
[FAILED: unprofitable inline] System.Globalization.CharUnicodeInfo:GetIsWhiteSpace(ushort):bool
[FAILED: noinline per IL/cached result] System.MemoryExtensions:<Trim>g__TrimFallback|194_0(System.ReadOnlySpan`1[ushort]):System.ReadOnlySpan`1[ushort]
[FAILED: unprofitable inline] System.Guid+GuidResult:SetFailure(int):this
[FAILED: unprofitable inline] System.Guid:TryParseExactP(System.ReadOnlySpan`1[ushort],byref):bool
[FAILED: unprofitable inline] System.Guid:TryParseExactX(System.ReadOnlySpan`1[ushort],byref):bool
[INLINED: profitable inline] System.Guid:TryParseExactB(System.ReadOnlySpan`1[ushort],byref):bool
[FAILED: unprofitable inline] System.Guid+GuidResult:SetFailure(int):this
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ushort]:Slice(int,int):System.ReadOnlySpan`1[ushort]:this
[FAILED: does not return] System.ThrowHelper:ThrowArgumentOutOfRangeException()
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ushort]:.ctor(byref,int):this
[INLINED: profitable inline] System.Diagnostics.Debug:Assert(bool)
[INLINED: below ALWAYS_INLINE size] System.Diagnostics.Debug:Assert(bool,System.String,System.String)
[INLINED: profitable inline] System.Guid:TryParseExactD(System.ReadOnlySpan`1[ushort],byref):bool
[FAILED: unprofitable inline] System.Guid+GuidResult:SetFailure(int):this
[INLINED: aggressive inline attribute] System.Span`1[System.Guid+GuidResult]:.ctor(byref):this
[INLINED: aggressive inline attribute] System.Runtime.InteropServices.MemoryMarshal:AsBytes[System.Guid+GuidResult](System.Span`1[System.Guid+GuidResult]):System.Span`1[ubyte]
[INLINED: below ALWAYS_INLINE size] System.Runtime.CompilerServices.RuntimeHelpers:IsReferenceOrContainsReferences[System.Guid+GuidResult]():bool
[FAILED: unprofitable inline] System.ThrowHelper:ThrowInvalidTypeWithPointersNotSupported(System.Type)
[INLINED: below ALWAYS_INLINE size] System.Runtime.InteropServices.MemoryMarshal:GetReference[System.Guid+GuidResult](System.Span`1[System.Guid+GuidResult]):byref
[INLINED: aggressive inline attribute] System.Span`1[ubyte]:.ctor(byref,int):this
[INLINED: profitable inline] System.Diagnostics.Debug:Assert(bool)
[INLINED: below ALWAYS_INLINE size] System.Diagnostics.Debug:Assert(bool,System.String,System.String)
[FAILED: noinline per IL/cached result] System.Diagnostics.Debug:Fail(System.String,System.String)
[INLINED: aggressive inline attribute] System.Guid:DecodeByte(ulong,ulong,byref):ubyte
[INLINED: below ALWAYS_INLINE size] System.HexConverter:get_CharToHexLookup():System.ReadOnlySpan`1[ubyte]
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ubyte]:.ctor(ulong,int):this
[INLINED: below ALWAYS_INLINE size] System.Runtime.CompilerServices.RuntimeHelpers:IsReferenceOrContainsReferences[ubyte]():bool
[FAILED: unprofitable inline] System.ThrowHelper:ThrowInvalidTypeWithPointersNotSupported(System.Type)
[INLINED: below ALWAYS_INLINE size] System.Runtime.InteropServices.MemoryMarshal:GetReference[ubyte](System.ReadOnlySpan`1[ubyte]):byref
[INLINED: below ALWAYS_INLINE size] System.Runtime.InteropServices.MemoryMarshal:GetReference[ubyte](System.ReadOnlySpan`1[ubyte]):byref
[INLINED: aggressive inline attribute] System.Guid:DecodeByte(ulong,ulong,byref):ubyte
[INLINED: below ALWAYS_INLINE size] System.HexConverter:get_CharToHexLookup():System.ReadOnlySpan`1[ubyte]
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ubyte]:.ctor(ulong,int):this
[INLINED: below ALWAYS_INLINE size] System.Runtime.CompilerServices.RuntimeHelpers:IsReferenceOrContainsReferences[ubyte]():bool
[FAILED: unprofitable inline] System.ThrowHelper:ThrowInvalidTypeWithPointersNotSupported(System.Type)
[INLINED: below ALWAYS_INLINE size] System.Runtime.InteropServices.MemoryMarshal:GetReference[ubyte](System.ReadOnlySpan`1[ubyte]):byref
[INLINED: below ALWAYS_INLINE size] System.Runtime.InteropServices.MemoryMarshal:GetReference[ubyte](System.ReadOnlySpan`1[ubyte]):byref
[INLINED: aggressive inline attribute] System.Guid:DecodeByte(ulong,ulong,byref):ubyte
[INLINED: below ALWAYS_INLINE size] System.HexConverter:get_CharToHexLookup():System.ReadOnlySpan`1[ubyte]
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ubyte]:.ctor(ulong,int):this
[INLINED: below ALWAYS_INLINE size] System.Runtime.CompilerServices.RuntimeHelpers:IsReferenceOrContainsReferences[ubyte]():bool
[FAILED: unprofitable inline] System.ThrowHelper:ThrowInvalidTypeWithPointersNotSupported(System.Type)
[INLINED: below ALWAYS_INLINE size] System.Runtime.InteropServices.MemoryMarshal:GetReference[ubyte](System.ReadOnlySpan`1[ubyte]):byref
[INLINED: below ALWAYS_INLINE size] System.Runtime.InteropServices.MemoryMarshal:GetReference[ubyte](System.ReadOnlySpan`1[ubyte]):byref
[INLINED: aggressive inline attribute] System.Guid:DecodeByte(ulong,ulong,byref):ubyte
[INLINED: below ALWAYS_INLINE size] System.HexConverter:get_CharToHexLookup():System.ReadOnlySpan`1[ubyte]
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ubyte]:.ctor(ulong,int):this
[INLINED: below ALWAYS_INLINE size] System.Runtime.CompilerServices.RuntimeHelpers:IsReferenceOrContainsReferences[ubyte]():bool
[FAILED: unprofitable inline] System.ThrowHelper:ThrowInvalidTypeWithPointersNotSupported(System.Type)
[INLINED: below ALWAYS_INLINE size] System.Runtime.InteropServices.MemoryMarshal:GetReference[ubyte](System.ReadOnlySpan`1[ubyte]):byref
[INLINED: below ALWAYS_INLINE size] System.Runtime.InteropServices.MemoryMarshal:GetReference[ubyte](System.ReadOnlySpan`1[ubyte]):byref
[INLINED: aggressive inline attribute] System.Guid:DecodeByte(ulong,ulong,byref):ubyte
[INLINED: below ALWAYS_INLINE size] System.HexConverter:get_CharToHexLookup():System.ReadOnlySpan`1[ubyte]
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ubyte]:.ctor(ulong,int):this
[INLINED: below ALWAYS_INLINE size] System.Runtime.CompilerServices.RuntimeHelpers:IsReferenceOrContainsReferences[ubyte]():bool
[FAILED: unprofitable inline] System.ThrowHelper:ThrowInvalidTypeWithPointersNotSupported(System.Type)
[INLINED: below ALWAYS_INLINE size] System.Runtime.InteropServices.MemoryMarshal:GetReference[ubyte](System.ReadOnlySpan`1[ubyte]):byref
[INLINED: below ALWAYS_INLINE size] System.Runtime.InteropServices.MemoryMarshal:GetReference[ubyte](System.ReadOnlySpan`1[ubyte]):byref
[INLINED: aggressive inline attribute] System.Guid:DecodeByte(ulong,ulong,byref):ubyte
[INLINED: below ALWAYS_INLINE size] System.HexConverter:get_CharToHexLookup():System.ReadOnlySpan`1[ubyte]
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ubyte]:.ctor(ulong,int):this
[INLINED: below ALWAYS_INLINE size] System.Runtime.CompilerServices.RuntimeHelpers:IsReferenceOrContainsReferences[ubyte]():bool
[FAILED: unprofitable inline] System.ThrowHelper:ThrowInvalidTypeWithPointersNotSupported(System.Type)
[INLINED: below ALWAYS_INLINE size] System.Runtime.InteropServices.MemoryMarshal:GetReference[ubyte](System.ReadOnlySpan`1[ubyte]):byref
[INLINED: below ALWAYS_INLINE size] System.Runtime.InteropServices.MemoryMarshal:GetReference[ubyte](System.ReadOnlySpan`1[ubyte]):byref
[INLINED: aggressive inline attribute] System.Guid:DecodeByte(ulong,ulong,byref):ubyte
[INLINED: below ALWAYS_INLINE size] System.HexConverter:get_CharToHexLookup():System.ReadOnlySpan`1[ubyte]
[INLINED: aggressive inline attribute] System.ReadOnlySpan`1[ubyte]:.ctor(ulong,int):this
[FAILED: inline exceeds budget] System.Runtime.CompilerServices.RuntimeHelpers:IsReferenceOrContainsReferences[ubyte]():bool
[FAILED: inline exceeds budget] System.ThrowHelper:ThrowInvalidTypeWithPointersNotSupported(System.Type)
[FAILED: inline exceeds budget] System.Runtime.InteropServices.MemoryMarshal:GetReference[ubyte](System.ReadOnlySpan`1[ubyte]):byref
[FAILED: inline exceeds budget] System.Runtime.InteropServices.MemoryMarshal:GetReference[ubyte](System.ReadOnlySpan`1[ubyte]):byref
[FAILED: inline exceeds budget] System.Guid:DecodeByte(ulong,ulong,byref):ubyte
[FAILED: inline exceeds budget] System.Guid:DecodeByte(ulong,ulong,byref):ubyte
[FAILED: inline exceeds budget] System.Guid:DecodeByte(ulong,ulong,byref):ubyte
[FAILED: inline exceeds budget] System.Guid:DecodeByte(ulong,ulong,byref):ubyte
[FAILED: inline exceeds budget] System.Guid:DecodeByte(ulong,ulong,byref):ubyte
[FAILED: inline exceeds budget] System.Guid:DecodeByte(ulong,ulong,byref):ubyte
[FAILED: inline exceeds budget] System.Guid:DecodeByte(ulong,ulong,byref):ubyte
[FAILED: inline exceeds budget] System.Guid:DecodeByte(ulong,ulong,byref):ubyte
[FAILED: inline exceeds budget] System.Guid:DecodeByte(ulong,ulong,byref):ubyte
[FAILED: inline exceeds budget] System.MemoryExtensions:IndexOfAny[ushort](System.ReadOnlySpan`1[ushort],ushort,ushort,ushort):int
[FAILED: inline exceeds budget] System.Guid:<TryParseExactD>g__TryCompatParsing|31_0(System.ReadOnlySpan`1[ushort],byref):bool
[FAILED: inline exceeds budget] System.Guid+GuidResult:SetFailure(int):this
[FAILED: inline exceeds budget] System.Guid:TryParseExactN(System.ReadOnlySpan`1[ushort],byref):bool
[FAILED: inline exceeds budget] System.Guid:TryParseExactD(System.ReadOnlySpan`1[ushort],byref):bool
One thing I noticed that methods with [Intrinsic]
and a default implementation (in case if intrinsic is not expanded) may eat budget as well despite being imported as intrinsic.
Moving to 9.0 as it's probably too late to land invasive changes for this
Moving to 10.0 since any changes here potentially have too risky impact
See https://github.com/dotnet/runtime/issues/84264 for context
A number of microbenchmarks—particularly those under
System.Text.Json
—run out of budget when run with TieredPGO.Suggest that we review RWC/SPMI to see how often this thing comes up outside of microbenchmarks.
Possible fixes
AggressiveInlining
inSystem.Text.Json
(if these cases are all json related)