Skip to content

feat(presto/bench): config buffer tuning and benchmark robustness fixes - #390

Open
misiugodfrey wants to merge 9 commits into
mainfrom
misiug/bench-fixes-tuning
Open

feat(presto/bench): config buffer tuning and benchmark robustness fixes#390
misiugodfrey wants to merge 9 commits into
mainfrom
misiug/bench-fixes-tuning

Conversation

@misiugodfrey

@misiugodfrey misiugodfrey commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Low-risk correctness fixes and config tuning for Presto native benchmarks. Good first merge of this series.

Based on kjmph's bench33 POC patch.

  • run_benchmark.sh: add --maxfail=1 when --profile is set (avoids waiting for all queries when one fails during profiling runs); add PRESTO_BENCHMARK_KEEP_VENV escape hatch
  • common_functions.sh: replace jq-based wait_for_worker_node_registration with python3 JSON parse; fix broken while-loop that was not actually retrying correctly
  • common_fixtures.py: fix error handling for non-Presto exceptions in failed_queries_dict; move REST metrics collection outside the profiler interval so profiling overhead doesn't skew results; add PRESTO_SESSION_PROPERTIES env var for per-run session overrides
  • hive.properties: comment out SOFT_AFFINITY in base template; keep it in the CPU-specific override (overrides/cpu/) only — GPU experiments should opt in explicitly
  • Config overrides: exchange.max-response-size=64MB for CPU coordinator; lower CPU worker buffer defaults to 32MB; add local-exchange.max-buffer-size and largest-size-class-pages; tune GPU exchange/sink buffer sizes
  • .gitignore: add result_dir_*/ and latest_result_dir.txt (introduced by PR Land @bdice prototype workflows in main for testing #3 of this series)

Dependencies

None. This PR is self-contained and should merge first.

Note: common_functions.sh, run_benchmark.sh, and common_fixtures.py overlap with the open dmakkar/qol-fixes branch. The common_fixtures.py changes touch the same fixture function — whichever merges second will need a manual merge. Coordinate before landing.

Verification

  • Run a GPU TPC-H benchmark end-to-end on the NVL72 cluster
  • Run a CPU TPC-H benchmark with --profile; verify benchmark aborts after the first query failure instead of continuing through all 22 queries
  • Run presto/scripts/run_benchmark.sh and confirm the PRESTO_BENCHMARK_KEEP_VENV=1 escape hatch skips venv teardown
  • Verify wait_for_worker_node_registration retries correctly when workers are slow to register (previously the loop exited immediately on the first iteration)
  • Confirm common_fixtures.py metrics are collected after the profiler window closes (check that QueryStats REST calls don't appear inside the nsys/perf capture interval in logs)
  • Run ./ci/check_style.sh (ruff + codespell) on changed Python files

@copy-pr-bot

copy-pr-bot Bot commented Jul 27, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@misiugodfrey
misiugodfrey force-pushed the misiug/bench-fixes-tuning branch from 4d119ee to 4fd0ca2 Compare July 27, 2026 22:05
Based on kjmph's bench33 POC patch.

- run_benchmark.sh: add --maxfail=1 when --profile is set; add
  PRESTO_BENCHMARK_KEEP_VENV escape hatch to skip venv teardown
- common_functions.sh: replace jq-based worker registration wait with
  python3 JSON parse; fix while-loop so it actually retries correctly
- common_fixtures.py: fix error handling for non-Presto exceptions in
  failed_queries_dict; move REST metrics collection outside profiler
  interval; add PRESTO_SESSION_PROPERTIES env var support
- hive.properties: comment out SOFT_AFFINITY in base template; keep in
  CPU-specific override only
- Config overrides: exchange.max-response-size=64MB for CPU coordinator;
  lower buffer defaults to 32MB for CPU workers; add local-exchange and
  largest-size-class-pages knobs; tune GPU exchange/sink buffer sizes
- .gitignore: add result_dir_*/ and latest_result_dir.txt
@misiugodfrey
misiugodfrey force-pushed the misiug/bench-fixes-tuning branch from 4fd0ca2 to 47b0a20 Compare July 28, 2026 16:03
@copy-pr-bot

copy-pr-bot Bot commented Jul 28, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@misiugodfrey misiugodfrey self-assigned this Jul 29, 2026

# CPU UCX row pages and local exchange were tuned together. The generator
# reapplies these as overridable CPU_* values on every run.
local-exchange.max-buffer-size=536870912

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that these values can't have units associated with them (MB for instance), so we need to leave this as a byte value.

while true; do
if curl -s -f -o node_response.json "${COORDINATOR_URL}/v1/node"; then
node_count=$(python3 -c \
'import json, sys; print(len(json.load(open(sys.argv[1]))))' \

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replaced jq with python parsing since jq is not installed in the cluster/coordinator image by default.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we complete the jq dependency removal in the Slurm launcher as part of this change? presto/slurm/presto-nvl72/functions.sh still stages a static jq binary at lines 550–570 and prepends its directory to PATH at line 577. Thus, a clean run still downloads jq from GitHub before launching the benchmark. An environment without access can still fail even though jq is no longer used.

Hence, can we remove the jq download block and remove /workspace/.cache/bin PATH prefix from run_coord_image? The source patch, bench33.patch removed both pieces.

@misiugodfrey
misiugodfrey marked this pull request as ready for review July 29, 2026 18:47
@misiugodfrey
misiugodfrey requested a review from a team as a code owner July 29, 2026 18:47

@kjmph kjmph left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to the inline review comments, I see a few broader or lower-priority items:

  • The PR description says result_dir_<jobid>/ and latest_result_dir.txt were verified, but that behavior does not appear to be implemented by this PR's current head. The diff only adds related .gitignore entries. It looks like some validation may have included stacked changes from MultiProfile or bench33.patch. Could we rerun the stated validation from a clean checkout of this exact PR head, then either include the missing dependencies or update the checklist?

  • --iterations=0 --metrics reaches the metrics collection path without ever assigning a query cursor. It would be good to reject non-positive iteration counts during argument validation.

  • PRESTO_SESSION_PROPERTIES currently accepts an empty property name such as =value. Could we reject that locally and report which entry is malformed?

  • The CPU template comments advertise CPU_* overrides for the local-exchange and page-size settings, but the corresponding generator logic is not present in this PR. We should either port that plumbing or revise the comments so they describe what this patch supports.

The inline comments contain the changes I consider most important. My main overall feedback is ensuring that the final patch is self-contained.

# large distributed shuffles.
exchange.max-buffer-size=512MB
sink.max-buffer-size=512MB
exchange.max-response-size=64MB

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we pair this exchange.max-response-size increase with the coordinator’s HTTP content limit? With 64MB, Presto can request roughly 48 MB after its 75% encoding allowance, while exchange.http-client.max-content-length remains at its 32 MB default. I received errors on SF=30K when we went over this limit.

The source benchmark attempted to set the HTTP limit to 128 MB through --config-overrides, but that helper was replace-only for coordinator properties. Because this key was absent, the override was silently applied only to native workers and never reached the Java coordinator. Now that we have this in the coordinator, we can override in testing. Alternatively, we could also extend --config-overrides to allow new propertise.

I can test once this PR is merged, and if we still have problems, the conservative fix is to use exchange.max-response-size=32MB. Yet, I'm pretty sure we are narrowing down why the prior test hetting exchange.http-client.max-content-length didn't work.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll go with the 128MB pairing for max-content-length for now. Unless you think we should leave both as default and refine it further once we do some explicit testing?

local-exchange.max-buffer-size=536870912
exchange.max-buffer-size=512MB
sink.max-buffer-size=512MB
exchange.max-response-size=64MB

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a coordinator only setting.. Can we remove this in the GPU and CPU worker properties, so it isn't confusing in the future?

@misiugodfrey misiugodfrey Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed from both cpu/gpu worker properties. It looks like the workers silently ignore this option

exchange.max-buffer-size=32MB
sink.max-buffer-size=32MB
# Increase max bytes returned per exchange HTTP response to reduce round trips for large shuffles.
exchange.max-response-size=64MB

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, remove this here, as this pre-existed the commit, and I think what confused me.

Comment thread presto/slurm/presto-nvl72/functions.sh Outdated
${LOGS}:${vt_cufile_log_dir},\
${LOGS}:${vt_nsys_report_dir}${driver_mounts}${gds_mounts:+,${gds_mounts}}${worker_extra_mounts} \
${LOGS}:${vt_nsys_report_dir},\
${libcudf_cache}:/root/.libcudf${driver_mounts}${gds_mounts:+,${gds_mounts}}${worker_extra_mounts} \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lamarrr, @bdice, could you weigh in on the intended libcudf cache location here? The relevant cuDF version defaults LIBCUDF_KERNEL_CACHE_PATH to $HOME/.cudf, yes? This mounts the writable directory at /root/.libcudf.

Unless the environment variable is set elsewhere to /root/.libcudf, this mount will not cover cuDF’s default cache path. @lamarrr mentioned that a few different locations are tested, so maybe I'm mistaken.

Yet, I think this mount target should be $HOME/.cudf.. or should the launcher explicitly set LIBCUDF_KERNEL_CACHE_PATH=xx as in PR #398 ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll go with LIBCUDF_KERNEL_CACHE_PATH for now, but will update if we get further feedback.

sink.max-buffer-size=1GB
# Single-worker fallbacks. generate_presto_config.sh raises exchange/sink to
# 512MB whenever the full cluster has more than one worker.
exchange.max-buffer-size=32MB

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was the corresponding generate_presto_config.sh change intentionally omitted? The comment says these are single-worker fallbacks and that multi-worker clusters are raised to 512MB, but the generator in this PR never modifies exchange.max-buffer-size or sink.max-buffer-size.

Consequently, every worker in a newly generated multi-worker CPU run will use 32MB for both buffers. Before this PR, each worker used 1GB. The source patch, bench33.patch intended 512MB for multi-worker runs. The coordinator also does not receive the intended 512MB values.

Perhaps we port the buffer reconciliation from the bench33.patch after the numbered worker configurations have been created? Use 32MB for a single worker and 512MB for multiple workers? We can apply both properties with replace-or-append to the coordinator and every etc_worker_* configuration.

If that generator locic is intentionally deferred, perhaps we avoid lowering the static worker values in this PR and remove the comments promising behavior that will be present later?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the generator logic is deferred to the next PR (#391), but some of it leaked over. For now I'll have these switch to the 512MB values by default (the intended multi-worker values) and the subsequent PR can add the single-worker configuration.

# profiler interval. Otherwise CPU samples after query
# completion describe metrics collection and worker idling,
# rather than the engine work the profile is meant to measure.
if metrics:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this hunk was ported without the per-iteration profiling structure it depended on in the source patch.

Moving metrics collection outside the iteration loop means only the final iteration's Presto query ID is collected. With the default five iterations, the previous code produced five query-specific
metrics files. Yet, this produces one. If a later iteration fails, metrics are not collected for any earlier successful iteration.

It also does not currently move metrics outside the profiler interval. Profiling starts before the loop at line 133 and stops in the outer finally at line 176, after this call.

I suggest we either port the complete per-iteration profiling structure from the source patch, bench33.patch, or retain the current combined mode while recording every iteration's Presto query ID, stopping and waiting for the profiler after the loop. Then collect metrics for every recorded ID. We should verify that collection begins only after profiling has stopped.

while true; do
if curl -s -f -o node_response.json "${COORDINATOR_URL}/v1/node"; then
node_count=$(python3 -c \
'import json, sys; print(len(json.load(open(sys.argv[1]))))' \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we complete the jq dependency removal in the Slurm launcher as part of this change? presto/slurm/presto-nvl72/functions.sh still stages a static jq binary at lines 550–570 and prepends its directory to PATH at line 577. Thus, a clean run still downloads jq from GitHub before launching the benchmark. An environment without access can still fail even though jq is no longer used.

Hence, can we remove the jq download block and remove /workspace/.cache/bin PATH prefix from run_coord_image? The source patch, bench33.patch removed both pieces.

hive.node-selection-strategy=SOFT_AFFINITY
# Affinity scheduling is variant-specific. CPU enables soft affinity in its
# override; GPU can opt in explicitly when placement experiments require it.
# hive.node-selection-strategy=SOFT_AFFINITY

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upon review, could we preserve the existing Java benchmark behavior here? This shared coordinator template is also used by the Java variant. Commenting out SOFT_AFFINITY here and restoring it only in the CPU override changes Java from SOFT_AFFINITY to Presto's default NO_PREFERENCE.

The stated intent is to disable affinity for GPU while retaining it for CPU.. Yet, maybe we want to preserve the pre-PR behavior for Java but adding a Java coordinator override containing hive.node-selection-strategy=SOFT_AFFINITY?

If we are intentionally changing Java, perhaps it should be called out and validated explicitly..

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add it to java for now, although I'm pretty confident that we never confirmed if we want SOFT_AFFINITY for java runs or not. I think it makes sense not to change more behavior than intended - but I also want to flag that adding an explicit option here implies that this option's affect on the java worker is more empirically measured than it is.

user=user,
catalog="hive",
schema=schema,
session_properties=_session_properties_from_env(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this feature is intended for per-run optimizer and execution tuning, could we record the effective session properties in the benchmark results? They are currently passed to the Presto connection but are not included in run_context or the generated configuration snapshot.

Two runs using different PRESTO_SESSION_PROPERTIES can produce materially different plans and timings while appearing to have identical configurations in benchmark_result.json. post_results.py also filters context fields that are not declared in BenchmarkMetadata.

Perhaps we parse the properties once, and pass the resulting map to the connection while storing the same normalized map under a session_properties context field? We can add the corresponding field to BenchmarkMetadata so it survives result posting. Maybe the env var format should also be documented alongside the benchmark options?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added sessions_properties in the benchmark_results.json's context and the format is now documented.

# Provide a writable directory for libcudf's JIT/RTC cache. The container
# root filesystem is read-only squashfs, so /root/.libcudf is not writable
# without this mount.
local libcudf_cache="${SCRIPT_DIR}/libcudf_cache_${worker_id}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these per-worker cache directories remain after resolving the cache-path question above, could we keep them out of the working tree status? Each Slurm run creates libcudf_cache_<worker_id> beneath the tracked presto-nvl72 directory, but the current .gitignore covers worker_data* and not these new directories.

Shall we add presto/slurm/presto-nvl72/libcudf_cache_*/ to .gitignore, or place the cache beneath an existing ignored per-worker runtime directory. If the earlier cache-path change removes these separate directories, no additional change is needed.

_session_properties_from_env() calls os.environ.get() but os was not
imported, causing NameError on every presto_cursor fixture initialization.
The native worker rejects DataSize suffixes (MB) for this property;
express 512MB as raw bytes instead.
…iner

The container root is read-only squashfs so /root/.libcudf is not
writable, causing libcudf JIT/RTC cache creation to fail. Bind-mount
a per-worker host directory to provide the writable path.
…ning

# Conflicts:
#	presto/testing/performance_benchmarks/common_fixtures.py
@misiugodfrey
misiugodfrey force-pushed the misiug/bench-fixes-tuning branch from c28bd27 to 36de78f Compare August 5, 2026 18:34
- Remove jq download block and PATH prefix from run_queries; replace
  remaining jq-based wait_for_workers_to_register with python3
- Add exchange.http-client.max-content-length=128MB to GPU coordinator
  to pair with exchange.max-response-size=64MB (avoids client rejecting
  responses it requested at SF30K+)
- Remove exchange.max-response-size from GPU and CPU worker configs;
  native workers do not read this property (not in Configs.h)
- Fix libcudf cache mount target: /var/lib/presto/data/libcudf-cache
  matches LIBCUDF_KERNEL_CACHE_PATH set by PR #398 in the native image
- Port full per-iteration profiler structure (PROFILE_ITERATIONS env var,
  combined and per-iter modes) with CTAS integration; collect metrics
  per-iteration after each per-iter profiler stop
- Add java/etc_coordinator/catalog/hive.properties override to preserve
  SOFT_AFFINITY for Java benchmarks after it was removed from the shared
  template
- Record PRESTO_SESSION_PROPERTIES in benchmark_result.json context as
  session_properties; add field to BenchmarkMetadata; document format in
  _session_properties_from_env docstring; reject empty property names
- Reject --iterations < 1 at session start
- Set CPU worker exchange/sink buffers to 512MB (safe multi-worker
  default until generate_presto_config.sh reconciliation lands in #391);
  remove misleading comment promising generator behavior not in this PR
- Remove CPU_* generator promise comment from cpu/etc_worker template
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants