Skip to content

Commit 2b497c8

Browse files
Rich-T-kidclaude
andcommitted
feat(benchmarks): add dict_encoding_sweep harness
Introduces `dict_encoding_sweep`, a focused benchmark driver that compares `Dictionary<Int32, Utf8>` against `Utf8View` for the same operator across a cardinality sweep. For each cell it generates two in-memory tables sharing identical values, runs the same SQL against each, and reports median / min / p25 / p75 runtimes to CSV so the dict vs view crossover is directly visible. The harness covers scan, filter, project, aggregation, sort, join, limit, repartition, coalesce_batches, coalesce_partitions, and spm groups. The README section documents operator groups, flags, and CSV schema so other contributors can reproduce the numbers without touching the harness. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 9551051 commit 2b497c8

4 files changed

Lines changed: 1329 additions & 0 deletions

File tree

‎benchmarks/README.md‎

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,3 +1144,80 @@ adjacent chunks at RG boundaries.
11441144
./bench.sh run sort_pushdown_inexact
11451145
./bench.sh run sort_pushdown_inexact_overlap
11461146
```
1147+
1148+
## Dictionary vs Utf8View Encoding Sweep
1149+
1150+
`dict_encoding_sweep` compares `Dictionary<Int32, Utf8>` against `Utf8View` for
1151+
the same operator across a cardinality sweep. For each cell it generates two
1152+
in-memory tables (one per encoding) that share values, SQL text, and seed; it
1153+
then interleaves warmup + timed iterations of both encodings so cache and
1154+
thermal state stay symmetric. Median / min / p25 / p75 runtimes (nanoseconds)
1155+
are appended to a CSV.
1156+
1157+
The intent is to make it easy for other engineers to reproduce where dictionary
1158+
encoding wins, where it loses, and at which NDV it crosses over, without
1159+
touching the harness itself.
1160+
1161+
### Operator groups
1162+
1163+
Pass `--group` to pick one of:
1164+
1165+
| Group | Queries |
1166+
|-------|---------|
1167+
| `scan` | `scan_k`, `scan_all`, `scan_count_star`, `scan_count_k` |
1168+
| `filter` | `filter_eq`, `filter_ne`, `filter_in10`, `filter_like_prefix`, `filter_gt`, `filter_1pct_group` |
1169+
| `project` | `proj_length`, `proj_substr`, `proj_upper`, `proj_concat`, `proj_case_like` |
1170+
| `aggregation` | `agg_count_distinct_k`, `agg_group_count_k`, `agg_group_sum_v_k`, `agg_group_count_kw`, `agg_having_k` |
1171+
| `sort` | `sort_k`, `sort_k_desc`, `sort_k_limit_1000`, `sort_kw`, `sort_v_by_k` |
1172+
| `join` | `join_inner`, `join_inner_project`, `join_left`, `join_semi`, `join_anti_half` |
1173+
| `limit` | `limit_k_100`, `limit_k_1k`, `limit_k_10k`, `limit_all_1k`, `limit_offset_50k` |
1174+
| `repartition` | `repart_group_k`, `repart_hash_join`, `repart_project_k` |
1175+
| `coalesce_batches` | `cb_filter_eq`, `cb_filter_project`, `cb_filter_group` |
1176+
| `coalesce_partitions` | `cp_scan_k`, `cp_count_star`, `cp_sum_v` |
1177+
| `spm` | `spm_sort_k`, `spm_sort_k_limit`, `spm_sort_v_by_k` |
1178+
1179+
Narrow to one query with `--query <id>`.
1180+
1181+
### Running
1182+
1183+
```bash
1184+
# build release binary (one time)
1185+
cargo build --release --bin dict_encoding_sweep -p datafusion-benchmarks
1186+
1187+
# single cell: filter group, 1M rows, sweep over NDVs
1188+
./target/release/dict_encoding_sweep \
1189+
--group filter --rows 1000000 \
1190+
--ndvs 10,100,500,1000,4000,8192 \
1191+
--iters 15 --warmups 3 \
1192+
--output /tmp/dict_sweep/filter_1m.csv
1193+
```
1194+
1195+
Useful flags:
1196+
1197+
| Flag | Default | Notes |
1198+
|------|---------|-------|
1199+
| `--group` | required | Operator group (see table above). |
1200+
| `--query` | all | Restrict to a single query id within the group. |
1201+
| `--rows` | required | Rows in the generated table. |
1202+
| `--ndvs` | required | Comma-separated distinct-value counts to sweep. |
1203+
| `--width` | `16` | Fixed byte width per value. |
1204+
| `--nulls` | `0.0` | Null fraction in column `k`. |
1205+
| `--batch-size` | `8192` | Session + record-batch size. |
1206+
| `--target-partitions` | `1` | Set `>1` to force `RepartitionExec` nodes. |
1207+
| `--dict-chunk` | `500000` | Rows per shared dictionary values-array chunk. |
1208+
| `--iters` | `15` | Timed iterations per cell per encoding. |
1209+
| `--warmups` | `3` | Untimed warmup iterations per cell per encoding. |
1210+
1211+
### CSV schema
1212+
1213+
The output CSV uses one row per `(encoding, cell)`. Columns:
1214+
1215+
```
1216+
git_sha, group, query_id, encoding, rows, ndv, width_bytes, null_rate,
1217+
batch_size, dict_chunk_rows, process_id,
1218+
median_ns, min_ns, p25_ns, p75_ns, iters, note
1219+
```
1220+
1221+
Pair the two rows for the same cell by `(group, query_id, rows, ndv,
1222+
width_bytes, null_rate, batch_size, dict_chunk_rows)` and divide
1223+
`dict.median_ns / view.median_ns` to get the per-cell speedup.

0 commit comments

Comments
 (0)