andygrove opened a new pull request, #7506:
URL: https://github.com/apache/datafusion-comet/pull/7506

   > [!WARNING]
   > **This is an experiment, and it will probably not be merged.** I opened it 
to share the code and numbers behind the discussion on #7504 about whether 
native columnar-to-row (C2R) is worth keeping. Please don't review it for merge.
   
   ## Which issue does this PR close?
   
   None. This is related to the discussion in #7504.
   
   ## Rationale for this change
   
   On #7504 the question came up of why Comet keeps the native C2R path when it 
is not the default and has not shown a clear win. I benchmarked the current 
native path, then tried two rounds of optimization to see whether a native C2R 
can beat the JVM path at all.
   
   Short answer: the current native C2R never beats the JVM codegen path end to 
end. The prototype here does win on decimal-heavy, wide and dictionary-encoded 
string schemas, ties on primitives and strings, and still loses on nested types.
   
   End-to-end results from `CometColumnarToRowBenchmark` (Comet native scan, 
then C2R, then a JVM sink; ns/row, lower is better; M3 Ultra, `local[1]`):
   
   | Schema | Comet JVM (codegen) | Native, current | Native, this prototype |
   |---|---|---|---|
   | TPC-H-like (4 x decimal(12,2), date, 2 strings) | 45.5 | 66.8 | **27.5** |
   | Same, rows consumed by a Scala UDF (fused codegen) | 46.7 | 67.3 | 
**28.7** |
   | Wide rows (50 columns) | 265 | 346 | **208** |
   | Dictionary-encoded strings | 42.8 | 62.3 | **31.4** |
   | Primitives | 33.0 | 67.9 | 32.8 |
   | Strings | 49.1 | 69.2 | 48.3 |
   | Fixed-width | 30.5 | 37.4 | 31.0 |
   | Struct | 162 | 193 | 190 |
   | Array | 86 | 113 | 110 |
   | Map | 180 | 229 | 223 |
   | TPC-H-like, 1% selective filter | 24.7 | 24.6 | 24.0 |
   
   The UDF-consumer row shows that the decimal win holds when the rows feed 
fused whole-stage codegen, not just a `noop` sink. In the isolated converter 
bench (`CometC2RIsolatedBench`), native is still 3 to 6 times slower at 32-row 
batches. That costs about 2 µs per batch, mostly JNI transitions.
   
   ## What changes are included in this PR?
   
   - **Flat path.** For schemas where every column is fixed-width, string, 
binary or decimal, the native side plans the row sizes, then writes the rows 
column by column straight into a JVM `byte[]`. The output is byte-identical to 
the existing row-at-a-time path, which a new Rust test checks.
   - **No per-row copy.** Each row is a new `UnsafeRow` over its batch's array. 
This keeps the guarantee that rows stay valid after later batches (#3308).
   - **Raw buffer path.** Plain, non-dictionary JVM vectors are passed as raw 
validity/offset/data buffer addresses instead of being exported through the 
Arrow C Data interface. Other columns use the C Data interface, with FFI 
structs reused across batches.
   - Unboxed row-count tracking in `NativeUtil.exportBatch`.
   - `-Dcomet.c2r.legacy=true` selects the old path for A/B runs.
   - Benchmark changes:
     - "legacy" and "optimized" native arms.
     - TPC-H-like groups: all rows, a UDF consumer, and a 1% selective filter.
     - Nested and long-string scenarios in the isolated bench.
   
   Known gaps and side findings:
   
   - Nested types still use the old row path. A real version would send them to 
the JVM path.
   - A batch whose rows exceed about 2 GiB fails with a clear error. A real 
version would split the batch into chunks (see #7494).
   - The raw path skips the lossy UTF-8 decode, so its output bytes match 
Spark's raw copy. This is a behavior change from the current native path.
   - The current `exportBatchToAddresses` allocates FFI structs per batch and 
never closes them. This is a separate leak, independent of this PR.
   - `GetPrimitiveArrayCritical` blocks GC while a batch is written.
   - I have not validated this on a cluster or on TPC-H at scale.
   
   ## How are these changes tested?
   
   - New Rust test `test_flat_path_matches_general_path`. It compares the flat 
path byte for byte against the existing conversion, covering nulls, slices, 
more than 64 columns, wide decimals and large binary.
   - `CometNativeColumnarToRowSuite` and `DirectColumnarToRowConverterSuite` 
pass (33 tests) with the prototype as the default.
   - Benchmarks as above.
   


-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to