Skip to content

Commit

Permalink
Use an inline array for decompression scratch (#86)
Browse files Browse the repository at this point in the history
Motivation
----------
This array is small, fixed size, and always created. We can reduce heap
allocations if it's inline within the class rather than a separate
object on the heap.

Modifications
-------------
For .NET 8 only use a fixed array to store the block decompression
scratch buffer.

Results
-------
BenchmarkDotNet v0.13.10, Windows 11
(10.0.22621.2861/22H2/2022Update/SunValley2) 12th Gen Intel Core
i7-1270P, 1 CPU, 16 logical and 12 physical cores .NET SDK 8.0.100
  [Host]     : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX2
  Job-SOJPFQ : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX2
  Job-OKVMCF : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX2
  Job-BRDMES : .NET 6.0.25 (6.0.2523.51912), X64 RyuJIT AVX2
Job-AJAIVB : .NET Framework 4.8.1 (4.8.9181.0), X64 RyuJIT
VectorSize=256

| Method | Runtime | PGO | Mean | Error | StdDev | Ratio | RatioSD |
Rank | Allocated | Alloc Ratio |
|------------ |------------------- |----
|---------:|---------:|---------:|------:|--------:|-----:|----------:|------------:|
| Array | .NET 8.0 | N | 10.77 us | 0.142 us | 0.132 us | 1.00 | 0.00 |
2 | 112 B | 1.00 |
| InlineArray | .NET 8.0 | N | 10.53 us | 0.168 us | 0.157 us | 0.98 |
0.02 | 1 | 80 B | 0.71 |
| | | | | | | | | | | |
| Array | .NET 8.0 | Y | 10.14 us | 0.114 us | 0.106 us | 1.00 | 0.00 |
1 | 112 B | 1.00 |
| InlineArray | .NET 8.0 | Y | 10.11 us | 0.080 us | 0.071 us | 1.00 |
0.02 | 1 | 80 B | 0.71 |
  • Loading branch information
brantburnett authored Jan 8, 2024
1 parent d647299 commit 4769e23
Showing 1 changed file with 24 additions and 2 deletions.
26 changes: 24 additions & 2 deletions Snappier/Internal/SnappyDecompressor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,24 @@ namespace Snappier.Internal
{
internal sealed class SnappyDecompressor : IDisposable
{
private byte[] _scratch = new byte[Constants.MaximumTagLength];
#if NET8_0_OR_GREATER
#pragma warning disable IDE0051
#pragma warning disable IDE0044
#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value
[InlineArray(Constants.MaximumTagLength)]
private struct ScratchBuffer
{
private byte _element0;
}

private ScratchBuffer _scratch;
#pragma warning restore CS0649 // Field is never assigned to, and will always have its default value
#pragma warning restore IDE0044
#pragma warning restore IDE0051
#else
private readonly byte[] _scratch = new byte[Constants.MaximumTagLength];
#endif

private uint _scratchLength = 0;

private int _remainingLiteral;
Expand Down Expand Up @@ -671,7 +688,12 @@ internal void WriteToBufferForTest(ReadOnlySpan<byte> toWrite)
internal void LoadScratchForTest(byte[] newScratch, uint newScratchLength)
{
ThrowHelper.ThrowIfNull(newScratch);
_scratch = newScratch;
if (newScratchLength > ((ReadOnlySpan<byte>)_scratch).Length)
{
ThrowHelper.ThrowArgumentOutOfRangeException(nameof(newScratchLength), "Scratch length exceeds limit");
}

newScratch.AsSpan(0, (int) newScratchLength).CopyTo(_scratch);
_scratchLength = newScratchLength;
}

Expand Down

0 comments on commit 4769e23

Please sign in to comment.