-
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
Add fast path to MemoryExtensions.Trim for input that needs no trimming #84210
Conversation
…invalid data parsing
It's often the case that trim is used when no trimming is actually needed. Is there a way to fix this in trim instead by prioritizing that use case? |
Good point, e.g. rewrite [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpan<char> Trim(this ReadOnlySpan<char> span)
{
// Assume that in the most cases input doesn't need trimming
if (span.Length == 0 ||
(span.Length > 0 && !char.IsWhiteSpace(span[0]) && !char.IsWhiteSpace(span[span.Length - 1])))
{
return span;
}
return TrimFallback(span);
[MethodImpl(MethodImplOptions.NoInlining)]
static ReadOnlySpan<char> TrimFallback(ReadOnlySpan<char> span)
{
int start = 0;
for (; start < span.Length; start++)
{
if (!char.IsWhiteSpace(span[start]))
{
break;
}
}
int end = span.Length - 1;
for (; end > start; end--)
{
if (!char.IsWhiteSpace(span[end]))
{
break;
}
}
return span.Slice(start, end - start + 1);
}
} |
@stephentoub done, it seems to even improve benchmark results. Do I need to do the same for TrimStart/TrimEnd or those are fine and rarely used? |
src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.Trim.cs
Outdated
Show resolved
Hide resolved
…ns.Trim.cs Co-authored-by: Stephen Toub <[email protected]>
src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.Trim.cs
Outdated
Show resolved
Hide resolved
I think we can leave those alone for now. They're used much less, and the one hot path I know about in our own code is already guarded. |
src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.Trim.cs
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.Trim.cs
Show resolved
Hide resolved
break; | ||
} | ||
} | ||
return span.Slice(start, end - start + 1); |
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.
Why not use the clamp helpers in the fallback?
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.
Since we add an additional overhead for cases when input does contain whitespaces I decided to have a slightly faster fallback (inlined clamp helpers) - didn't want to mark the helpers always-inlineable. Can revert to clamp helpers if you think an extra 1ns is not worth it
Co-authored-by: Stephen Toub <[email protected]>
Profiler states that majority of time during
Guid.Parse
is spent inside.Trim()
and it seems that if we can trade around 1% of perf for inputs with trailing/leading whitespaces we can get up to 45% boost for other cases, e.g.:Another mystery is why B format is faster than N (reproduces accross multiple runs)
PS: grep.app for Guid.Parse with constant input: https://grep.app/search?q=Guid.Parse%28%22&filter[lang][0]=C%23 (unlikely on hot path but anyway)