SteNicholas opened a new issue, #228: URL: https://github.com/apache/paimon-cpp/issues/228
### Search before asking - [x] I searched in the [issues](https://github.com/apache/paimon-cpp/issues) and found nothing similar. ### Motivation `benchmark/` currently only contains table-level end-to-end cases (`benchmark_case_read.cpp`, `benchmark_case_write.cpp`, `benchmark_case_pk_write.cpp`, `benchmark_case_mor_read.cpp`). There is no way to measure a change that lives entirely in the format layer — writer properties, encoding passthrough, per-batch overhead in the read loop — without the noise of catalog lookup, split planning, merge/sort and commit. That makes format-level optimizations hard to justify and hard to review: a proposal either lands without evidence, or it is dropped because nobody can quantify it. Several concrete candidates below are currently blocked on exactly this. For reference, the Velox Parquet writer effort ([facebookincubator/velox#17988](https://github.com/facebookincubator/velox/issues/17988)) landed a dedicated writer benchmark ([velox#18052](https://github.com/facebookincubator/velox/pull/18052)) alongside the optimizations precisely so each change could be attributed individually. The negative result in that same effort — parallel column writing plateauing at 1.3–1.6x ([velox#18128](https://github.com/facebookincubator/velox/pull/18128), closed unmerged) — was only identifiable because the measurement infrastructure existed. ### Solution Add format-level micro-benchmarks for the Parquet reader and writer, driving `ParquetFormatWriter` / `ParquetFileBatchReader` directly instead of going through the table API. Suggested coverage: - **Writer**: flat primitives; low / medium / high cardinality `VARCHAR`; `DECIMAL` at precision 9 / 18 / 38; nested `STRUCT` / `LIST` / `VECTOR`; multi-batch writes (schema and property setup amortized over N batches); compression codecs already supported by `ParquetWriterBuilder`. - **Reader**: full scan; projection; page-index filtered reads at varying selectivity; skip-heavy reads (many small surviving row ranges); nested column reads. - **Metrics**: ns/row and bytes written for the writer, ns/row and bytes read for the reader, so encoding changes that trade CPU for size are visible. Candidates to measure once this exists — listed here so they are not lost, all currently **unquantified**: 1. **Per-batch fixed cost in `ParquetFileBatchReader::NextBatch`**: - `array->Validate()` on every batch (`src/paimon/format/parquet/parquet_file_batch_reader.cpp:619`) — structural validation that arguably belongs behind a debug-only guard; - two `MetricsImpl::SetCounter` calls per batch (`:641`, `:642`), each taking a `std::mutex` and doing a `std::map<std::string, uint64_t>` lookup; - a fresh `ArrowSchema` export on every batch (`:637`) even though the type tree is constant for the whole file. This is the paimon-cpp analogue of the per-page fixed-overhead work in [velox#17989](https://github.com/facebookincubator/velox/pull/17989) (~100 ns/page). Whether it is worth touching depends entirely on batch size, and nothing here should change before there is a number. 2. **Intra-page skip cost in `PageFilteredRowGroupReader::ExecuteSkipReadPattern`** (`src/paimon/format/parquet/page_filtered_row_group_reader.cpp:243`): the data page read plan already skips fully-filtered pages at the IO layer, but inside a partially selected page arrow's `TypedColumnReaderImpl::Skip` decodes into a scratch buffer and discards (`cpp/src/parquet/column_reader.cc:1249` in arrow 17). The residual cost scales with the skipped-but-decoded run length and is unknown today. ### Anything else? This issue came out of evaluating the Velox Parquet reader/writer performance issues ([velox#17994](https://github.com/facebookincubator/velox/issues/17994), [velox#17988](https://github.com/facebookincubator/velox/issues/17988)) against paimon-cpp. Most of the reader-side items there do not apply, because Velox optimizes its own decoders while paimon-cpp reads through arrow 17, which already has the equivalents: - boolean batch decoding — arrow already has bulk paths (`CopyBitmap` for the null-free case, `BitBlockCounter` otherwise); - `BYTE_STREAM_SPLIT` — arrow 17 supports FLOAT / DOUBLE / INT32 / INT64 / FLBA; - `FIXED_LEN_BYTE_ARRAY` skip correctness — arrow's skip path is correct; - PDEP/PEXT dispatch — arrow already gates BMI2 on `CpuInfo::HasEfficientBmi2()`, which excludes AMD entirely. The items that *do* apply are tracked separately, and both need this benchmark to be evaluated properly. ### Are you willing to submit a PR? - [x] I'm willing to submit a PR! -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
