Skip to content
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

Optimize Guid comparisons #104610

Closed
wants to merge 1 commit into from
Closed

Conversation

lilinus
Copy link
Contributor

@lilinus lilinus commented Jul 9, 2024

Optimization of Guid.CompareTo and the comparison operators.

Might be more useful when comparing and orderign Guids, especially now with Guid.CreateVersion7 where the first 4-bits is a unix timestamp.

Benchmark on x64 below, ,

  • Source code to benchmark here
  • There are small regressions, largest being when the Guids biffer on bits 33-48 (1 being MSB). Hopefully these are OK with regards to improvements (especially when Guids differ on bits 1-32, which should be more likely).
  • I would expect it to be even faster and without regressions on a big endian machine.
AMD Ryzen 9 4900HS with Radeon Graphics, 1 CPU, 16 logical and 8 physical cores
.NET SDK 9.0.100-preview.3.24204.13
  [Host]     : .NET 9.0.0 (9.0.24.17209), X64 RyuJIT AVX2
  Job-YIWRTN : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX2
  Job-FNCFRH : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX2

PowerPlanMode=00000000-0000-0000-0000-000000000000  IterationTime=250ms  MaxIterationCount=20
MinIterationCount=15  WarmupCount=1

| Method         | Job        | Toolchain | left                                 | right                                | Mean      | Error     | StdDev    | Median    | Min       | Max       | Ratio | RatioSD | Allocated | Alloc Ratio |
|--------------- |----------- |---------- |------------------------------------- |------------------------------------- |----------:|----------:|----------:|----------:|----------:|----------:|------:|--------:|----------:|------------:|
| Guid_CompareTo | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010101010101 | 1.9087 ns | 0.0212 ns | 0.0188 ns | 1.9090 ns | 1.8567 ns | 1.9391 ns |  1.00 |    0.01 |         - |          NA |
| Guid_CompareTo | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010101010101 | 0.5605 ns | 0.0138 ns | 0.0129 ns | 0.5604 ns | 0.5363 ns | 0.5896 ns |  0.29 |    0.01 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_LessThan  | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010101010101 | 2.0176 ns | 0.0176 ns | 0.0165 ns | 2.0145 ns | 1.9983 ns | 2.0403 ns |  1.00 |    0.01 |         - |          NA |
| Guid_LessThan  | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010101010101 | 0.5596 ns | 0.0085 ns | 0.0067 ns | 0.5578 ns | 0.5518 ns | 0.5794 ns |  0.28 |    0.00 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_CompareTo | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010101010102 | 2.0196 ns | 0.0029 ns | 0.0022 ns | 2.0197 ns | 2.0149 ns | 2.0237 ns |  1.00 |    0.00 |         - |          NA |
| Guid_CompareTo | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010101010102 | 1.0225 ns | 0.0050 ns | 0.0045 ns | 1.0207 ns | 1.0183 ns | 1.0330 ns |  0.51 |    0.00 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_LessThan  | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010101010102 | 1.9995 ns | 0.0076 ns | 0.0059 ns | 1.9998 ns | 1.9863 ns | 2.0073 ns |  1.00 |    0.00 |         - |          NA |
| Guid_LessThan  | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010101010102 | 0.8299 ns | 0.0048 ns | 0.0038 ns | 0.8307 ns | 0.8185 ns | 0.8326 ns |  0.42 |    0.00 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_CompareTo | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010101010201 | 1.8399 ns | 0.0032 ns | 0.0029 ns | 1.8399 ns | 1.8348 ns | 1.8451 ns |  1.00 |    0.00 |         - |          NA |
| Guid_CompareTo | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010101010201 | 1.0371 ns | 0.0232 ns | 0.0217 ns | 1.0240 ns | 1.0142 ns | 1.0824 ns |  0.56 |    0.01 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_LessThan  | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010101010201 | 1.8787 ns | 0.0017 ns | 0.0015 ns | 1.8784 ns | 1.8770 ns | 1.8820 ns |  1.00 |    0.00 |         - |          NA |
| Guid_LessThan  | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010101010201 | 0.8052 ns | 0.0033 ns | 0.0029 ns | 0.8044 ns | 0.8011 ns | 0.8115 ns |  0.43 |    0.00 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_CompareTo | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010101020101 | 1.7517 ns | 0.0053 ns | 0.0047 ns | 1.7507 ns | 1.7454 ns | 1.7618 ns |  1.00 |    0.00 |         - |          NA |
| Guid_CompareTo | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010101020101 | 1.0644 ns | 0.0254 ns | 0.0237 ns | 1.0581 ns | 1.0208 ns | 1.1109 ns |  0.61 |    0.01 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_LessThan  | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010101020101 | 1.4990 ns | 0.0109 ns | 0.0102 ns | 1.4955 ns | 1.4851 ns | 1.5206 ns |  1.00 |    0.01 |         - |          NA |
| Guid_LessThan  | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010101020101 | 0.8379 ns | 0.0158 ns | 0.0148 ns | 0.8301 ns | 0.8250 ns | 0.8663 ns |  0.56 |    0.01 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_CompareTo | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010102010101 | 1.5684 ns | 0.0298 ns | 0.0278 ns | 1.5712 ns | 1.5297 ns | 1.6310 ns |  1.00 |    0.02 |         - |          NA |
| Guid_CompareTo | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010102010101 | 1.0231 ns | 0.0034 ns | 0.0030 ns | 1.0228 ns | 1.0184 ns | 1.0304 ns |  0.65 |    0.01 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_LessThan  | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010102010101 | 1.3128 ns | 0.0138 ns | 0.0129 ns | 1.3087 ns | 1.3000 ns | 1.3350 ns |  1.00 |    0.01 |         - |          NA |
| Guid_LessThan  | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010102010101 | 0.8496 ns | 0.0285 ns | 0.0266 ns | 0.8437 ns | 0.8130 ns | 0.9028 ns |  0.65 |    0.02 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_CompareTo | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010201010101 | 1.3388 ns | 0.0030 ns | 0.0026 ns | 1.3388 ns | 1.3351 ns | 1.3441 ns |  1.00 |    0.00 |         - |          NA |
| Guid_CompareTo | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010201010101 | 0.8111 ns | 0.0038 ns | 0.0030 ns | 0.8102 ns | 0.8078 ns | 0.8184 ns |  0.61 |    0.00 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_LessThan  | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010201010101 | 1.2191 ns | 0.0263 ns | 0.0246 ns | 1.2057 ns | 1.1988 ns | 1.2746 ns |  1.00 |    0.03 |         - |          NA |
| Guid_LessThan  | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-010201010101 | 0.5961 ns | 0.0028 ns | 0.0023 ns | 0.5960 ns | 0.5931 ns | 0.6013 ns |  0.49 |    0.01 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_CompareTo | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-020101010101 | 1.0730 ns | 0.0017 ns | 0.0014 ns | 1.0728 ns | 1.0715 ns | 1.0759 ns |  1.00 |    0.00 |         - |          NA |
| Guid_CompareTo | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-020101010101 | 0.8169 ns | 0.0032 ns | 0.0027 ns | 0.8163 ns | 0.8137 ns | 0.8228 ns |  0.76 |    0.00 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_LessThan  | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-020101010101 | 0.9278 ns | 0.0078 ns | 0.0066 ns | 0.9268 ns | 0.9194 ns | 0.9436 ns |  1.00 |    0.01 |         - |          NA |
| Guid_LessThan  | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0101-020101010101 | 0.5970 ns | 0.0027 ns | 0.0024 ns | 0.5965 ns | 0.5942 ns | 0.6029 ns |  0.64 |    0.00 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_CompareTo | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0102-010101010101 | 1.0591 ns | 0.0086 ns | 0.0072 ns | 1.0563 ns | 1.0519 ns | 1.0779 ns |  1.00 |    0.01 |         - |          NA |
| Guid_CompareTo | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0102-010101010101 | 0.7861 ns | 0.0024 ns | 0.0020 ns | 0.7861 ns | 0.7824 ns | 0.7894 ns |  0.74 |    0.01 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_LessThan  | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0102-010101010101 | 0.7911 ns | 0.0039 ns | 0.0035 ns | 0.7904 ns | 0.7868 ns | 0.7994 ns |  1.00 |    0.01 |         - |          NA |
| Guid_LessThan  | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0102-010101010101 | 0.5923 ns | 0.0081 ns | 0.0075 ns | 0.5945 ns | 0.5808 ns | 0.6024 ns |  0.75 |    0.01 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_CompareTo | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0201-010101010101 | 0.8243 ns | 0.0121 ns | 0.0101 ns | 0.8210 ns | 0.8171 ns | 0.8490 ns |  1.00 |    0.02 |         - |          NA |
| Guid_CompareTo | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0201-010101010101 | 0.8161 ns | 0.0158 ns | 0.0148 ns | 0.8084 ns | 0.8010 ns | 0.8426 ns |  0.99 |    0.02 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_LessThan  | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0201-010101010101 | 0.5659 ns | 0.0013 ns | 0.0011 ns | 0.5656 ns | 0.5643 ns | 0.5678 ns |  1.00 |    0.00 |         - |          NA |
| Guid_LessThan  | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0001-0201-010101010101 | 0.6087 ns | 0.0151 ns | 0.0118 ns | 0.6133 ns | 0.5724 ns | 0.6142 ns |  1.08 |    0.02 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_CompareTo | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0002-0101-010101010101 | 0.5969 ns | 0.0160 ns | 0.0150 ns | 0.5920 ns | 0.5665 ns | 0.6283 ns |  1.00 |    0.03 |         - |          NA |
| Guid_CompareTo | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0002-0101-010101010101 | 0.5510 ns | 0.0040 ns | 0.0036 ns | 0.5513 ns | 0.5465 ns | 0.5587 ns |  0.92 |    0.02 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_LessThan  | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0002-0101-010101010101 | 0.5629 ns | 0.0125 ns | 0.0117 ns | 0.5559 ns | 0.5515 ns | 0.5832 ns |  1.00 |    0.03 |         - |          NA |
| Guid_LessThan  | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0001-0002-0101-010101010101 | 0.5811 ns | 0.0236 ns | 0.0221 ns | 0.5756 ns | 0.5461 ns | 0.6184 ns |  1.03 |    0.04 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_CompareTo | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0002-0001-0101-010101010101 | 0.5513 ns | 0.0020 ns | 0.0018 ns | 0.5508 ns | 0.5487 ns | 0.5543 ns |  1.00 |    0.00 |         - |          NA |
| Guid_CompareTo | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0002-0001-0101-010101010101 | 0.5661 ns | 0.0202 ns | 0.0168 ns | 0.5743 ns | 0.5275 ns | 0.5774 ns |  1.03 |    0.03 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_LessThan  | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000001-0002-0001-0101-010101010101 | 0.5020 ns | 0.0091 ns | 0.0076 ns | 0.5001 ns | 0.4945 ns | 0.5208 ns |  1.00 |    0.02 |         - |          NA |
| Guid_LessThan  | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000001-0002-0001-0101-010101010101 | 0.5835 ns | 0.0178 ns | 0.0167 ns | 0.5752 ns | 0.5618 ns | 0.6105 ns |  1.16 |    0.04 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_CompareTo | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000002-0001-0001-0101-010101010101 | 0.4597 ns | 0.0007 ns | 0.0007 ns | 0.4595 ns | 0.4587 ns | 0.4606 ns |  1.00 |    0.00 |         - |          NA |
| Guid_CompareTo | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000002-0001-0001-0101-010101010101 | 0.3161 ns | 0.0020 ns | 0.0018 ns | 0.3162 ns | 0.3132 ns | 0.3195 ns |  0.69 |    0.00 |         - |          NA |
|                |            |           |                                      |                                      |           |           |           |           |           |           |       |         |           |             |
| Guid_LessThan  | Job-YIWRTN | main      | 00000001-0001-0001-0101-010101010101 | 00000002-0001-0001-0101-010101010101 | 0.4961 ns | 0.0139 ns | 0.0124 ns | 0.4897 ns | 0.4818 ns | 0.5182 ns |  1.00 |    0.03 |         - |          NA |
| Guid_LessThan  | Job-FNCFRH | pr        | 00000001-0001-0001-0101-010101010101 | 00000002-0001-0001-0101-010101010101 | 0.3056 ns | 0.0078 ns | 0.0061 ns | 0.3078 ns | 0.2900 ns | 0.3136 ns |  0.62 |    0.02 |         - |          NA |

@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Jul 9, 2024
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Jul 9, 2024
@EgorBo
Copy link
Member

EgorBo commented Jul 9, 2024

@EgorBot

using BenchmarkDotNet.Attributes;

public class Perf
{
    public static IEnumerable<object[]> Values()
    {
        yield return [
            new Guid("EE268EB3-1E8F-4F76-87D7-6A5A43983CF4"), 
            new Guid("69F1C1B8-E6FE-4494-A536-BBFAC3429AD3")];
    }

    [Benchmark, ArgumentsSource(nameof(Values))]
    public int Guid_CompareTo(Guid left, Guid right) => left.CompareTo(right);
}

@EgorBot
Copy link

EgorBot commented Jul 9, 2024

Benchmark results on Intel
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
  Job-ASWFUG : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
  Job-UVQCUY : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Method Toolchain left right Mean Error Ratio
Guid_CompareTo Main ee268(...)83cf4 [36] 69f1c(...)29ad3 [36] 1.473 ns 0.0004 ns 1.00
Guid_CompareTo PR ee268(...)83cf4 [36] 69f1c(...)29ad3 [36] 1.470 ns 0.0006 ns 1.00

BDN_Artifacts.zip

@tannergooding
Copy link
Member

This is a significant reduction in readability for what is at most a 1.5ns savings. I don't think the change is justifiable.

It would likely be beneficial to see what the perf difference would be if we instead did:

compare a
compare b
compare c
compare d-k using `ReadUInt64BigEndian`

This would reduce the total number of compares to 4 without making the code significantly more complex.

@aloraman
Copy link

aloraman commented Jul 9, 2024

V7 (G/U)uids have time-based ordering, and there are a lot of usage scenarios for them.
Still, they do not a replacement for V4, there's a lot of specific scenarios where using V4 is preferred.
Consider this common shuffling snippet:

IEnumerable<T> Shuffle<T>(IEnumerable<T> sequence) => sequence.OrderBy(x => Guid.NewGuid());

Are any regressions observed here?

@lilinus
Copy link
Contributor Author

lilinus commented Jul 10, 2024

I don't think the change is justifiable.

Got it.

It would likely be beneficial to see what the perf difference would be if we instead did:


compare a

compare b

compare c

compare d-k using `ReadUInt64BigEndian`

I just tried this but there were unfortunately bigger regressions.

Closing the PR.

@lilinus lilinus closed this Jul 10, 2024
@lilinus lilinus deleted the optimize-guid-comp branch July 18, 2024 08:41
@github-actions github-actions bot locked and limited conversation to collaborators Aug 18, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
community-contribution Indicates that the PR has been added by a community member needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants