[SPARK-57562][SQL] Add benchmarks for the TIME data type#56809
[SPARK-57562][SQL] Add benchmarks for the TIME data type#56809shrirangmhalgi wants to merge 8 commits into
Conversation
MaxGekk
left a comment
There was a problem hiding this comment.
1 blocking, 2 non-blocking, 0 nits.
Clean, well-modeled benchmark mirroring DateTimeBenchmark. One blocking process issue: the committed results must come from the standard CI hardware, not a local Mac.
Design / architecture (1)
*-results.txt: results were regenerated on Apple M3 Pro / macOS instead of the standard CI hardware (Linux / Intel Xeon Platinum 8370C, used by the existing committed results). This rewrites every number in the three modified files, not just the new TIME cases (ExtractBenchmark +104/-86, CSVBenchmark +56/-51, JsonBenchmark +82/-77), so the numbers are no longer comparable against the rest of the repo and the unrelated churn obscures the PR's actual contribution. Please regenerate all four results files via the "Benchmarks" GitHub Actions workflow and drop the local Mac-generated output.
Correctness (1)
- CSVBenchmark.scala:197 (same pattern at JsonBenchmark.scala:414):
timesgenerator(t % 86400000000L) * 1000000L— see inline.
Suggestions (1)
- ExtractBenchmark.scala:72: the
case othermessage"Valid column types are 'timestamp' and 'date'"is now stale — it omits the newly-added'time'(and the pre-existing'interval'). Only reachable on a programming error, so optional, but worth updating while you're here.
|
|
||
| def times = { | ||
| spark.range(0, rowsNum, 1, 1).mapPartitions { iter => | ||
| iter.map(t => LocalTime.ofNanoOfDay((t % 86400000000L) * 1000000L)) |
There was a problem hiding this comment.
The (t % 86400000000L) * 1000000L formula is inconsistent and latently unsafe:
- The modulus is micros/day (
86_400_000_000) but the scale factor is*1e6, so the two don't compose into nanos-of-day. - Since
t < rowsNum(1e7) is far below the modulus, the% 86400000000Lis a dead no-op, and the generated times only span the first ~2.8h of the day rather than the full day. - It would overflow
LocalTime.ofNanoOfDay(max86399999999999) ifrowsNumis ever raised above ~8.64e7.
It doesn't fail at the current rowsNum, but consider aligning with TimeBenchmark's full-day wrap (nanos % 86400000000000L):
| iter.map(t => LocalTime.ofNanoOfDay((t % 86400000000L) * 1000000L)) | |
| iter.map(t => LocalTime.ofNanoOfDay(t % 86400000000000L)) |
|
|
||
| def times = { | ||
| spark.range(0, rowsNum, 1, 1).mapPartitions { iter => | ||
| iter.map(t => LocalTime.ofNanoOfDay((t % 86400000000L) * 1000000L)) |
There was a problem hiding this comment.
Same generator issue as CSVBenchmark.scala:197: (t % 86400000000L) * 1000000L has an inconsistent modulus/scale (micros/day mod, *1e6 scale), the % 86400000000L is a dead no-op at this rowsNum, the times don't span a full day, and it would overflow ofNanoOfDay if rowsNum exceeded ~8.64e7. Suggest the same full-day wrap as TimeBenchmark:
| iter.map(t => LocalTime.ofNanoOfDay((t % 86400000000L) * 1000000L)) | |
| iter.map(t => LocalTime.ofNanoOfDay(t % 86400000000000L)) |
### What changes were proposed in this pull request? Add TimeBenchmark covering TIME data type functions: current_time, make_time, to_time, hour/minute/second extraction, time_trunc, time_diff, TIME +/- interval, and LocalTime conversion/collection. ### Why are the changes needed? The SPIP (SPARK-51162, Q6) flagged performance regressions as the main risk. There was no TIME-specific benchmark until now. ### Does this PR introduce _any_ user-facing change? No. Benchmark only. ### How was this patch tested? Benchmark runs successfully and results file is generated. ### Was this patch authored or co-authored using generative AI tooling? Co-Authored using Claude Opus 4.6
c620316 to
ad5c3c5
Compare
|
Thanks @MaxGekk for the review! All addressed:
|
ad5c3c5 to
b6ae6d2
Compare
MaxGekk
left a comment
There was a problem hiding this comment.
2 addressed, 1 remaining, 0 new.
Thanks for the quick turnaround — the generator fix, the ExtractBenchmark message, and the reverted results churn all look good, and the new TIME feature-gating (spark.sql.timeType.enabled) is correct.
Design / architecture — remaining (1)
TimeBenchmark-results.txtis still generated on Apple M3 Pro / macOS. The three modified results files are reverted andHashBenchmark-results.txtis correctly on Linux CI now, butTimeBenchmark-results.txtstill carries Mac numbers — and the reverted CSV/Json/Extract results no longer include the new TIME cases their.scalafiles add. Please finish the GitHub Actions "Benchmarks" regeneration so all of them come from the standard Linux hardware rather than a local Mac.
…e error message - Fix LocalTime generator: use t % 86400000000000L (nanos/day) instead of inconsistent (t % 86400000000L) * 1000000L in CSV and JSON benchmarks - Revert ExtractBenchmark/CSV/JSON/Hash results to master (drop Mac output; will regenerate via GitHub Actions Benchmarks workflow) - Update ExtractBenchmark error message to list all valid types
727e46b to
098bfd2
Compare
…nchmark (JDK 17, Scala 2.13, split 1 of 1)
…tBenchmark (JDK 17, Scala 2.13, split 1 of 1)
….JsonBenchmark (JDK 17, Scala 2.13, split 1 of 1)
…CSVBenchmark (JDK 17, Scala 2.13, split 1 of 1)
|
@MaxGekk. I regenerated all four results files ( |
MaxGekk
left a comment
There was a problem hiding this comment.
1 addressed, 0 remaining, 1 new.
The round-2 provenance blocker is resolved — all four sql/core results files are now regenerated on the standard Linux CI runner (17.0.19 / Linux 6.17 azure) and include the TIME cases. Thanks! One new inconsistency this round:
Design / architecture — new (1)
- HashBenchmark.scala:128: the
.scalaadds atimecolumn butHashBenchmark-results.txtwas reverted to master (no time column, old hardware) — see inline.
| .add("binary", BinaryType) | ||
| .add("date", DateType) | ||
| .add("timestamp", TimestampType) | ||
| .add("time", TimeType()) |
There was a problem hiding this comment.
This adds a time column to the normal hash schema, but HashBenchmark-results.txt was reverted to upstream/master in this commit — it still has the old hardware header (17.0.18 / Linux 6.14) and no time column. Round 2 (727e46b) had this file correctly regenerated on CI, so the benchmark runs fine; this commit just dropped the regenerated results while keeping the schema change.
Your note mentions regenerating "all four" results files (the sql/core ones); HashBenchmark lives in sql/catalyst and is a fifth modified benchmark whose results were missed. As committed, the benchmark code and its results file are out of sync. Please regenerate HashBenchmark-results.txt on the CI runner too (so it reflects the new time column), or drop this HashBenchmark schema change if it's out of scope for the PR.
|
Thank you @MaxGekk. Good catch - the revert dropped the earlier CI-generated
|
…la 2.13, split 1 of 1)
What changes were proposed in this pull request?
Add TIME data type benchmarks:
TimeBenchmarkcovering current_time, make_time, to_time, hour/minute/second extraction, time_trunc, time_diff, TIME +/- interval, and LocalTime conversion/collectionExtractBenchmark: add TIME cases (HOUR, MINUTE, SECOND)JsonBenchmark: add TIME write/read casesCSVBenchmark: add TIME write/read casesHashBenchmark: add TIME column to normal schemaAdd
TimeBenchmarkcovering TIME data type functions:current_time,make_time,to_time, hour / minute / second extraction,time_trunc,time_diff, TIME + / - interval, andLocalTimeconversion / collection.Why are the changes needed?
The SPIP (SPARK-51162, Q6) flagged performance regressions as the main risk. There was no TIME-specific benchmark until now.
Does this PR introduce any user-facing change?
No. Benchmark only.
How was this patch tested?
All five benchmarks run successfully. Results generated via GitHub Actions Benchmarks workflow on Linux CI (AMD EPYC 7763 / OpenJDK 17.0.19).
Was this patch authored or co-authored using generative AI tooling?
Co-Authored using Claude Opus 4.6