Optimize LZ4 IPC decompression by avoiding an intermediate frame-reader drain copy #353
InCerryGit
started this conversation in
Ideas
Replies: 1 comment 5 replies
-
|
Let's start by trying to get a better API from K4os. The easiest way to do that might be to submit a PR to that project :). If it's been a few weeks and that hasn't panned out, then we could consider something more complicated in our own code. |
Beta Was this translation helpful? Give feedback.
5 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Hi,
I would like to discuss a potential optimization for LZ4-compressed Arrow IPC buffers in Arrow .NET.
Background
Arrow IPC compressed buffers already carry the expected uncompressed buffer length in the IPC metadata. During reading, Arrow .NET allocates the destination buffer first, then calls the configured compression codec to decompress into that destination.
For LZ4 today, the current path uses K4os' frame reader API roughly like this:
This is correct and simple, but profiling shows a significant amount of time is spent in an intermediate drain/copy path inside the K4os frame reader.
Profiling evidence
Using a deterministic local benchmark that generates a real LZ4-compressed Arrow IPC stream and replays it without external network variability, the hot path was dominated by:
LZ4_decompress_*Buffer._MemmoveThe important observation is that the
Buffer._Memmovecost appears to come largely from K4os decoding into its internal decoder buffer and then draining/copying into the caller-provided destination span.Experiment
I prototyped a restricted fast path in Arrow .NET:
If any unsupported frame feature or malformed input is detected, the code falls back to the existing K4os frame reader path.
This is not a public API change and not a "zero-copy" decompression path. The better description is:
Benchmark result
On the deterministic LZ4 Arrow IPC replay benchmark:
The trace also showed
Buffer._Memmovedropping substantially:Buffer._MemmoveBuffer._MemmoveApplicability
This fast path is expected to help common Arrow IPC LZ4 compressed buffers where the producer writes simple LZ4 frames.
It does not apply to all LZ4 frames. The implementation falls back to K4os for:
So this is not intended to replace a full LZ4 frame decoder.
Design question
I see two possible directions:
Option A: Add a restricted fast path in Arrow .NET
Arrow .NET can keep a private, conservative parser for simple LZ4 frames and use K4os' block decoder to write directly into the already-allocated Arrow destination buffer.
Pros:
Cons:
Option B: Request a new K4os API
A cleaner long-term solution may be an upstream K4os API such as:
or similar.
The key requirement is that the frame decoder should be able to write directly into a caller-provided destination span when the caller already knows the expected output size.
Pros:
Cons:
Question
Would maintainers prefer that Arrow .NET:
My current leaning is:
I would appreciate feedback on which direction is more acceptable for this project.
Beta Was this translation helpful? Give feedback.
All reactions