Skip to content

Commit 47b8dd2

Browse files
committed
DO NOT MERGE: diagnose DataFusion memory at TPC-H SF1000
Runs DataFusion Q1, Q2, Q9, Q16, Q18 and Q21 on Parquet and on Vortex under several scan settings, each with its own memory monitor, to test whether the Vortex excess scales with in-flight scan splits (scan concurrency x available parallelism per stream, one stream per DataFusion partition). Also records page-fault call stacks with perf and EXPLAIN plans for the queries that run out of memory. Adds a VORTEX_SCAN_CONCURRENCY env knob to datafusion-bench for the experiment only. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FDifRZhxcVd5gvt3dsDhu5
1 parent f0d3345 commit 47b8dd2

3 files changed

Lines changed: 91 additions & 27 deletions

File tree

‎.github/workflows/tpch-sf1000.yml‎

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@
88
# OOM-killed or times out is recorded and the rest still run, and system memory is sampled
99
# throughout data generation, conversion and every query.
1010

11-
name: TPC-H SF1000
11+
name: TPC-H SF1000 (OOM diagnosis)
1212

1313
concurrency:
14-
group: tpch-sf1000
14+
group: tpch-sf1000-oom-diag
1515
cancel-in-progress: false
1616

1717
on:
1818
# TEMPORARY: lets the branch run the workflow before it lands; drop this commit before merging.
1919
push:
20-
branches: [ji/tpch-sf1000-weekly]
20+
branches: [ji/tpch-sf1000-oom-diag]
2121
schedule:
2222
- cron: "17 2 * * 6" # weekly, Saturday
2323
workflow_dispatch:
@@ -102,7 +102,7 @@ jobs:
102102
strategy:
103103
fail-fast: false
104104
matrix:
105-
engine: ${{ fromJSON(inputs.engine == 'datafusion' && '["datafusion"]' || inputs.engine == 'duckdb' && '["duckdb"]' || '["datafusion", "duckdb"]') }}
105+
engine: [datafusion]
106106
runs-on: runs-on=${{ github.run_id }}/runner=bench-dedicated/family=${{ inputs.machine_type || 'c8gd.metal-24xl' }}/image=ubuntu24-full-arm64-pre-v2/tag=tpch-sf1000-${{ matrix.engine }}
107107
env:
108108
DATA_DIR: vortex-bench/data/tpch/${{ inputs.scale_factor || '1000.0' }}
@@ -185,32 +185,11 @@ jobs:
185185
echo idle > "$PHASE_FILE"
186186
du -sh "$DATA_DIR"/vortex-file-compressed/*
187187
188-
- name: Run ${{ matrix.engine }} queries
189-
id: queries
188+
- name: Diagnose DataFusion memory
190189
shell: bash
191190
env:
192191
RUST_BACKTRACE: "1"
193-
QUERIES: ${{ inputs.queries }}
194-
ITERATIONS: ${{ inputs.iterations || '1' }}
195-
QUERY_TIMEOUT_MINUTES: ${{ inputs.query_timeout_minutes || '45' }}
196-
run: |
197-
set -Eeuo pipefail
198-
# Leave the job time for the summary and uploads once the queries have used 9 hours.
199-
# Word splitting of $QUERIES is intended.
200-
# shellcheck disable=SC2086
201-
python3 scripts/bench-memory.py run-queries \
202-
--binary "target/release_debug/${{ matrix.engine }}-bench" \
203-
--engine "${{ matrix.engine }}" \
204-
--formats parquet vortex \
205-
${QUERIES:+--queries $QUERIES} \
206-
--iterations "$ITERATIONS" \
207-
--timeout "$(( QUERY_TIMEOUT_MINUTES * 60 ))" \
208-
--budget "$(( 9 * 3600 ))" \
209-
--opt scale-factor="$SCALE_FACTOR" \
210-
--out-dir "$OUT_DIR" \
211-
--phase-file "$PHASE_FILE" \
212-
--min-available-gib 8 \
213-
--fail-on-error
192+
run: bash scripts/tpch-oom-diag.sh
214193

215194
- name: Stop memory monitor
216195
if: always()

‎benchmarks/datafusion-bench/src/lib.rs‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,13 @@ fn vortex_table_options() -> VortexTableOptions {
116116

117117
opts.predicate_pushdown = true;
118118
opts.projection_pushdown = true;
119+
// DO NOT MERGE: diagnostic knob for the SF1000 OOM investigation.
120+
if let Some(concurrency) = std::env::var("VORTEX_SCAN_CONCURRENCY")
121+
.ok()
122+
.and_then(|v| v.parse().ok())
123+
{
124+
opts.scan_concurrency = Some(concurrency);
125+
}
119126

120127
opts
121128
}

‎scripts/tpch-oom-diag.sh‎

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#!/usr/bin/env bash
2+
3+
# SPDX-License-Identifier: Apache-2.0
4+
# SPDX-FileCopyrightText: Copyright the Vortex contributors
5+
6+
# DO NOT MERGE: diagnoses DataFusion memory at TPC-H SF1000.
7+
#
8+
# 1. Runs the heaviest queries under several scan settings, each with its own memory monitor, to
9+
# test whether the Vortex excess scales with in-flight scan splits
10+
# (VORTEX_SCAN_CONCURRENCY x available parallelism per stream, one stream per partition).
11+
# 2. Records page-fault call stacks with perf to show which code touches the new memory.
12+
# 3. Saves EXPLAIN plans for the queries that run out of memory.
13+
14+
set -Eeuo pipefail
15+
16+
BIN=${BIN:-target/release_debug/datafusion-bench}
17+
QUERIES=(1 2 9 16 18 21)
18+
RUNNER="ec2_${RUNS_ON_INSTANCE_TYPE:-unknown}"
19+
20+
run_variant() {
21+
local name=$1 formats=$2
22+
shift 2
23+
local dir="$OUT_DIR/$name"
24+
mkdir -p "$dir"
25+
python3 scripts/bench-memory.py monitor --output "$dir/memory.csv" --phase-file "$PHASE_FILE" --interval 1 &
26+
local monitor=$!
27+
# shellcheck disable=SC2086
28+
env "$@" python3 scripts/bench-memory.py run-queries \
29+
--binary "$BIN" --engine datafusion --formats $formats --queries "${QUERIES[@]}" \
30+
--timeout 1800 --opt scale-factor="$SCALE_FACTOR" --out-dir "$dir" \
31+
--phase-file "$PHASE_FILE" --min-available-gib 8 || true
32+
kill "$monitor" || true
33+
wait "$monitor" || true
34+
}
35+
36+
run_variant parquet-default parquet
37+
run_variant vortex-default vortex
38+
run_variant vortex-scan1 vortex VORTEX_SCAN_CONCURRENCY=1
39+
run_variant vortex-tp24 vortex DATAFUSION_EXECUTION_TARGET_PARTITIONS=24
40+
run_variant vortex-scan1-tp24 vortex VORTEX_SCAN_CONCURRENCY=1 DATAFUSION_EXECUTION_TARGET_PARTITIONS=24
41+
42+
echo "::group::EXPLAIN plans"
43+
"$BIN" tpch --explain --formats parquet,vortex --queries 9,18,21 --runner "$RUNNER" \
44+
--opt scale-factor="$SCALE_FACTOR" > "$OUT_DIR/explain.txt" 2>&1 || true
45+
echo "::endgroup::"
46+
47+
# Page faults mark the first touch of each new page, so their call stacks show what grows RSS.
48+
sudo -n apt-get install -y -qq linux-tools-common "linux-tools-$(uname -r)" > /dev/null 2>&1 \
49+
|| sudo -n apt-get install -y -qq linux-tools-generic > /dev/null 2>&1 || true
50+
PERF=$(command -v perf || find /usr/lib/linux-tools* -name perf -type f 2>/dev/null | head -1 || true)
51+
if [[ -n "$PERF" ]] && "$PERF" --version > /dev/null 2>&1; then
52+
sudo -n sysctl -w kernel.perf_event_paranoid=-1 > /dev/null || true
53+
profile() {
54+
local name=$1 format=$2 query=$3
55+
shift 3
56+
env "$@" "$PERF" record -e page-faults -c 2000 --call-graph fp -o "$OUT_DIR/$name.perf" -- \
57+
"$BIN" tpch --formats "$format" --queries "$query" --iterations 1 --hide-progress-bar \
58+
--runner "$RUNNER" --opt scale-factor="$SCALE_FACTOR" > /dev/null 2>&1 || true
59+
"$PERF" report -i "$OUT_DIR/$name.perf" --stdio --no-children --sort sym -g none \
60+
--percent-limit 0.5 > "$OUT_DIR/$name.flat.txt" 2>/dev/null || true
61+
"$PERF" report -i "$OUT_DIR/$name.perf" --stdio --no-children --sort sym \
62+
-g caller,1,callee,function,percent --percent-limit 3 2>/dev/null \
63+
| head -1500 > "$OUT_DIR/$name.graph.txt" || true
64+
rm -f "$OUT_DIR/$name.perf"
65+
}
66+
profile pagefaults-vortex-q01 vortex 1
67+
profile pagefaults-parquet-q01 parquet 1
68+
profile pagefaults-vortex-q16 vortex 16
69+
profile pagefaults-vortex-scan1-q01 vortex 1 VORTEX_SCAN_CONCURRENCY=1
70+
else
71+
echo "::warning::perf unavailable; skipping page-fault profiles"
72+
fi
73+
74+
for dir in "$OUT_DIR"/*/; do
75+
[[ -f "$dir/queries.jsonl" ]] || continue
76+
python3 scripts/bench-memory.py summarize --monitor-csv "$dir/memory.csv" \
77+
--queries-jsonl "$dir/queries.jsonl" --title "$(basename "$dir")" >> "$GITHUB_STEP_SUMMARY"
78+
done

0 commit comments

Comments
 (0)