Consider wrapping throw in call to encourage JITter
Opened this issue ยท 3 comments
NIT/Future: Consider wrapping throw in call to encourage JITter.
Originally posted by @to11mtm in #303 (comment)
So, to elaborate here... Apologies, priorities abound...
In general we should, when throwing in potentially hot methods, prefer to call a ThrowHelper()
instead of throwing.
As a very good example
the fact we are throwing actually causes a number of optimizations to not happen and can also impact inline ability.
An example refactoring would be:
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int GetInt32(ReadOnlySpan<byte> span)
{
if (!Utf8Parser.TryParse(span, out int value, out var consumed))
{
ThrowOnUtf8ParseFail();
}
return value;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ThrowOnUtf8ParseFail()
{
throw new Exception();
}
Further Docs and explanation of potential value for perf: (FWIW these are from CommunityToolkit's Diagnostic analyzer docs, so we could, if we wanted, add as an analyzer to help identify across projects[0])
https://learn.microsoft.com/en-us/dotnet/communitytoolkit/diagnostics/throwhelper#technical-details
We probably should have some form of:
internal static class ThrowHelpers
{
//example, add others to taste
[MethodImpl(MethodImplOptions.NoInlining)] //may be too paranoid
public void ThrowNatsException(string message)
{
throw new NatsException(message);
}
}
And use that when throwing on hot paths/etc.
[0] - I think that analyzer will only really work if we take CommunityToolKit
as a dependency and we want to stay lean, so probably not for now.
Makes sense. Also runtime libs are always using this. We could start with read/write loops maybe?