fixer-m / snowflake-db-net-client

Snowflake .NET Client
Apache License 2.0
51 stars 14 forks source link

Deserialization efficiency improvements - PR using a UTF8 memory stream to further reduce memory pressure. #40

Closed colgreen closed 1 year ago

colgreen commented 1 year ago

This PR takes the code from PR #39, and further reduces memory allocations. This is done by writing JSON directly into a MemoryStream (actually a RecyclableMemoryStream) as UTF8 bytes. This provide the following benefits:

1) Avoids the final call to stringBuilder.toString() and the large temporary JSON string that allocates (and the copying of characters from the StringBuilder into that string). Instead, the memory stream can be passed directly to JsonSerializer.Deserialize(). 2) The characters are written to the memory stream utf8 encoded, which writes one byte per character (for typical payloads) instead of two bytes per character for strings.

These factors are particularly beneficial when handling large binary hex values.

Here are some BenchmarkDotNet benchmarks comparing performance in these these three branches:

Method Mean Error StdDev Gen0 Allocated
ResponseWithValues_MapTo_CustomClass (master) 279.5 us 1.33 us 1.24 us 49.8047 409.46 KB
ResponseWithValues_MapTo_CustomClass (PR #39) 228.2 us 1.20 us 1.12 us 20.0195 165.72 KB
ResponseWithValues_MapTo_CustomClass (this PR) 256.5 us 0.83 us 0.77 us 13.1836 108.01 KB

The benchmark used here processes 100 rows. This new PR uses 108.01 / 409.46 = 26.37% of the memory allocations, compared to the current master branch. Speed is slightly faster too.


Here's a benchmark for processing 1MiB of binary (2,000,000 hex characters)...

Method Mean Error StdDev Gen0 Gen1 Gen2 Allocated
HexToBase64_Long (master) 24.30 ms 0.278 ms 0.260 ms 4406.2500 593.7500 593.7500 34.01 MB
HexToBase64_Long (PR #39) 6.088 ms 0.0932 ms 0.0872 ms 312.5000 148.4375 - 2.56 MB
HexToBase64_Long (this PR) 6.812 ms 0.0474 ms 0.0420 ms - - - 37 B

Memory allocations are reduced from 34MB to 37 bytes! Performance is 3.56 faster.

/cc @georgebarbu

fixer-m commented 1 year ago

@colgreen Hi! Thank you, this looks really nice. It took me a while to digest all these changes, but they are looking good. Oh and benchmark results looks awesome - thanks. I'm gonna merge this and release new version soon.

fixer-m commented 1 year ago

Added in 0.4.6.

colgreen commented 1 year ago

@colgreen Hi! Thank you, this looks really nice. It took me a while to digest all these changes, but they are looking good. Oh and benchmark results looks awesome - thanks. I'm gonna merge this and release new version soon.

No problem. Thanks for taking a look and merging 👍 🚀