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

Utilize ImmutableCollectionsMarshal to get ROS for XxHash128.Hash call #73692

Merged
merged 5 commits into from
May 24, 2024

Conversation

ToddGrun
Copy link
Contributor

@ToddGrun ToddGrun commented May 24, 2024

There is apparently a significant advantage to being able to utilize the static Hash method on XxHash128

Here are the numbers I see in commit 1 (has both old and new code still present so can be measured side by side)

|                             Method |       Mean |     Error |    StdDev |      Gen 0 | Gen 1 | Gen 2 |     Allocated |
|----------------------------------- |-----------:|----------:|----------:|-----------:|------:|------:|--------------:|
|      Old_ImmutableArray_Byte_Small | 832.274 ms | 5.2416 ms | 4.6465 ms | 12000.0000 |     - |     - | 128,000,672 B |
|      New_ImmutableArray_Byte_Small |  21.616 ms | 0.0720 ms | 0.0602 ms |          - |     - |     - |          10 B |
|     Old_ImmutableArray_Byte_Medium | 582.447 ms | 7.2233 ms | 6.4032 ms |  1000.0000 |     - |     - |  12,800,672 B |
|     New_ImmutableArray_Byte_Medium |   6.957 ms | 0.0960 ms | 0.0898 ms |          - |     - |     - |           3 B |
|      Old_ImmutableArray_Byte_Large | 595.394 ms | 2.6109 ms | 2.3145 ms |          - |     - |     - |   1,280,672 B |
|      New_ImmutableArray_Byte_Large |   6.151 ms | 0.0207 ms | 0.0193 ms |          - |     - |     - |           3 B |
|  Old_ImmutableArray_Checksum_Small | 713.301 ms | 1.7292 ms | 1.5329 ms | 12000.0000 |     - |     - | 128,000,672 B |
|  New_ImmutableArray_Checksum_Small |  21.390 ms | 0.0565 ms | 0.0528 ms |          - |     - |     - |          10 B |
| Old_ImmutableArray_Checksum_Medium | 555.612 ms | 2.1861 ms | 2.0449 ms |  1000.0000 |     - |     - |  12,800,672 B |
| New_ImmutableArray_Checksum_Medium |   6.850 ms | 0.0113 ms | 0.0106 ms |          - |     - |     - |           3 B |
|  Old_ImmutableArray_Checksum_Large | 554.068 ms | 1.2069 ms | 1.0698 ms |          - |     - |     - |   1,280,672 B |
|  New_ImmutableArray_Checksum_Large |   6.144 ms | 0.0146 ms | 0.0136 ms |          - |     - |     - |           3 B |
|             Old_ArrayBuilder_Small |  768.56 ms |  3.951 ms |  3.696 ms | 12000.0000 |     - |     - | 128,000,672 B |
|             New_ArrayBuilder_Small |   34.26 ms |  0.335 ms |  0.314 ms |          - |     - |     - |          22 B |
|            Old_ArrayBuilder_Medium |  598.04 ms |  2.844 ms |  2.660 ms |  1000.0000 |     - |     - |  12,800,672 B |
|            New_ArrayBuilder_Medium |   25.05 ms |  0.159 ms |  0.141 ms |          - |     - |     - |             - |
|             Old_ArrayBuilder_Large |  627.52 ms |  2.758 ms |  2.303 ms |          - |     - |     - |   1,280,672 B |
|             New_ArrayBuilder_Large |   20.71 ms |  0.130 ms |  0.122 ms |          - |     - |     - |          10 B |

There is apparently a *significant* advantage to being able to utilize the static Hash method on XxHash128
@dotnet-issue-labeler dotnet-issue-labeler bot added Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead labels May 24, 2024
@ToddGrun
Copy link
Contributor Author

Frankly, these numbers look too good, so I'm a bit skeptical

public static Checksum CreateNew(ArrayBuilder<Checksum> checksums)
{
var checksumsCount = checksums.Count;
if (checksumsCount <= 100)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stephentoub does runtime have a general rule of thumb about reasonable stackalloc sizes? for context, each item in this array is 16 bytes, so this would be up to 1.6k alloc (on a leaf node of the stack, no recursion). Is that in line with what you guys do?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We generally avoid going above 1k

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, current changes should not exceeed 1 KB

public static Checksum Create(ImmutableArray<Checksum> checksums)
=> Create(checksums, static (checksums, writer) =>
{
foreach (var checksum in checksums)
checksum.WriteTo(writer);
});

public static Checksum CreateNew(ImmutableArray<byte> bytes)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one nagging issue i have with this is ensuring we don't end up in collision situations. So, like getting the checksum for an empty array of bytes, will produced the same checksum as an empty enumerable of strings. I don't know if that's a concern or not. And it's likely a problem external to this PR.

@CyrusNajmabadi
Copy link
Member

@ToddGrun can you write some test helpers that hash teh old way and the new way? to validate you're getting the same hashes?

@CyrusNajmabadi
Copy link
Member

Frankly, these numbers look too good, so I'm a bit skeptical

Seems reasonable to me. We're going from N chatty calls to keep hashing tiny bits of data, to one chunky call where the data can be hashed in its entirety :)

Should be easy to verify with some tests. This is what i did as well to validate that our NetCore impls of xxhash matches the NetFx versions (where we don't have access to all the goodness netcore provides). We have tests that still demonstrate you get the exact same hashed values out.

@ToddGrun ToddGrun marked this pull request as ready for review May 24, 2024 19:15
@ToddGrun ToddGrun requested a review from a team as a code owner May 24, 2024 19:15
var count = Math.Min(maxStackAllocCount, checksumsCount - checksumsIndex);

for (var checksumsSpanIndex = 0; checksumsSpanIndex < count; checksumsIndex++)
checksumsSpan[checksumsSpanIndex++] = checksums[checksumsIndex];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

plz.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants