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

   ## Which issue does this PR close?
   
   Closes #5770.
   
   ## Rationale for this change
   
   Two date/time paths rebuilt a `chrono` calendar datetime per row to produce 
a value that is a
   pure function of the epoch day or the microsecond-of-day. The reconstruction 
is the expensive
   part and neither field needs it.
   
   ## What changes are included in this PR?
   
   **1. `hour` / `minute` / `second` integer fast path** 
(`extract_date_part.rs`)
   
   When no timezone offset applies, the field is arithmetic on the stored 
microseconds and no
   datetime has to be built. That covers `TimestampNTZ` (already local 
wall-clock) and a
   timezone-aware timestamp in a UTC session -- `array_with_timezone` only 
re-tags such an array
   (`utils.rs`, the `Timestamp(Microsecond, Some(_))` arm calls `with_timezone` 
and returns), so the
   stored value is the UTC instant either way.
   
   The gate is deliberately narrow: dictionaries, non-microsecond units, and 
any session timezone
   outside a small zero-offset allowlist keep the existing `date_part` path, 
which is always
   correct. Euclidean division is load-bearing -- at UTC, `-1` us is 
`1969-12-31 23:59:59.999999`,
   so truncation toward zero would give the wrong field for pre-epoch instants.
   
   **2. Native `dayofweek` / `weekday` kernels** (new 
`datetime_funcs/day_of_week.rs`)
   
   The serde emitted `datepart('dow', child) + 1` and `datepart('isodow', 
child) - 1`. For `Date32`,
   arrow's `date_part` runs `unary_opt(|d| date32_to_datetime(d).map(..))` -- a 
`NaiveDateTime` per
   row plus a recomputed null mask -- and the `+1` / `-1` walked the result a 
second time in a
   separate plan node. Both collapse to one modulo of the epoch day, folded 
into the kernel so the
   arithmetic node is gone.
   
   The `Int32` cast the serde used to emit was already a no-op (`date_part` 
returns `Int32` for
   these parts and `cast.rs` short-circuits an identity cast), so it is not 
part of the win.
   
   ## How are these changes tested?
   
   New Rust unit tests:
   
   - `day_of_week.rs`: the week either side of the epoch pinning both numbering 
conventions, null
     preservation, the full `i32` domain, agreement between the two numberings 
across a 400-year
     Gregorian cycle, dictionary input, scalar input, and the non-date 
rejection path.
   - `extract_date_part.rs`: the UTC fast path against the general path on the 
same instant,
     pre-epoch instants (where truncation would diverge), null preservation, 
and a check that an
     offset session timezone is *not* accelerated.
   
   Existing coverage: the full `datafusion-comet-spark-expr` suite passes (731 
tests). On the Spark
   side `CometExpressionSuite` already exercises `weekday`/`dayofweek` under
   `checkSparkAnswerAndOperator` with and without dictionary encoding -- which 
fails if the
   expression stops running natively -- and this PR adds a date-column case 
covering the epoch week,
   leap days, the century rules, and dates at the edges of chrono's range. Both 
suites pass.
   
   ### Behaviour change worth noting
   
   For `dayofweek`/`weekday`, the old path returned NULL for epoch days outside 
chrono's range,
   because `date32_to_datetime` returns `None` there. The native kernel returns 
a correct weekday
   across the full `i32` domain. Spark's own date range is narrower, so no 
realistic query reaches
   those inputs, but the output is not bit-identical on them.
   
   ## Benchmarks
   
   Release profile, 8192-row batches, aarch64, quiet machine, two samples each. 
Both benchmarks
   assert the replacement is bit-identical to the path it replaces before 
timing anything.
   
   **`benches/extract_clock_fields.rs`** -- invokes the real UDFs, compared 
against a
   `--save-baseline main` capture on unmodified source:
   
   | shape | sample 1 | sample 2 |
   | --- | --- | --- |
   | `hour` / `minute` / `second`, NTZ, no nulls | -87.5% / -92.3% / -91.7% | 
-87.5% / -92.3% / -91.7% |
   | `hour` / `minute` / `second`, UTC session, no nulls | -96.4% / -95.2% / 
-93.2% | -95.8% / -95.0% / -93.3% |
   | NTZ, sparse nulls | -87.6% / -83.7% / -84.6% | -87.3% / -83.1% / -83.9% |
   | UTC session, sparse nulls | -91.6% / -89.2% / -89.8% | -90.9% / -88.1% / 
-90.0% |
   | `America/Los_Angeles` (keeps the general path) | -0.9% to -21.4% | -2.2% 
to -23.1% |
   
   No shape regressed. The offset-timezone path is untouched code and drifts 
slightly faster.
   
   **`benches/dayofweek_weekday.rs`** -- both arms run in the same process (a 
cross-run baseline is
   impossible: the native kernels do not exist on `main`):
   
   | shape | old chain | native kernel | sample 1 | sample 2 |
   | --- | --- | --- | --- | --- |
   | `dayofweek`, no nulls | 39.4 us | 4.06 us | 9.71x | 9.30x |
   | `dayofweek`, sparse nulls | 32.7 us | 3.47 us | 9.42x | 8.35x |
   | `weekday`, no nulls | 40.6 us | 3.99 us | 10.17x | 8.96x |
   | `weekday`, sparse nulls | 46.8 us | 7.42 us | 6.30x | 8.67x |
   
   Two samples are reported because on this hardware a library change shifts 
codegen enough to move
   *unrelated* bench arms by up to 60% reproducibly, so single cross-run deltas 
below roughly +/-20%
   on these benches are not trustworthy. The figures above are either far 
outside that band or are
   same-process comparisons.
   
   A third target from the issue -- a year-only Gregorian split for 
`iceberg_years` -- is
   deliberately **not** included. It improved that transform by 30-54%, but 
reproducibly slowed
   `iceberg_days` sparse-null shapes by 16-24% through codegen layout, which 
the no-regression gate
   in `optimizing_expressions.md` does not allow. Details and numbers are in
   
https://github.com/apache/datafusion-comet/issues/5770#issuecomment-5586112182.
   


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