Conversation
|
Tagging subscribers to this area: @dotnet/area-system-runtime |
There was a problem hiding this comment.
Pull request overview
Optimizes Guid formatting by streamlining the default ToString path and adding an AVX-512 VBMI+VL vectorized implementation for fast hex formatting, with related tweaks in Utf8Formatter for Guid.
Changes:
- Reworks
Guid.ToString/TryFormatCoreto use a flags-based fast path and adds an AVX-512 VBMI+VL implementation for D/N/B/P formats. - Refactors
Guidcomparison operators /CompareToto use unsigned comparisons for_b/_cand a big-endianulongcompare for the trailing bytes. - Updates
Utf8Formatter.TryFormat(Guid, ...)to compute and pass the newGuidformatting flags directly.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/libraries/System.Private.CoreLib/src/System/Guid.cs | Adds new vectorized formatting path and adjusts comparison logic and ToString fast path to use flags-based formatting. |
| src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Guid.cs | Updates Utf8Formatter’s Guid formatting to use flags directly and streamline default-format handling. |
You can also share your feedback on Copilot code review. Take the survey.
| int flags = format.Symbol; | ||
| if (flags is '\0' or 'D') | ||
| { | ||
| case 'D': // nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn | ||
| flags = 36 + Guid.TryFormatFlags_UseDashes; | ||
| break; | ||
|
|
||
| case 'B': // {nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn} | ||
| flags = 38 + Guid.TryFormatFlags_UseDashes + Guid.TryFormatFlags_CurlyBraces; | ||
| break; | ||
| // nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn | ||
| flags = 36 + Guid.TryFormatFlags_UseDashes; | ||
| } |
There was a problem hiding this comment.
Utf8Formatter.TryFormat(Guid, ..., StandardFormat) now treats format.Symbol == '\0' as the default 'D' format without also checking that the StandardFormat is actually default (i.e., Precision == 0). This changes behavior for values like new StandardFormat('\0', 1), which previously would have thrown FormatException but will now format as 'D'.
Use format.IsDefault (or replicate FormattingHelpers.GetSymbolOrDefault logic) so that only the true default StandardFormat maps to 'D'.
| if ((ushort)value._b != (ushort)_b) | ||
| { | ||
| return GetResult(_d, value._d); | ||
| return ((ushort)_b).CompareTo((ushort)value._b); | ||
| } | ||
|
|
||
| if (value._e != _e) | ||
| if ((ushort)value._c != (ushort)_c) | ||
| { | ||
| return GetResult(_e, value._e); | ||
| return ((ushort)_c).CompareTo((ushort)value._c); | ||
| } | ||
|
|
||
| if (value._f != _f) | ||
| { | ||
| return GetResult(_f, value._f); | ||
| } | ||
|
|
||
| if (value._g != _g) | ||
| { | ||
| return GetResult(_g, value._g); | ||
| } | ||
|
|
||
| if (value._h != _h) | ||
| { | ||
| return GetResult(_h, value._h); | ||
| } | ||
|
|
||
| if (value._i != _i) | ||
| { | ||
| return GetResult(_i, value._i); | ||
| } | ||
|
|
||
| if (value._j != _j) | ||
| { | ||
| return GetResult(_j, value._j); | ||
| } | ||
|
|
||
| if (value._k != _k) | ||
| { | ||
| return GetResult(_k, value._k); | ||
| } | ||
|
|
||
| return 0; | ||
| return BinaryPrimitives.ReadUInt64BigEndian(MemoryMarshal.CreateReadOnlySpan(in _d, 8)) | ||
| .CompareTo(BinaryPrimitives.ReadUInt64BigEndian(MemoryMarshal.CreateReadOnlySpan(in value._d, 8))); |
There was a problem hiding this comment.
The comparison logic now treats _b / _c as ushort (and the tail as a big-endian ulong). This changes ordering vs the previous implementation for GUIDs where _b or _c have the high bit set (e.g., values corresponding to negative shorts).
There are GuidTests.CompareTo_TestData cases for _b and _c, but they only cover small positive values. Please add test cases covering boundary values (e.g., short.MinValue, -1, 0x8000) to lock in the intended ordering and ensure this behavior change is validated.
|
This seems like a lot of churn for what amounts to about a nanosecond of savings and which will only light up on a small portion of available hardware today. |
Streamline the default path and use AVX-512 VBMI+VL for even faster formatting.
Benchmark code