Skip to content

Commit

Permalink
GH-44237: [C#] Use stack allocated buffer when serializing decimal va…
Browse files Browse the repository at this point in the history
…lues (#44238)

[Span overrides for `decimal.GetBits`](https://learn.microsoft.com/en-us/dotnet/api/system.decimal.getbits?view=net-8.0#system-decimal-getbits(system-decimal-system-span((system-int32)))) were added in .NET 5, and allow us to avoid a heap allocation for each decimal value serialized.

Running a quick benchmark shows the expected reduction in allocations 

```csharp
using BenchmarkDotNet.Attributes;

namespace Apache.Arrow.Benchmarks;

[MemoryDiagnoser]
public class DecimalUtilityBenchmark
{
    public decimal Value => 1.00000000m;

    private byte[] _buffer = new byte[16];

    [Benchmark(Baseline = true)]
    public void Baseline() => DecimalUtilityMain.GetBytes(Value, 34, 10, 16, _buffer);

    [Benchmark]
    public void Candidate() => DecimalUtility.GetBytes(Value, 34, 10, 16, _buffer);
}
```
```
BenchmarkDotNet v0.14.0, Windows 10 (10.0.19045.4894/22H2/2022Update)
13th Gen Intel Core i7-13800H, 1 CPU, 20 logical and 14 physical cores
.NET SDK 8.0.304
  [Host]     : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
  DefaultJob : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
```

| Method    | Mean     | Error   | StdDev  | Ratio | RatioSD | Gen0   | Allocated | Alloc Ratio |
|---------- |---------:|--------:|--------:|------:|--------:|-------:|----------:|------------:|
| Baseline  | 162.7 ns | 3.25 ns | 4.23 ns |  1.00 |    0.04 | 0.0088 |     112 B |        1.00 |
| Candidate | 152.8 ns | 1.38 ns | 1.22 ns |  0.94 |    0.02 | 0.0057 |      72 B |        0.64 |

Happy to check in some benchmarks for `DecimalUtility` if they might be useful in future, but thought I'd leave them out for now.

If merged, will close #44237.
* GitHub Issue: #44237

Authored-by: George Vanburgh <[email protected]>
Signed-off-by: Curt Hagenlocher <[email protected]>
  • Loading branch information
georgevanburgh authored Sep 26, 2024
1 parent 80622fa commit dcf0d8c
Showing 1 changed file with 7 additions and 0 deletions.
7 changes: 7 additions & 0 deletions csharp/src/Apache.Arrow/DecimalUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,14 @@ internal static void GetBytes(decimal value, int precision, int scale, int byteW
{
// create BigInteger from decimal
BigInteger bigInt;

#if NET5_0_OR_GREATER
Span<int> decimalBits = stackalloc int[4];
decimal.GetBits(value, decimalBits);
#else
int[] decimalBits = decimal.GetBits(value);
#endif

int decScale = (decimalBits[3] >> 16) & 0x7F;
#if NETCOREAPP
Span<byte> bigIntBytes = stackalloc byte[13];
Expand Down

0 comments on commit dcf0d8c

Please sign in to comment.