Skip to content

Commit

Permalink
Switch decompression input and scratch to use ref byte (#50)
Browse files Browse the repository at this point in the history
Motivation
----------
This is a step towards code that doesn't require pinning which can help
with GC when compression/decompression is run a lot. GC will be able to
move memory even when in the middle of a compression or decompression
run and update the ref pointers.

Modifications
-------------
Switch all usages of input, inputEnd, and scratch to be `ref byte`
within the decompression logic.

Redesign so that inputEnd points to the last byte in the input rather
than just past the end of the input.

Redesign RefillTag to return information rather than directly
manipulating the pointer parameters since you can't pass a ref to a ref
(except in .NET 7).

Results
-------
Smaller code size across all platforms, and a slight gain on modern
frameworks. .NET 4.8 regresses a bit, hopefully we can improve that with
tuning later.

BenchmarkDotNet=v0.13.4, OS=Windows 11 (10.0.22000.1455/21H2) Intel Core
i7-10850H CPU 2.70GHz, 1 CPU, 12 logical and 6 physical cores .NET
SDK=7.0.102
[Host] : .NET 7.0.2 (7.0.222.60605), X64 RyuJIT AVX2
MediumRun-.NET 6.0 : .NET 6.0.13 (6.0.1322.58009), X64 RyuJIT AVX2
MediumRun-.NET 7.0 : .NET 7.0.2 (7.0.222.60605), X64 RyuJIT AVX2
MediumRun-.NET Framework 4.8 : .NET Framework 4.8 (4.8.4515.0), X64
RyuJIT VectorSize=256

IterationCount=15  LaunchCount=2  WarmupCount=10

| Method | Job | Runtime | Mean | Error | StdDev | Median | Ratio |
RatioSD | Code Size |
|-------- |----------------------------- |-------------------
|----------:|---------:|---------:|----------:|------:|--------:|----------:|
| Pointer | MediumRun-.NET 6.0 | .NET 6.0 | 103.15 us | 1.167 us | 1.674
us | 102.30 us | 1.00 | 0.00 | 6,034 B |
| Ref | MediumRun-.NET 6.0 | .NET 6.0 | 102.52 us | 0.386 us | 0.516 us
| 102.45 us | 0.99 | 0.02 | 5,784 B |
| | | | | | | | | | |
| Pointer | MediumRun-.NET 7.0 | .NET 7.0 | 91.47 us | 0.698 us | 1.045
us | 91.13 us | 1.00 | 0.00 | 5,197 B |
| Ref | MediumRun-.NET 7.0 | .NET 7.0 | 89.62 us | 1.262 us | 1.888 us |
90.80 us | 0.98 | 0.03 | 4,609 B |
| | | | | | | | | | |
| Pointer | MediumRun-.NET Framework 4.8 | .NET Framework 4.8 | 104.69
us | 0.138 us | 0.203 us | 104.77 us | 1.00 | 0.00 | 6,213 B |
| Ref | MediumRun-.NET Framework 4.8 | .NET Framework 4.8 | 116.17 us |
3.613 us | 5.408 us | 117.59 us | 1.11 | 0.05 | 5,846 B |
  • Loading branch information
brantburnett authored Feb 7, 2023
1 parent 8a631ce commit 4b2c26e
Show file tree
Hide file tree
Showing 3 changed files with 234 additions and 196 deletions.
2 changes: 1 addition & 1 deletion Snappier/Internal/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public enum ChunkType : byte
public const byte Copy2ByteOffset = 2;
public const byte Copy4ByteOffset = 3;

public const long MaximumTagLength = 5;
public const int MaximumTagLength = 5;

public const int BlockLog = 16;
public const long BlockSize = 1 << BlockLog;
Expand Down
12 changes: 12 additions & 0 deletions Snappier/Internal/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ public static unsafe uint UnsafeReadUInt32(void* ptr)
return result;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint UnsafeReadUInt32(ref byte ptr)
{
var result = Unsafe.ReadUnaligned<uint>(ref ptr);
if (!BitConverter.IsLittleEndian)
{
result = BinaryPrimitives.ReverseEndianness(result);
}

return result;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe ulong UnsafeReadUInt64(void* ptr)
{
Expand Down
Loading

0 comments on commit 4b2c26e

Please # to comment.