Skip to content

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 |

@ghost ghost 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