Almost double the performance of parsing Guids#3965
Almost double the performance of parsing Guids#3965hughbe wants to merge 1 commit intodotnet:masterfrom hughbe:guid-performance
Conversation
src/mscorlib/src/System/Guid.cs
Outdated
| else { | ||
| if ((flags & GuidStyles.RequireDashes) != 0) { | ||
| // dashes are required | ||
| for (int i = end; i > start; i--) |
There was a problem hiding this comment.
This can be
for (int i = end - 1; i > start; i--)
instead, since guidString[end] is guaranteed to be '\0'.
However, I think it would be more elegant to write these two loops as
int start = 0;
while (start < g.Length && char.IsWhitespace(guidString[start]))
start++;
int end = g.Length;
while (end > start && char.IsWhitespace(guidString[end - 1]))
end--;
There was a problem hiding this comment.
Thanks, I pushed a commit adopting your more elegant code
|
@hughbe Just to back up your findings, here's a benchmark of
For reference, here is the full benchmark code (note that it's using BenchmarkDotNet) |
src/mscorlib/src/System/Guid.cs
Outdated
| length = newLength; | ||
| fixed (char* newGuidString = new string(chars, 0, newLength)) | ||
| { | ||
| return newGuidString; |
There was a problem hiding this comment.
I believe this is unsafe, after the fixed block exits, there's nothing preventing the GC from relocating the managed object backing newGuidString and preventing the pointer from dangling.
|
First, it's great to see the improvements here, so thanks a lot for starting the conversation. Looking over the diff, I suspect some of the wins come from being smarter about the sorts of allocations we do (I see a bunch of places where calls to I don't like how much unsafe code we end up having to add to the system. Seeing If we do need to introduce more places we use |
|
Thanks for the review. I recall that plenty of those char* were used because I think that indexing into a char* is quicker than indexing into a string. Could you let me know there is no change or in fact it's better to index into a string? |
| } | ||
| } | ||
| catch(IndexOutOfRangeException ex) { | ||
| catch (IndexOutOfRangeException ex) |
There was a problem hiding this comment.
@ellismg Is catching this IndexOutOfRangeException and the ArgumentException below necessary, or actually hiding a bug that has the potential to happen?
|
I've updated the PR just squashing the old commits (so thats easier to review) and shortening the diff for you. |
|
Just updated the PR to not allocate anything if a hex string contains whitespace - this more than doubled the perf of creating a hex guid |
src/mscorlib/src/System/Guid.cs
Outdated
| { | ||
| chArr[newLength++] = curChar; | ||
| } | ||
| char c = guidString[start]; |
There was a problem hiding this comment.
Is this really needed? It looks like c is never used.
Use a bit of (safe) unsafe code to speed up code and remove allocations Bring in a utility helper to avoid calling native code Average improvement of 40% + for parsing each type of Guid
|
Closing for now, fails corefx tests - will send in an updated PR soon |

Remove substring and other allocations
Bring in a utility helper to avoid calling native code
Average improvement of -40% + for parsing each type of Guid.
Benchmark Results:
(newTime - oldTime) / oldTime * 100Benchmark Code:
Click Here