This is an automated email from the ASF dual-hosted git repository.
andygrove pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-ballista.git
The following commit(s) were added to refs/heads/main by this push:
new d738ca9bd docs: refresh benchmarking.md with current SF1000 results
(Ballista main @ 696ca29b, Spark 3.4 baseline) (#2161)
d738ca9bd is described below
commit d738ca9bd6b86aecaf9587af9025ae0dd12c5af1
Author: Andy Grove <[email protected]>
AuthorDate: Thu Jul 23 16:25:57 2026 -0600
docs: refresh benchmarking.md with current SF1000 results (Ballista main @
696ca29b, Spark 3.4 baseline) (#2161)
* docs: refresh benchmarking.md with current SF1000 Ballista results
Replace the homelab-era result set with a fresh TPC-H SF1000 run captured
on a 32-executor Kubernetes cluster with data on S3, and trim the
surrounding narrative.
- Pin the commit under test (696ca29b) and record versions, environment,
and Ballista/DataFusion configuration together.
- Publish Q1-Q19 mean times (2 iterations); mark Q20-Q22 as FAIL on this
configuration.
- Drop the stale Spark/Comet comparison columns; a fresh comparison at
this cluster shape will be added in a follow-up.
Signed-off-by: Andy Grove <[email protected]>
* docs: add Spark 3.4 baseline to benchmarking.md
Include the Spark 3.4 (vanilla, no acceleration) column in the results
table and a Spark configuration highlights section, so the same-cluster
baseline is documented alongside the Ballista numbers.
Signed-off-by: Andy Grove <[email protected]>
* docs: note Spark task/CPU oversubscription in benchmarking.md
spark.executor.cores=16 is task parallelism, not CPU allocation. The
executor pods get 8 physical vCPU via spark.kubernetes.executor.limit.cores,
so Spark schedules 16 concurrent tasks on 8 physical cores. Call this out
alongside Ballistas 1:1 (--concurrent-tasks=8) sizing.
Signed-off-by: Andy Grove <[email protected]>
* docs: prettier format benchmarking.md
Signed-off-by: Andy Grove <[email protected]>
* docs: refresh benchmarking.md with 64 GiB executor run
Refresh the SF1000 results with a new run captured on the same commit
(696ca29b), same cluster shape, but with executor pod memory raised
32 -> 64 GiB (DataFusion memory pool auto-scales to ~44.8 GiB, still 70 %
of container). --concurrent-tasks stays at 8.
Trade-off vs the previous 32 GiB run:
- Q1-Q17 sum 1980 -> 868 s (-44 %). Big wins on the join-heavy queries:
Q5/Q7/Q9/Q17 each -60 % to -67 %; Q8 -43 %.
- Q18 and Q19, which completed at 32 GiB, do not complete at this sizing
and are recorded as FAIL alongside Q20-Q22.
Signed-off-by: Andy Grove <[email protected]>
* docs: refresh benchmarking.md with clean 22-query run
Ballista now completes the full TPC-H SF1000 suite at this commit and
cluster shape, so drop the FAIL rows and publish a full Q1-Q22 result set
plus a Q1-Q22 total.
Also record that the Python benchmark client (BallistaSessionContext) needs
a 64 GiB pod memory limit to run the whole suite in one job: with a smaller
limit the client OOMs midway through, even though the executor cluster is
healthy. This is a client-side sizing note, not an executor tuning knob.
Suite total: Ballista 1353 s vs Spark 3.4 845 s (SF1000, 32 executors x
8 vCPU x 64 GiB, AQE on, 1 iteration).
Signed-off-by: Andy Grove <[email protected]>
---------
Signed-off-by: Andy Grove <[email protected]>
---
docs/source/contributors-guide/benchmarking.md | 476 +++++++------------------
1 file changed, 134 insertions(+), 342 deletions(-)
diff --git a/docs/source/contributors-guide/benchmarking.md
b/docs/source/contributors-guide/benchmarking.md
index 94b608623..fb3b911bf 100644
--- a/docs/source/contributors-guide/benchmarking.md
+++ b/docs/source/contributors-guide/benchmarking.md
@@ -19,384 +19,176 @@
# Benchmarking
-This page describes how Ballista is benchmarked at scale, and records the
current
-results. It is aimed at contributors who want to reproduce a number,
understand why
-a comparison is set up the way it is, or add a result of their own.
+Current TPC-H **SF1000** results for Ballista, compared against a vanilla
+**Spark 3.4** baseline running on the same cluster shape.
-The benchmark used here is derived from TPC-H. For running TPC-H locally at
small
-scale factors, see [`benchmarks/README.md`][bench-readme] in the repository;
this
-page covers the multi-node, large-scale-factor setup and the cross-engine
-comparisons.
+## Versions under test
-[bench-readme]:
https://github.com/apache/datafusion-ballista/blob/main/benchmarks/README.md
-
-## What we measure, and why
-
-Ballista's central performance question is **how evenly work is spread across
-executor tasks**. A distributed query is only as fast as its slowest stage,
and a
-stage is only as fast as its slowest task, so a query whose work concentrates
onto
-a few partitions will underperform no matter how fast the underlying operators
are.
-Benchmarks are therefore run at a scale where that imbalance actually shows up.
-
-These benchmarks are run with **adaptive query execution (AQE) enabled**
-(`ballista.planner.adaptive.enabled=true`). This is the configuration Ballista
is
-being actively developed against, so it is the one measured here.
-
-AQE selects the adaptive planner, which can re-plan stages using runtime
statistics —
-coalescing partitions, re-optimising joins, and promoting a small join side to
a
-broadcast at runtime. The alternative, AQE off, selects the static
-`DefaultDistributedPlanner`; it is a different planner with materially
different join
-behaviour, and it is no longer benchmarked on this page.
+| Engine | Version
|
+| -------- |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
+| Ballista |
[`696ca29b`](https://github.com/apache/datafusion-ballista/commit/696ca29b3c1fe3013238822b7f5d8cdb918fdaa3)
(`main`, 2026-07-23), Cargo pkg `54.0.0`, DataFusion `54.1.0` |
+| Spark | 3.4 (vanilla, no acceleration plugin)
|
## Environment
-The results on this page currently come from a **small homelab cluster**: two
-bare-metal nodes running Kubernetes, with the TPC-H data staged on node-local
disk.
-This is a deliberate starting point rather than a final destination. A two-node
-cluster with local disk removes as many confounds as possible — no object-store
-latency, no cloud network variance, no noisy neighbours — so that when a query
is
-slow, the cause is Ballista and not the environment.
-
-The intent is to **move these benchmarks to AWS with data in S3** once the
results
-here are good. That environment is the one users actually run, and it exercises
-things a homelab cannot: object-store reads instead of local disk, higher and
more
-variable network latency between executors, and larger executor counts. Some of
-Ballista's behaviour is expected to change there — a shuffle that is cheap
over a
-local link is not cheap over a cloud network, and object-store reads make scan
-parallelism matter differently.
-
-So results on this page should be read as **relative comparisons on controlled
-hardware**, useful for "did this change help", not as absolute throughput
numbers
-for a cloud deployment.
-
-## Reference cluster
-
-All results on this page use the following shape. It is a reference point, not
a
-requirement — the commands below work on any cluster, but numbers are only
-comparable when the shape matches.
-
-| | |
-| ------------------- | ------------------------------------------- |
-| Executors | 2, one per physical node |
-| Per executor | 16 cores, 56 GiB, `--memory-pool-size=48GB` |
-| Per task slot | 16 concurrent tasks → 3 GB pool each |
-| Scheduler | 1 |
-| Data | TPC-H SF1000 Parquet, node-local disk |
-| `target_partitions` | 64 |
-
-Two details matter more than they look:
-
-- **Executors are spread one per node.** Packing two executors onto one node
makes
- them contend for the same disk and memory bandwidth, which is measuring the
host,
- not the engine.
-- **Data is on node-local disk, not object storage.** With a modest network
between
- nodes, reading from object storage makes the interconnect the bottleneck and
the
- engine comparison becomes an I/O comparison.
-
-The memory pool is deliberately set below the container limit. Ballista splits
-`--memory-pool-size` into one `FairSpillPool` per task slot, and that
accounting
-does not cover every allocation, so leaving headroom between the pool and the
-container limit avoids the container being killed outright instead of
reporting a
-graceful resource error.
+- **Cluster:** Kubernetes on AWS (`us-west-2`); one driver/scheduler pod and
+ 32 executor pods for each engine, launched on the same node pool.
+- **Executor pod (Ballista):** x86_64, 8 vCPU, 64 GiB memory.
+- **Executor pod (Spark):** x86_64, 8 vCPU, 64 GiB + 10 GiB overhead.
+- **Client pod (Ballista):** the Python benchmark runner submits SQL to
+ Ballista via `BallistaSessionContext` and collects results locally.
+ Requires 64 GiB memory limit to complete the full 22-query suite —
+ smaller limits (16 GiB) OOM the client partway through, even though the
+ executor cluster is healthy.
+- **Data:** TPC-H SF1000 Parquet on S3 (`us-west-2`), ZSTD compression,
+ ~512 MiB row groups, one directory per table.
+
+## Ballista configuration
+
+| Flag / config key | Value
|
+| ------------------------------------------------------------- |
------------- |
+| `--concurrent-tasks` | `8`
|
+| `--memory-pool-size` (bytes; ≈70 % of the 64 GiB container) |
`48103633715` |
+| `datafusion.execution.target_partitions` | `256`
|
+| `datafusion.execution.collect_statistics` | `true`
|
+| `datafusion.execution.listing_table_factory_infer_partitions` | `false`
|
+| `datafusion.catalog.information_schema` | `true`
|
+| `ballista.planner.adaptive.enabled` | `true` (AQE)
|
+| `ballista.shuffle.sort_based.memory_limit_per_task_bytes` | `0`
|
+
+`datafusion.optimizer.prefer_hash_join` is left at its default; under AQE the
+join strategy is selected at runtime by `DelayJoinSelectionRule` /
+`DynamicJoinSelectionExec` from runtime statistics and the broadcast /
+`ballista.optimizer.hash_join_max_build_partition_bytes` thresholds.
+
+## Spark configuration (highlights)
+
+Vanilla Spark 3.4 — no Comet plugin, stock `SortShuffleManager`.
+
+| Key | Value
|
+| ---------------------------------------------------------- |
------------------------------------ |
+| `spark.executor.instances` | `32`
|
+| `spark.executor.cores` | `16` (task
parallelism per executor) |
+| `spark.kubernetes.executor.limit.cores` / `.request.cores` | `8` (physical
vCPU) |
+| `spark.executor.memory` | `64G`
|
+| `spark.executor.memoryOverhead` | `10G`
|
+| `spark.memory.fraction` | `0.6`
|
+| `spark.memory.storageFraction` | `0.2`
|
+| `spark.sql.shuffle.partitions` | `512`
|
+| `spark.sql.broadcastTimeout` | `900`
|
+| `spark.serializer` |
`KryoSerializer` |
+| `spark.io.compression.codec` | `zstd`
|
+
+Spark AQE is left at its Spark 3.4 defaults. Shuffle spills to a `gp3`-backed
+per-executor volume (`spark.kubernetes.executor.volumes...spark-local-dir-1`).
+
+Note that `spark.executor.cores=16` is Spark's **task parallelism** setting,
+not a CPU allocation — each executor pod is given only **8 physical vCPU**
+via `spark.kubernetes.executor.limit.cores` / `.request.cores`, so Spark
+schedules 16 concurrent tasks onto 8 physical cores (2× oversubscription).
+The matching Ballista executor runs `--concurrent-tasks=8` on the same
+8 physical vCPU (1:1).
## Queries
-All engines run the **same SQL**, which is what makes a cross-engine comparison
-apples-to-apples.
+The SQLBench-H phrasing of the 22 TPC-H queries from
+[apache/datafusion-benchmarks](https://github.com/apache/datafusion-benchmarks).
-The shared set is the TPC-H queries from [apache/datafusion-benchmarks][dfb]
-(SQLBench-H). Ballista's bundled queries in `benchmarks/queries/` are the
classic
-TPC-H phrasing and differ in places, so the shared set is overlaid over them
for a
-comparison run.
-
-Spark and Comet are driven through Comet's benchmark harness, which reads its
own
-bundled copy of the queries (labelled CometBench-H). That copy is textually
-identical to the SQLBench-H set — all 22 queries match once the licence header
-comment is ignored — so the engines are executing the same statements even
though
-they load them from different paths. Worth re-checking if either set is ever
-regenerated.
-
-[dfb]: https://github.com/apache/datafusion-benchmarks
+## Results
-## Running the benchmark
+**Times in seconds; lower is better.** Ballista: single iteration. Spark:
+mean of 3 iterations (cold iteration dropped by the harness).
+
+| Query | Ballista (s) | Spark 3.4 (s) |
+| -----------------: | -----------: | ------------: |
+| 1 | 21.16 | 67.58 |
+| 2 | 32.37 | 29.80 |
+| 3 | 32.69 | 25.13 |
+| 4 | 27.75 | 21.19 |
+| 5 | 49.37 | 54.12 |
+| 6 | 16.17 | 1.23 |
+| 7 | 48.24 | 19.57 |
+| 8 | 189.30 | 48.60 |
+| 9 | 154.88 | 69.38 |
+| 10 | 67.72 | 35.92 |
+| 11 | 26.72 | 30.88 |
+| 12 | 24.46 | 10.78 |
+| 13 | 18.36 | 20.45 |
+| 14 | 19.93 | 7.00 |
+| 15 | 27.56 | 23.75 |
+| 16 | 18.03 | 23.41 |
+| 17 | 60.46 | 82.30 |
+| 18 | 282.79 | 129.40 |
+| 19 | 23.28 | 11.26 |
+| 20 | 88.93 | 19.22 |
+| 21 | 110.87 | 101.53 |
+| 22 | 12.17 | 12.71 |
+| **Total (Q1–Q22)** | **1353.21** | **845.21** |
+
+Row counts agree across engines for every query. Ballista completed the
+full 22-query suite in a single continuous run.
+
+## Reproducing
### Ballista
-Start a scheduler and one executor per node:
+Bring up the cluster (one scheduler, N executors), then run the suite from a
+client. Executor sizing on each node:
```sh
-# scheduler
-ballista-scheduler --bind-host 0.0.0.0 --bind-port 50050
-
-# executor (one per node; --concurrent-tasks defaults to the detected core
count)
ballista-executor \
- --bind-host 0.0.0.0 \
+ --bind-host 0.0.0.0 --bind-port 50051 \
--scheduler-host <scheduler> --scheduler-port 50050 \
- --memory-pool-size=48GB \
- --work-dir /work \
- --client-ttl=60
+ --concurrent-tasks 8 \
+ --memory-pool-size 48103633715
```
-`--client-ttl=60` enables shuffle-client connection caching. Without it every
-shuffle fetch opens a new connection, and a high `target_partitions` can
exhaust
-ephemeral ports.
-
-Run a query:
+Run all 22 queries:
```sh
tpch benchmark ballista \
--host <scheduler> --port 50050 \
- --query 18 \
- --path /mnt/bigdata/tpch/sf1000 --format parquet \
- --partitions 64 --iterations 1 \
- -c ballista.planner.adaptive.enabled=true
+ --path s3://<bucket>/tpch/sf1000 --format parquet \
+ --partitions 256 --iterations 2 \
+ -c ballista.planner.adaptive.enabled=true \
+ -c datafusion.execution.collect_statistics=true \
+ -c ballista.shuffle.sort_based.memory_limit_per_task_bytes=0
```
-Omit `--query` to run all 22, and add `--skip <n>` (repeatable) to leave
individual
-queries out of that run — `--skip 18` is what produced the Ballista column
below.
-`ballista.planner.adaptive.enabled=true` is the AQE-on configuration these
results
-use.
-
-Note that `datafusion.optimizer.prefer_hash_join` is deliberately left at its
default.
-Under AQE it does not select the join strategy: `DelayJoinSelectionRule` folds
both
-`HashJoinExec` and `SortMergeJoinExec` into a single
`DynamicJoinSelectionExec`, and
-the strategy is then chosen from runtime statistics — the broadcast
thresholds, and
-`ballista.optimizer.hash_join_max_build_partition_bytes` (64 MiB by default),
which
-lowers a Partitioned hash join to the spillable `SortMergeJoin` when the build
side's
-largest partition would not fit. Setting `prefer_hash_join=false` does not
force
-sort-merge; it only changes which conversion path the plan takes, and the
-`SortMergeJoinExec` path discards the join's projection, so it measures a
slower plan
-rather than a different join strategy.
-
### Spark
-Spark runs the same queries via `tpcbench.py` from
-[apache/datafusion-benchmarks][dfb]:
+Runs the same queries via `tpcbench.py` from
+[apache/datafusion-benchmarks](https://github.com/apache/datafusion-benchmarks),
+with the highlights above and stock Spark 3.4 defaults for everything else:
```sh
spark-submit \
--master <master> \
- --conf spark.executor.instances=2 \
+ --conf spark.executor.instances=32 \
--conf spark.executor.cores=16 \
- --conf spark.executor.memory=32G \
- --conf spark.executor.memoryOverhead=8G \
- --conf spark.memory.offHeap.enabled=true \
- --conf spark.memory.offHeap.size=16g \
- --conf spark.comet.enabled=false \
- --conf
spark.shuffle.manager=org.apache.spark.shuffle.sort.SortShuffleManager \
+ --conf spark.executor.memory=64G \
+ --conf spark.executor.memoryOverhead=10G \
+ --conf spark.sql.shuffle.partitions=512 \
tpcbench.py \
--benchmark tpch \
- --data /mnt/bigdata/tpch/sf1000 \
+ --data s3a://<bucket>/tpch/sf1000 \
--format parquet \
- --iterations 1 \
- --query 18
+ --iterations 3
```
-`spark.comet.enabled=false` and the stock `SortShuffleManager` are what make
this a
-**vanilla** Spark baseline, in case the image being used ships Comet.
-
-### Comet
-
-[Apache DataFusion Comet][comet] accelerates Spark by translating supported
-operators to DataFusion. Same queries, same sizing; the difference is the
plugin,
-the Comet shuffle manager, and the jar on the classpath:
-
-```sh
-spark-submit \
- --master <master> \
- --jars $COMET_JAR --driver-class-path $COMET_JAR \
- --conf spark.executor.extraClassPath=$COMET_JAR \
- --conf spark.plugins=org.apache.spark.CometPlugin \
- --conf
spark.shuffle.manager=org.apache.spark.sql.comet.execution.shuffle.CometShuffleManager
\
- --conf spark.comet.exec.replaceSortMergeJoin=false \
- --conf spark.comet.exec.memoryPool=fair_unified \
- --conf spark.comet.exec.memoryPool.fraction=0.8 \
- --conf spark.executor.instances=2 \
- --conf spark.executor.cores=16 \
- --conf spark.executor.memory=32G \
- --conf spark.executor.memoryOverhead=8G \
- --conf spark.memory.offHeap.enabled=true \
- --conf spark.memory.offHeap.size=16g \
- tpcbench.py \
- --benchmark tpch \
- --data /mnt/bigdata/tpch/sf1000 \
- --format parquet \
- --iterations 1 \
- --query 18
-```
-
-`spark.comet.exec.replaceSortMergeJoin=false` keeps Comet on Spark's
`SortMergeJoin`
-instead of converting it to a shuffled hash join.
-
-This no longer pins the two engines to the same join strategy. Ballista under
AQE
-chooses per join at runtime — broadcast, Partitioned hash, or sort-merge — and
there
-is no supported way to force it to sort-merge throughout (see the note in the
Ballista
-section above). So a Ballista-vs-Comet gap may partly reflect different join
-strategies, not only different execution. Read the comparison with that in
mind.
-
-[comet]: https://datafusion.apache.org/comet/
-
-## Why compare against Comet
-
-Comet is the most informative comparison available to Ballista, because
**Comet and
-Ballista execute DataFusion physical plans using the same DataFusion
operators**.
-The scan, filter, join, and aggregate implementations doing the work are
largely
-shared code. When Ballista and Comet diverge on a query, the difference
therefore
-points at what is _not_ shared — how work is distributed, scheduled, shuffled,
and
-bounded by memory — rather than at the speed of the operators themselves. That
is
-precisely the surface Ballista is trying to improve, which makes the comparison
-diagnostic rather than merely competitive.
-
-That said, **the two do not necessarily run the same plan shape**, and the
numbers
-should not be read as an operator-level A/B:
-
-- **Different planners produce the plan.** Comet accelerates a plan that
_Spark's_
- optimizer produced: Spark chooses the join order and join strategies, and
- **Spark's AQE** coalesces shuffle partitions, converts joins, and splits
skewed
- partitions at runtime. Ballista plans with DataFusion's optimizer and, when
- enabled, its own experimental AQE. Spark's AQE is a mature implementation and
- Ballista's is not, so the same SQL can arrive at execution with materially
- different plans.
-- **Comet falls back to Spark.** Operators and expressions Comet does not
support
- stay on the JVM, so a Comet run is generally a mix of DataFusion and Spark
- execution rather than an all-DataFusion one.
-- **The distribution models differ.** Comet executes within Spark's task model
and
- shuffle service; Ballista has its own scheduler, stage/task model, and
shuffle.
-
-So a Comet-vs-Ballista gap is best read as a question — _what is Spark's
planner or
-execution model doing here that Ballista's is not?_ — rather than as a verdict
on
-DataFusion. Vanilla Spark is included as the third data point, since it
isolates
-how much of any Comet result comes from DataFusion acceleration versus from
Spark's
-planner.
-
-## Results
-
-TPC-H **SF1000**, reference cluster above, **AQE on**, 1 iteration,
-`target_partitions=64`, all Ballista join settings at their defaults. Ballista
picks
-each join's strategy at runtime; Spark and Comet are held to `SortMergeJoin`.
Times in
-seconds; lower is better.
-
-Versions under test:
-
-| Engine | Version |
-| -------- | ----------------------------------------------- |
-| Ballista | `#2124` @ `5290436d` |
-| Spark | 3.5.3 (vanilla, Comet disabled) |
-| Comet | `main` @ `b0165552` (1.0.0-SNAPSHOT, Spark 3.5) |
-
-Pin the **exact commit** the numbers came from, not "main": `main` moves, and
a row
-that mixes numbers from different commits silently misattributes a regression.
-
-The Ballista column comes from a **single suite run of 21 queries** on freshly
-started executors, using `--skip 18` to leave out the one query that exhausts
the
-memory pool and OOM-kills the executors (see below), which would otherwise
wedge
-the rest of the suite. Comet and Spark each completed the full suite in one
run.
-
-Keep the whole column to one continuous run wherever possible. Driving queries
as
-individual single-query jobs measures something different: each job starts
against
-a cold page cache, which on this cluster cost the two join-free queries (Q1,
Q6)
-roughly 20 s and 20 s respectively when the two methods were compared
directly. Use
-`--skip` rather than a loop of `--query` runs.
-
-Single iteration means **run-to-run variance is not quantified here**.
Comparing the
-same commit across the two methods above showed spreads of up to ~20% on
individual
-queries, so treat a per-query difference under about 20% as noise and read the
total
-row instead.
-
-| Query | Spark | Comet | Ballista (AQE on) | Rows
|
-| --------------------: | ---------: | ---------: | ----------------: | -----:
|
-| 1 | 427.1 | 46.6 | 54.2 | 4
|
-| 2 | 75.9 | 39.2 | 60.3 | 100
|
-| 3 | 154.1 | 195.4 | 140.0 | 10
|
-| 4 | 82.0 | 42.6 | 46.3 | 5
|
-| 5 | 336.4 | 493.4 | 327.2 | 5
|
-| 6 | 28.9 | 14.6 | 27.2 | 1
|
-| 7 | 180.6 | 149.5 | 364.9 | 4
|
-| 8 | 391.8 | 642.1 | 481.1 | 2
|
-| 9 | 509.8 | 843.5 | 606.4 | 175
|
-| 10 | 151.1 | 104.8 | 148.4 | 20
|
-| 11 | 44.7 | 44.1 | 62.0 | 0 [1]
|
-| 12 | 74.1 | 49.9 | 58.3 | 2
|
-| 13 | 98.7 | 58.3 | 100.4 | 30
|
-| 14 | 43.0 | 27.4 | 71.1 | 1
|
-| 15 | 121.5 | 65.6 | 53.8 | 1 [2]
|
-| 16 | 24.5 | 17.5 | 34.3 | 27840
|
-| 17 | 406.7 | 285.8 | 417.8 | 1
|
-| 18 | 428.8 | 370.5 | TBD | 100
|
-| 19 | 58.9 | 35.5 | 68.5 | 1
|
-| 20 | 105.9 | 67.6 | 93.7 | 110759
|
-| 21 | 562.2 | 460.1 | 698.0 | 100
|
-| 22 | 36.8 | 21.5 | 22.9 | 7
|
-| **Total (excl. Q18)** | **3914.7** | **3705.0** | **3936.8** |
|
-
-The **Total** row sums the 21 queries **excluding Q18**, because Q18 has no
Ballista
-figure at this commit (below), so a 22-query total would not be comparable
across
-engines. Spark's and Comet's Q18 times are in its row.
-
-Row counts agree across all three engines on every query for which Ballista
produced
-a result.
-
-The **AQE-off** Ballista column has been removed pending a re-run at a matched
core
-count; the numbers above for AQE off were taken at a different executor size
and are
-not comparable to a fresh AQE-off run, so they were dropped rather than left
stale.
-
-[1] Q11 returns 0 rows for every engine at this scale factor: the query's
threshold
-constant is tuned for SF1.
-
-[2] Q15 is a multi-statement query (`CREATE VIEW` / `SELECT` / `DROP VIEW`);
all three
-engines report 1 row here. (A previous result set saw Spark report 0 for Q15
depending
-on which statement the harness took as the result; it does not recur in this
run.)
-
-**Q18 is not measured at this commit.** Q18's hash-join build side is
`Partitioned`
-and does not spill; with 16 task slots sharing the 48 GB pool (3 GB per slot),
the
-per-task build side exceeds the container limit and the executor is OOM-killed
-([#2025](https://github.com/apache/datafusion-ballista/issues/2025)). At the
previous
-8-slot sizing (6 GB per slot) Q18 completed, so this is a direct consequence
of the
-denser packing.
-
-It was excluded from the suite run above with `--skip 18` so that one query
could not
-wedge the other 21, and it has not since been run to completion at this commit
— hence
-`TBD` rather than `OOM`. An earlier attempt on this branch did OOM-kill an
executor,
-but under a different configuration (`prefer_hash_join=false`, which sends the
plan
-down a conversion path that discards the join's projection and so materialises
more
-columns than the configuration documented above). That result does not
transfer, so it
-is not recorded here.
-
-The `Rows` column is the row count the query returned, recorded so a time is
never
-read without the answer it produced.
-
-This table records **one current result set**. When results are refreshed, the
-table and the pinned versions above are replaced together — a row must never
mix
-numbers from different commits, because a stale row silently misattributes a
-regression.
-
-`TBD` means not yet measured on this cluster at this commit; a query that ran
but
-did not produce an answer is recorded as `FAIL`, or `OOM` where the failure is
a
-known memory exhaustion.
-
-### Recording a result
+## Recording a new result set
- Pin the **exact commit** the numbers came from, not a branch name.
-- Report the **AQE-on** number (`ballista.planner.adaptive.enabled=true`) — the
- configuration this page measures — from the same commit and cluster.
-- Prefer the figure from a **full suite run**, not a standalone single-query
run: a
- long-lived executor deep into a suite is not in the same state as a freshly
started
- one, and a single-query job pays a cold-cache penalty that is large enough
to swamp
- the effect being measured. When a query cannot complete in-suite (e.g. Q18's
OOM
- currently wedges the run), exclude it with `--skip <n>` so the rest of the
column
- still comes from one continuous run, and measure that query separately.
-- Note the **row count** each query returned. A fast wrong answer is not a
result,
- and distributed execution has produced silently wrong row counts before.
-- Flag any stage whose runtime is dominated by a few partitions — that is the
- imbalance this page exists to surface.
-
-## Known issues found by benchmarking
-
-Benchmarking at SF1000 is how most of the following were found. They are worth
-knowing about before interpreting a number:
-
-| Issue | Summary
|
-| ------------------------------------------------------------------ |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-| [#1359](https://github.com/apache/datafusion-ballista/issues/1359) |
Umbrella issue for adaptive (AQE) query execution.
|
-| [#2025](https://github.com/apache/datafusion-ballista/issues/2025) | Q18's
hash-join build side exhausts the memory pool at SF1000. DataFusion's hash-join
build side does not spill, so a per-partition build side larger than one task
slot's pool fails the task outright. |
-| [#2063](https://github.com/apache/datafusion-ballista/issues/2063) | AQE can
hang when a re-plan cancels an in-flight stage; the job never reports
completion.
|
+- Replace the version, environment, config, and results tables together — a
+ row that mixes numbers from different commits silently misattributes a
+ regression.
+- Prefer a single continuous suite run: a long-lived executor deep into a
+ suite is not in the same state as a freshly started one.
+- Report `FAIL` for a query that ran but did not produce an answer, and
+ `OOM` when the failure is a known memory exhaustion. See the tracker for
+ open issues found by benchmarking: [#1359][aqe],
+ [#2025][q18], [#2063][aqe-hang].
+
+[aqe]: https://github.com/apache/datafusion-ballista/issues/1359
+[q18]: https://github.com/apache/datafusion-ballista/issues/2025
+[aqe-hang]: https://github.com/apache/datafusion-ballista/issues/2063
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]