@@ -26,6 +26,10 @@ For full instructions on running these benchmarks on an EC2 instance, see the [C
2626
2727[ Comet Benchmarking on EC2 Guide ] : https://datafusion.apache.org/comet/contributor-guide/benchmarking_aws_ec2.html
2828
29+ ## Setup
30+
31+ TPC queries are bundled in ` benchmarks/tpc/queries/ ` (derived from TPC-H/DS under the TPC Fair Use Policy).
32+
2933## Usage
3034
3135All benchmarks are run via ` run.py ` :
@@ -55,10 +59,9 @@ export SPARK_HOME=/opt/spark-3.5.3-bin-hadoop3/
5559export SPARK_MASTER=spark://yourhostname:7077
5660```
5761
58- Set path to queries and data :
62+ Set path to data (TPC queries are bundled in ` benchmarks/tpc/queries/ ` ) :
5963
6064``` shell
61- export TPCH_QUERIES=/mnt/bigdata/tpch/queries/
6265export TPCH_DATA=/mnt/bigdata/tpch/sf100/
6366```
6467
@@ -135,9 +138,9 @@ $SPARK_HOME/bin/spark-submit \
135138 --master $SPARK_MASTER \
136139 --packages org.apache.iceberg:iceberg-spark-runtime-3.5_2.12:1.8.1 \
137140 --conf spark.driver.memory=8G \
138- --conf spark.executor.instances=1 \
141+ --conf spark.executor.instances=2 \
139142 --conf spark.executor.cores=8 \
140- --conf spark.cores.max=8 \
143+ --conf spark.cores.max=16 \
141144 --conf spark.executor.memory=16g \
142145 create-iceberg-tables.py \
143146 --benchmark tpch \
@@ -166,7 +169,6 @@ export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
166169export COMET_JAR=/opt/comet/comet-spark-spark3.5_2.12-0.10.0.jar
167170export ICEBERG_JAR=/path/to/iceberg-spark-runtime-3.5_2.12-1.8.1.jar
168171export ICEBERG_WAREHOUSE=/mnt/bigdata/iceberg-warehouse
169- export TPCH_QUERIES=/mnt/bigdata/tpch/queries/
170172sudo ./drop-caches.sh
171173python3 run.py --engine comet-iceberg --benchmark tpch
172174```
@@ -185,6 +187,172 @@ physical plan output.
185187| ` --catalog ` | No | ` local ` | Iceberg catalog name |
186188| ` --database ` | No | benchmark name | Database name for the tables |
187189
190+ ## Running with Docker
191+
192+ A Docker Compose setup is provided in ` infra/docker/ ` for running benchmarks in an isolated
193+ Spark standalone cluster. The Docker image supports both ** Linux (amd64)** and ** macOS (arm64)**
194+ via architecture-agnostic Java symlinks created at build time.
195+
196+ ### Build the image
197+
198+ The image must be built for the correct platform to match the native libraries in the
199+ engine JARs (e.g. Comet bundles ` libcomet.so ` for a specific OS/arch).
200+
201+ ``` shell
202+ docker build -t comet-bench -f benchmarks/tpc/infra/docker/Dockerfile .
203+ ```
204+
205+ ### Building a compatible Comet JAR
206+
207+ The Comet JAR contains platform-specific native libraries (` libcomet.so ` / ` libcomet.dylib ` ).
208+ A JAR built on the host may not work inside the Docker container due to OS, architecture,
209+ or glibc version mismatches. Use ` Dockerfile.build-comet ` to build a JAR with compatible
210+ native libraries:
211+
212+ - ** macOS (Apple Silicon):** The host JAR contains ` darwin/aarch64 ` libraries which
213+ won't work in Linux containers. You ** must** use the build Dockerfile.
214+ - ** Linux:** If your host glibc version differs from the container's, the native library
215+ will fail to load with a ` GLIBC_x.xx not found ` error. The build Dockerfile uses
216+ Ubuntu 20.04 (glibc 2.31) for broad compatibility. Use it if you see
217+ ` UnsatisfiedLinkError ` mentioning glibc when running benchmarks.
218+
219+ ``` shell
220+ mkdir -p output
221+ docker build -t comet-builder \
222+ -f benchmarks/tpc/infra/docker/Dockerfile.build-comet .
223+ docker run --rm -v $( pwd) /output:/output comet-builder
224+ export COMET_JAR=$( pwd) /output/comet-spark-spark3.5_2.12-* .jar
225+ ```
226+
227+ ### Platform notes
228+
229+ ** macOS (Apple Silicon):** Docker Desktop is required.
230+
231+ - ** Memory:** Docker Desktop defaults to a small memory allocation (often 8 GB) which
232+ is not enough for Spark benchmarks. Go to ** Docker Desktop > Settings > Resources >
233+ Memory** and increase it to at least 48 GB (each worker requests 16 GB for its executor
234+ plus overhead, and the driver needs 8 GB). Without enough memory, executors will be
235+ OOM-killed (exit code 137).
236+ - ** File Sharing:** You may need to add your data directory (e.g. ` /opt ` ) to
237+ ** Docker Desktop > Settings > Resources > File Sharing** before mounting host volumes.
238+
239+ ** Linux (amd64):** Docker uses cgroup memory limits directly without a VM layer. No
240+ special Docker configuration is needed, but you may still need to build the Comet JAR
241+ using ` Dockerfile.build-comet ` (see above) if your host glibc version doesn't match
242+ the container's.
243+
244+ The Docker image auto-detects the container architecture (amd64/arm64) and sets up
245+ arch-agnostic Java symlinks. The compose file uses ` BENCH_JAVA_HOME ` (not ` JAVA_HOME ` )
246+ to avoid inheriting the host's Java path into the container.
247+
248+ ### Start the cluster
249+
250+ Set environment variables pointing to your host paths, then start the Spark master and
251+ two workers:
252+
253+ ``` shell
254+ export DATA_DIR=/mnt/bigdata/tpch/sf100
255+ export RESULTS_DIR=/tmp/bench-results
256+ export COMET_JAR=/opt/comet/comet-spark-spark3.5_2.12-0.10.0.jar
257+
258+ mkdir -p $RESULTS_DIR /spark-events
259+ docker compose -f benchmarks/tpc/infra/docker/docker-compose.yml up -d
260+ ```
261+
262+ Set ` COMET_JAR ` , ` GLUTEN_JAR ` , or ` ICEBERG_JAR ` to the host path of the engine JAR you
263+ want to use. Each JAR is mounted individually into the container, so you can easily switch
264+ between versions by changing the path and restarting.
265+
266+ ### Run benchmarks
267+
268+ Use ` docker compose run --rm ` to execute benchmarks. The ` --rm ` flag removes the
269+ container when it exits, preventing port conflicts on subsequent runs. Pass
270+ ` --no-restart ` since the cluster is already managed by Compose, and ` --output /results `
271+ so that output files land in the mounted results directory:
272+
273+ ``` shell
274+ docker compose -f benchmarks/tpc/infra/docker/docker-compose.yml \
275+ run --rm -p 4040:4040 bench \
276+ python3 /opt/benchmarks/run.py \
277+ --engine comet --benchmark tpch --output /results --no-restart
278+ ```
279+
280+ The ` -p 4040:4040 ` flag exposes the Spark Application UI on the host. The following
281+ UIs are available during a benchmark run:
282+
283+ | UI | URL |
284+ | ----------------- | ---------------------- |
285+ | Spark Master | http://localhost:8080 |
286+ | Worker 1 | http://localhost:8081 |
287+ | Worker 2 | http://localhost:8082 |
288+ | Spark Application | http://localhost:4040 |
289+ | History Server | http://localhost:18080 |
290+
291+ > ** Note:** The Master UI links to the Application UI using the container's internal
292+ > hostname, which is not reachable from the host. Use ` http://localhost:4040 ` directly
293+ > to access the Application UI.
294+
295+ The Spark Application UI is only available while a benchmark is running. To inspect
296+ completed runs, uncomment the ` history-server ` service in ` docker-compose.yml ` and
297+ restart the cluster. The History Server reads event logs from ` $RESULTS_DIR/spark-events ` .
298+
299+ For Gluten (requires Java 8), you must restart the ** entire cluster** with ` JAVA_HOME `
300+ set so that all services (master, workers, and bench) use Java 8:
301+
302+ ``` shell
303+ export BENCH_JAVA_HOME=/usr/lib/jvm/java-8-openjdk
304+ docker compose -f benchmarks/tpc/infra/docker/docker-compose.yml down
305+ docker compose -f benchmarks/tpc/infra/docker/docker-compose.yml up -d
306+
307+ docker compose -f benchmarks/tpc/infra/docker/docker-compose.yml \
308+ run --rm bench \
309+ python3 /opt/benchmarks/run.py \
310+ --engine gluten --benchmark tpch --output /results --no-restart
311+ ```
312+
313+ > ** Important:** Only passing ` -e JAVA_HOME=... ` to the ` bench ` container is not
314+ > sufficient -- the workers also need Java 8 or Gluten will fail at runtime with
315+ > ` sun.misc.Unsafe ` errors. Unset ` BENCH_JAVA_HOME ` (or switch it back to Java 17)
316+ > and restart the cluster before running Comet or Spark benchmarks.
317+
318+ ### Memory limits
319+
320+ Two compose files are provided for different hardware profiles:
321+
322+ | File | Workers | Total memory | Use case |
323+ | --------------------------- | ------- | ------------ | ------------------------------ |
324+ | ` docker-compose.yml ` | 2 | ~ 74 GB | SF100+ on a workstation/server |
325+ | ` docker-compose-laptop.yml ` | 1 | ~ 12 GB | SF1–SF10 on a laptop |
326+
327+ ** ` docker-compose.yml ` ** (workstation default):
328+
329+ | Container | Container limit (` mem_limit ` ) | Spark JVM allocation |
330+ | -------------- | ----------------------------- | ------------------------- |
331+ | spark-worker-1 | 32 GB | 16 GB executor + overhead |
332+ | spark-worker-2 | 32 GB | 16 GB executor + overhead |
333+ | bench (driver) | 10 GB | 8 GB driver |
334+ | ** Total** | ** 74 GB** | |
335+
336+ Configure via environment variables: ` WORKER_MEM_LIMIT ` (default: 32g per worker),
337+ ` BENCH_MEM_LIMIT ` (default: 10g), ` WORKER_MEMORY ` (default: 16g, Spark executor memory),
338+ ` WORKER_CORES ` (default: 8).
339+
340+ ### Running on a laptop with small scale factors
341+
342+ For local development or testing with small scale factors (e.g. SF1 or SF10), use the
343+ laptop compose file which runs a single worker with reduced memory:
344+
345+ ``` shell
346+ docker compose -f benchmarks/tpc/infra/docker/docker-compose-laptop.yml up -d
347+ ```
348+
349+ This starts one worker (4 GB executor inside an 8 GB container) and a 4 GB bench
350+ container, totaling approximately ** 12 GB** of memory.
351+
352+ The benchmark scripts request 2 executor instances and 16 max cores by default
353+ (` run.py ` ). Spark will simply use whatever resources are available on the single worker,
354+ so no script changes are needed.
355+
188356### Comparing Parquet vs Iceberg performance
189357
190358Run both benchmarks and compare:
0 commit comments