Repository navigation
Inflate OASIS CBLOCKs in one go with zlib - #2468
nikosavola wants to merge 1 commit into
Conversation
- CBLOCKs are decompressed by zlib into memory using their byte counts instead of bit by bit by the built-in decoder; comp-byte-count decides where the next record starts, uncomp-byte-count is only a size hint - inline fast path for InputStream::get; the OASIS varint readers are one template per signedness and decode straight from the buffer - pos () stays at the end of a CBLOCK while its content is read | vexriscv read, 1 thread (n=20) | before (ms) | after (ms) | |---|---:|---:| | OASIS with CBLOCKs | 138.69 ± 1.42 | 75.71 ± 1.01 | | OASIS without CBLOCKs | 67.77 ± 1.30 | 68.59 ± 1.18 | Measured on 2x Intel Xeon Gold 6148 (40 cores), g++ 13 -O2, mean ± standard deviation. Co-Authored-By: GLM 5.3 <noreply@z.ai>
148673f to
a0b61ef
Compare
|
Does it work with double .gz OASIS? CBLOCK inside and .gz outside? Such files exist. And the patch is too big for my taste. I don't want to review it. |
|
Double-compressed files work: the .gz layer is a delegate in front (InputZLibFile), and inflate_block pulls the CBLOCK bytes through it with its raw reads. TEST(CBlockGzip) in this PR covers exactly that case: the same CBLOCK layout read plain, then again through a .oas.gz wrapper, both compared against the original layout. Sorry about the size. I can split it into independent pieces instead: (1) the inline fast path on tl::InputStream::get, (2) the varint readers decoding from the buffered bytes, (3) inflate_block with the CBLOCK byte counts and the reader-side handling. (1) and (2) are small on their own and useful for every streamer, not just OASIS. Would that work for you? |
|
Closing this one as it is too big to review, as you said. I will split it into smaller PRs. #2505 is the first one, the inline fast path on |
tl::InputStream::inflate_block, which decompresses the whole block with zlib (already linked for writing) and serves reads from memory; the streaming decoder stays for other inflate users and forcomp-byte-count = 0comp-byte-countdecides where the next record starts (padding after the DEFLATE stream is skipped),uncomp-byte-countis only a hint for the initial buffer size, which grows as needed up to 1 GiBInputStream::gethas an inline fast path; the OASIS varint readers are one template per signedness and decode from the buffer directly when enough bytes are available (C++11, with[[likely]]under C++20)pos ()now stays at the end of a CBLOCK while its content is read, so error messages for records inside a CBLOCK report the block endAfter the change the CBLOCK file reads about as fast as the uncompressed one; the rest is parsing. The table was measured on the first version of this change, before the lenient count handling and the varint templates; those changed error handling and code structure but not the decoding path.
The benchmarks use the Google Benchmark suite from
parallelize-rebasedon my fork, which is not part of this PR. Measured on theparallelizebranch, where the changed code is the same as on master. Numbers: 2x Intel Xeon Gold 6148 (40 cores, exclusive node), g++ 13 -O2, 20 runs each, mean ± standard deviation.Benchmark code
This PR was carried out with AI assistance (open-weight GLM 5.3) and reviewed before submission.