Use IndexOfAnyWhiteSpace in Guid.EatAllWhitespace#127123
Conversation
…helpers Replace manual for-loops that scan for whitespace/non-whitespace characters with calls to IndexOfAnyWhiteSpace, IndexOfAnyExceptWhiteSpace, LastIndexOfAnyExceptWhiteSpace, which use vectorized SearchValues internally. Changed: - MemoryExtensions.IsWhiteSpace - MemoryExtensions.Trim/TrimStart/TrimEnd (ReadOnlySpan and Span overloads) - MemoryExtensions.ClampStart/ClampEnd - MemoryExtensions.TrimSplitEntry - String.IsNullOrWhiteSpace - String.TrimWhiteSpaceHelper - String.MakeSeparatorListAny (whitespace case) - Guid.EatAllWhitespace - StringSegment.TrimStart/TrimEnd Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/41ef7392-01aa-4cd7-8f27-9439896279e3 Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Keep only the IndexOfAnyWhiteSpace change in Guid.EatAllWhitespace, reverting all other replacements as requested. Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/2e3e7d3b-f6ce-480c-a749-c51bd5124c9f Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
|
Tagging subscribers to this area: @dotnet/area-system-memory |
|
This seems like one of the only places where using a vectorized helper should be a perf improvement. |
|
@copilot Use the benchmark skill to test the impact of this change to Guid parsing |
Note This comment was generated by Copilot. @EgorBot -linux_amd -osx_arm64 using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);
[MemoryDiagnoser]
public class Bench
{
private string _noWhitespace;
private string _withWhitespace;
private string _dFormat;
[GlobalSetup]
public void Setup()
{
var guid = Guid.NewGuid();
// X format: {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
_noWhitespace = guid.ToString("X");
// Same but with whitespace scattered throughout (EatAllWhitespace must strip it)
_withWhitespace = " " + _noWhitespace.Insert(10, " ").Insert(20, " ") + " ";
// D format for comparison (doesn't use EatAllWhitespace)
_dFormat = guid.ToString("D");
}
[Benchmark]
public Guid ParseExactX_NoWhitespace() => Guid.ParseExact(_noWhitespace, "X");
[Benchmark]
public Guid ParseExactX_WithWhitespace() => Guid.ParseExact(_withWhitespace, "X");
[Benchmark(Baseline = true)]
public Guid ParseExactD() => Guid.ParseExact(_dFormat, "D");
} |
There was a problem hiding this comment.
Pull request overview
This PR updates Guid.EatAllWhitespace to use the newer vectorized MemoryExtensions.IndexOfAnyWhiteSpace helper (introduced in #111439) instead of a manual loop when scanning ReadOnlySpan<char> for the first whitespace.
Changes:
- Replace manual whitespace scan loop with
IndexOfAnyWhiteSpace()in thecharfast-path. - Update the “no whitespace found” check to use
i < 0(theIndexOf*not-found convention).
|
@copilot, benchmark results are ready: Please analyze the results and act accordingly. |
macOS ARM64 (Apple M4) results:
The fast path (no whitespace) sees a ~30% improvement from vectorized The The linux_amd run timed out (infrastructure issue, not related to the change). Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
Description
Replace the manual
forloop scanning for whitespace inGuid.EatAllWhitespacewith the new vectorizedIndexOfAnyWhiteSpacehelper added in #111439.