andygrove opened a new issue, #6596:
URL: https://github.com/apache/datafusion-comet/issues/6596

   ### What is the problem the feature request solves?
   
   Comet's JVM columnar shuffle buffers Spark `UnsafeRow`s and converts them to 
Arrow natively, in `native/shuffle/src/spark_unsafe/`. I compared that 
converter with the JVM `ArrowWriter` row path that `CometSparkToColumnarExec` 
uses (#6566), on identical rows. Spark's `UnsafeProjection` generated the rows 
from the column shapes in `CometArrowWriterBenchmark`: one column, 8192 rows, 
every tenth row null.
   
   Per-row cost in ns:
   
   | Type                          | Native converter | JVM `ArrowWriter` |
   | ----------------------------- | ---------------- | ----------------- |
   | int, boolean                  | 2.3              | 4.0-5.2           |
   | decimal(18,2), decimal(38,10) | 2.4, 3.8         | 7.6, 13.4         |
   | struct<int,long,double,date>  | 11.4             | 22.3-22.7         |
   | array<int>, array<string>     | 9.1, 38          | 11.0-11.8, 32.9-35.7 |
   | string                        | 20-23            | 9.1-13            |
   | map<string,string>            | 149              | 65-86             |
   
   The native converter is two to three times faster on fixed-width types, 
decimals and structs, but it loses on strings and maps. Three per-value costs 
account for that.
   
   - **Map field names.** `append_map_elements` calls 
`get_map_key_value_fields` for every map value. That builds a `MapFieldNames`, 
allocating and freeing six strings, to read two field references. Resolving the 
fields once per batch takes `map<string,string>` from 149 to 73 ns per row.
   - **UTF-8 validation.** `get_string` checks each value with 
`decode_utf8_spark_lossy`, and its `str::from_utf8` call is about 7.5 of the 12 
ns that a short string takes. Checking `is_ascii()` first, and decoding only 
the values that are not ASCII, gives 5.1 ns with identical output. Validating a 
whole batch once, as `StringArray::try_new` does, gives 5.2. The same cost 
repeats for every key and value of a map: without it, `map<string,string>` 
drops to about 31 ns.
   - **Element arrays.** The `append_slice` bulk path only runs for map keys. 
Array elements and map values are appended one at a time, even when an array 
has no nulls. For arrays of 50 ints, a bulk copy when the array's null bitset 
is empty takes 51.7 ns per row down to 9.6. For arrays of zero to five elements 
the bulk copy is slightly slower than the loop, so it needs a length threshold.
   
   ### Describe the potential solution
   
   - Read a map's key and value fields without building `MapFieldNames`, which 
only `make_builders` needs.
   - Add an ASCII fast path to `decode_utf8_spark_lossy`.
   - Bulk-copy the elements of an array that has no nulls once it holds more 
than a few elements.
   
   ### Additional context
   
   Measured on an M3 Max with a release build (`-Ctarget-cpu=native`), timing 
`append_columns` plus `builder_to_array` per 8192-row batch and taking the best 
of 2000 batches. The JVM numbers come from the same rows through 
`ArrowWriter.write`. Other jobs were running on the machine, so treat the 
numbers as indicative.
   
   For fixed-width columns, compression costs more than conversion. The whole 
`process_sorted_row_partition` call for a `decimal(18,2)` column takes 2.4 ns 
per row to convert, and 14.6 with LZ4 encoding and the write.
   
   The default dictionary trial for top-level strings is a separate cost, 
tracked in {{B}}. Converting row input with `CometSparkToColumnarExec` and 
using native shuffle, instead of the JVM columnar shuffle, is tracked in {{C}}.
   


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