nat-openai opened a new pull request, #6819:
URL: https://github.com/apache/datafusion-comet/pull/6819

   ## Which issue does this PR close?
   
   <!--
   We generally require a GitHub issue to be filed for all bug fixes and 
enhancements and this helps us generate change logs for our releases. You can 
link an issue to this PR using the GitHub syntax. For example `Closes #123` 
indicates that this PR will close issue #123.
   -->
   
   Partially addresses #5712: large integral-sequence performance and unbounded 
output allocations. The issue’s remaining follow-ups stay open.
   
   ## Rationale for this change
   
   <!--
    Why are you proposing this change? If this is already explained clearly in 
the issue then this section is not needed.
    Explaining clearly why changes are proposed helps reviewers understand your 
changes and offer better suggestions for fixes.
   -->
   
   Integral sequence currently limits the number of generated elements, but has 
no practical byte-based allocation limit. A single batch can allocate several 
gigabytes, and concurrent tasks or retained outputs can multiply that memory 
use. The native implementation also loses to Spark on the large shapes reported 
in #5712.
   
   This change bounds live sequence-buffer allocations and reduces sizing and 
generation overhead.
   
   Sequence buffers can outlive the producing native plan through Arrow clones, 
slices and JVM exports. Integrating these allocations into the general memory 
pool would require broader changes to propagate shared reservations across 
those ownership boundaries, charge each backing allocation precisely once, and 
release its reservation only after the final owner disappears. A dedicated 
executor-wide allowance provides a bounded solution without requiring that more 
invasive reservation-propagation work.
   
   The 256 MiB default is configurable independently of Spark’s 
execution-memory budget. Requests that exceed it fail before allocation; 
applications can reduce the batch size or raise the allowance at startup. It 
bounds live sequence backing buffers, rather than total native memory or 
process RSS.
   
   ## What changes are included in this PR?
   
   <!--
   There is no need to duplicate the description in the issue here but it is 
sometimes worth providing a summary of the individual changes in this PR.
   -->
   
   - Add spark.comet.exec.sequence.maxBytesPerExecutor, read from executor 
startup SparkConf, with a default of 256 MiB. Concurrent tasks share the 
outstanding-byte counter; SQL session changes cannot enlarge the allowance.
   - Validate and size the complete invocation before allocating. Account for 
values, offsets, optional validity and alignment padding, and retain each 
allocation’s charge through Arrow sharing and JVM exports.
   - Reduce kernel overhead by borrowing scalar inputs, using constant-size 
sizing scratch, allocating the final output capacity once, inlining small 
input-access helpers, and copying previously generated rows for larger repeated 
scalar outputs.
   - Generate and admit the full requested batch for scalar-only calls. Prevent 
constant folding into a list scalar whose later expansion could bypass 
admission.
   - Check the captured Spark task context during sizing and generation so 
cancellation releases partially constructed output.
   - Extend behavioural tests, benchmark coverage and documentation. Native 
eligibility remains limited to integral literal/column arguments; temporal 
sequences continue to use the dispatcher.
   
   The allowance fails immediately when a request does not fit; it does not 
spill or wait for another task to release memory. Existing Spark row-error 
behaviour and the batch list-offset ceiling are preserved.
   
   And LLM was used for for exploring potential solutions and implementing 
these commits.
   
   ## How are these changes tested?
   
   <!--
   We typically require tests for all PRs in order to:
   1. Prevent the code from being accidentally broken by subsequent changes
   2. Serve as another way to document the expected behavior of the code
   
   If tests are not included in your PR, please explain why (for example, are 
they covered by existing tests)?
   -->
   
   Native tests: 18 kernel/memory tests and the scalar-folding registration 
regression pass in release mode. Coverage includes all four integral widths, 
null/scalar inputs, arithmetic boundaries, error precedence, 
admission/refusal/recovery, concurrent reservations, clone/slice/FFI lifetimes, 
and cancellation/unwind cleanup.
   
   JVM tests: nine targeted tests pass on Spark 4.1.3, covering executor 
configuration, allocation refusal and recovery, native/fallback routing, 
captured-task cancellation, and the existing sequence.sql fixture.
   
   Build and checks: native release build, workspace all-target Clippy with 
warnings denied, Rust formatting, Spotless and whitespace checks pass.
   
   Before merge: the broader Spark SQL suite still needs the 
run-spark-4.1-tests CI gate.
   
   ### Performance
   
   `CometSequenceBenchmark` completed on Spark 4.1.3, Scala 2.13.17 and Java 17 
with `local[1]` and 8,192 rows. Integral endpoints were materialised Parquet 
columns. The benchmark explicitly raises the sequence allowance to **4 GiB** to 
measure large outputs.
   
   These are Spark Benchmark best/average timings, **not medians**:
   
   | Shape | Spark best / average (ms) | Comet best / average (ms) |
   |---|---:|---:|
   | 2 elements | 13 / 17 | 7 / 9 |
   | 5 elements | 10 / 13 | 5 / 7 |
   | 365 elements | 13 / 14 | 7 / 8 |
   | 1,000 elements | 17 / 18 | 9 / 11 |
   | 10,000 elements | 67 / 69 | 39 / 40 |
   | 50,000 elements | 270 / 272 | 167 / 169 |
   | Descending, 365 elements | 12 / 13 | 6 / 8 |
   | Explicit step 7 | 10 / 11 | 5 / 6 |
   | Sparse nulls, 365 elements | 12 / 13 | 6 / 8 |
   | Date dispatcher control | 11 / 13 | 16 / 18 |
   
   Comet is faster on all integral shapes in this run. These are fresh 
measurements from the current harness and Spark version; absolute timings are 
not directly comparable with the original issue’s report. Concurrent-task peak 
RSS was not measured.
   
   The native performance gains compared to the main branch come from 
simplifying the sizing and generation loops: values are written directly into 
fixed-capacity buffers, scalar inputs are borrowed instead of expanded into 
temporary arrays, and small value, null and length helpers are inlined to avoid 
repeated calls and intermediate structures. Larger repeated scalar sequences 
also reuse the first generated row through bulk copying. The largest 
improvements occur with column-valued endpoints producing hundreds or thousands 
of elements per row, where generation costs dominate: 365- and 10,000-element 
sequences are approximately 5× faster. Ordinary two- and five-element column 
sequences inly improve by about 10%.


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