Skip to content

Serialize engine config in new pdsh benchmark CLI - #22572

Merged
rapids-bot[bot] merged 3 commits into
NVIDIA:release/26.06from
TomAugspurger:tom/serialize-config-backport
May 19, 2026
Merged

Serialize engine config in new pdsh benchmark CLI#22572
rapids-bot[bot] merged 3 commits into
NVIDIA:release/26.06from
TomAugspurger:tom/serialize-config-backport

Conversation

@TomAugspurger

Copy link
Copy Markdown
Contributor

Description

This backports a pair of commits for the cudf-polars benchmarking CLI. We're currently running benchmarks against both release/26.06 and main.

TomAugspurger and others added 2 commits May 19, 2026 05:52
This updates the cudf-polars benchmarks CLI to serialize the engine configuration. This will let us see what options were *actually* used.

Authors:
  - Tom Augspurger (https://github.com/TomAugspurger)

Approvers:
  - Matthew Roeschke (https://github.com/mroeschke)
  - Mads R. B. Kristensen (https://github.com/madsbk)

URL: NVIDIA#22365
(cherry picked from commit 38f2d41)
This was missed while merging NVIDIA#22365

Authors:
  - Lawrence Mitchell (https://github.com/wence-)

Approvers:
  - Tom Augspurger (https://github.com/TomAugspurger)
  - Matthew Murray (https://github.com/Matt711)

URL: NVIDIA#22549
(cherry picked from commit f239649)
@TomAugspurger
TomAugspurger requested a review from a team as a code owner May 19, 2026 12:56
@github-actions github-actions Bot added Python Affects Python cuDF API. cudf-polars Issues specific to cudf-polars labels May 19, 2026
@GPUtester GPUtester moved this to In Progress in cuDF Python May 19, 2026
@coderabbitai

coderabbitai Bot commented May 19, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 8a22ef3f-e05d-4a5a-ac64-e24c76cc4d14

📥 Commits

Reviewing files that changed from the base of the PR and between 3b00e8e and 501bab5.

📒 Files selected for processing (5)
  • python/cudf_polars/cudf_polars/engine/core.py
  • python/cudf_polars/cudf_polars/engine/dask.py
  • python/cudf_polars/cudf_polars/engine/ray.py
  • python/cudf_polars/cudf_polars/engine/spmd.py
  • python/cudf_polars/cudf_polars/streaming/benchmarks/utils.py
✅ Files skipped from review due to trivial changes (1)
  • python/cudf_polars/cudf_polars/engine/core.py

📝 Walkthrough

Summary by CodeRabbit

  • Refactor
    • Streamlined configuration management across Dask, Ray, and SPMD streaming engines to consistently store engine settings on instances, improving internal consistency and configuration tracking.
    • Enhanced benchmark utilities to more accurately capture and serialize streaming engine configuration details in benchmark result outputs.

Walkthrough

Resolved RapidsMPF options are now stored on StreamingEngine instances to enable serialization in benchmark outputs. Engine-aware serialization extracts configuration from live engine objects for distributed/GPU frontends while using None for CPU/in-memory paths.

Changes

RapidsMPF options storage and benchmark serialization

Layer / File(s) Summary
StreamingEngine options type contract
python/cudf_polars/cudf_polars/engine/core.py
Added rapidsmpf.config import and class-scope type annotation rapidsmpf_options: rapidsmpf.config.Options to StreamingEngine.
Engine implementations persist resolved options
python/cudf_polars/cudf_polars/engine/dask.py, python/cudf_polars/cudf_polars/engine/ray.py, python/cudf_polars/cudf_polars/engine/spmd.py
DaskEngine, RayEngine, and SPMDEngine store resolve_rapidsmpf_options() on self.rapidsmpf_options during __init__; SPMDEngine uses the instance attribute for both single-rank communicator and Context initialization.
Benchmark config serialization with engine-aware options
python/cudf_polars/cudf_polars/streaming/benchmarks/utils.py
RunConfig.serialize() signature changes to accept StreamingEngine | None; when engine is present, extracts and sanitizes both config_options and rapidsmpf_options into the output; _finalize_benchmark_run() now takes engine parameter and calls serialize(engine=engine) instead of engine=None.
Benchmark runner wiring to pass engines
python/cudf_polars/cudf_polars/streaming/benchmarks/utils.py
CPU and in-memory runners pass engine=None; SPMD, Ray, and Dask runners pass the live engine object to _finalize_benchmark_run().

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • rapidsai/cudf#22365: Similar rapidsmpf_options refactoring across different module paths with engine-aware benchmark serialization.

Suggested labels

improvement, non-breaking

Suggested reviewers

  • nirandaperera
  • mroeschke
  • madsbk
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 69.23% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding engine configuration serialization to the benchmark CLI.
Description check ✅ Passed The description is related to the changeset, explaining that it backports commits for the benchmarking CLI to serialize engine configuration.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@python/cudf_polars/cudf_polars/experimental/benchmarks/utils_new_frontends.py`:
- Around line 1266-1268: _finalize_benchmark_run is being called with
engine=engine after the engine context has exited, so RunConfig.serialize() may
read a torn/cleared engine; move the _finalize_benchmark_run(...) call (the ones
in run_polars_ray and run_polars_dask) so they execute inside the corresponding
"with ... as engine:" block (before the context manager returns) to ensure the
engine is still alive when RunConfig.serialize()/finalization runs.

In `@python/cudf_polars/cudf_polars/experimental/rapidsmpf/frontend/dask.py`:
- Around line 619-620: _reset() rebuilds worker contexts from newly resolved
options but doesn't update the persisted field self.rapidsmpf_options (and its
serialized bytes), causing stale options to be emitted. In the _reset()
implementation, after calling resolve_rapidsmpf_options(...) and before
rebuilding contexts, assign the result to self.rapidsmpf_options and reserialize
(e.g., update rapidsmpf_options_as_bytes = self.rapidsmpf_options.serialize() or
the instance field that holds the bytes) so both the in-memory options and their
serialized representation remain synchronized with the newly resolved options
used to recreate worker contexts.

In `@python/cudf_polars/cudf_polars/experimental/rapidsmpf/frontend/ray.py`:
- Around line 553-554: In RayEngine._reset() the resolved options are only
converted to bytes (rapidsmpf_options_as_bytes) and self.rapidsmpf_options is
left stale; change _reset() to call
resolve_rapidsmpf_options(rapidsmpf_options), assign the result back to
self.rapidsmpf_options, then call self.rapidsmpf_options.serialize() (updating
rapidsmpf_options_as_bytes) so the engine state and persisted bytes reflect the
fresh config; reference the resolve_rapidsmpf_options, self.rapidsmpf_options,
rapidsmpf_options_as_bytes and serialize() symbols when making the change.

In `@python/cudf_polars/cudf_polars/experimental/rapidsmpf/frontend/spmd.py`:
- Line 353: SPMDEngine stores init-time options in self.rapidsmpf_options but
_reset() resolves options into a local variable and never updates the instance
attribute, causing stale persisted options; modify the _reset() implementation
(and the other occurrences where resolve_rapidsmpf_options(...) is called) to
assign the resolved value back to self.rapidsmpf_options (e.g.,
self.rapidsmpf_options = resolve_rapidsmpf_options(rapidsmpf_options)) and use
that instance attribute everywhere the local resolved variable is currently used
so the engine and serialization always reflect the latest options.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 33f7fe23-2129-4e84-be24-97416d0a624d

📥 Commits

Reviewing files that changed from the base of the PR and between 65f8363 and 3b00e8e.

📒 Files selected for processing (5)
  • python/cudf_polars/cudf_polars/experimental/benchmarks/utils_new_frontends.py
  • python/cudf_polars/cudf_polars/experimental/rapidsmpf/frontend/core.py
  • python/cudf_polars/cudf_polars/experimental/rapidsmpf/frontend/dask.py
  • python/cudf_polars/cudf_polars/experimental/rapidsmpf/frontend/ray.py
  • python/cudf_polars/cudf_polars/experimental/rapidsmpf/frontend/spmd.py

Comment on lines +1266 to +1268
_finalize_benchmark_run(
args, run_config, validation_failures, query_failures, engine=engine
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Serialize before leaving the Ray/Dask engine context.

These calls now pass engine=engine, but they execute after the with ... as engine: block. At that point the engine is shut down, so RunConfig.serialize() may read cleared/invalid engine config and emit incorrect benchmark config.

Suggested fix
-    _finalize_benchmark_run(
-        args, run_config, validation_failures, query_failures, engine=engine
-    )
+        _finalize_benchmark_run(
+            args, run_config, validation_failures, query_failures, engine=engine
+        )

Apply the same move for both run_polars_ray and run_polars_dask so finalization happens while the engine is still alive.

Also applies to: 1328-1330

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@python/cudf_polars/cudf_polars/experimental/benchmarks/utils_new_frontends.py`
around lines 1266 - 1268, _finalize_benchmark_run is being called with
engine=engine after the engine context has exited, so RunConfig.serialize() may
read a torn/cleared engine; move the _finalize_benchmark_run(...) call (the ones
in run_polars_ray and run_polars_dask) so they execute inside the corresponding
"with ... as engine:" block (before the context manager returns) to ensure the
engine is still alive when RunConfig.serialize()/finalization runs.

Comment on lines +619 to +620
self.rapidsmpf_options = resolve_rapidsmpf_options(rapidsmpf_options)
rapidsmpf_options_as_bytes = self.rapidsmpf_options.serialize()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep self.rapidsmpf_options synchronized on reset.

This new persisted field is initialized here, but _reset() currently rebuilds worker contexts from newly resolved options without updating self.rapidsmpf_options. After a reset, benchmark serialization will emit stale RapidsMPF options.

Suggested fix
 def _reset(
@@
-        rapidsmpf_options_as_bytes = resolve_rapidsmpf_options(
-            rapidsmpf_options
-        ).serialize()
+        self.rapidsmpf_options = resolve_rapidsmpf_options(rapidsmpf_options)
+        rapidsmpf_options_as_bytes = self.rapidsmpf_options.serialize()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
self.rapidsmpf_options = resolve_rapidsmpf_options(rapidsmpf_options)
rapidsmpf_options_as_bytes = self.rapidsmpf_options.serialize()
def _reset(
self,
rapidsmpf_options: dict[str, Any] | None = None,
) -> None:
"""Reset the Dask cluster, optionally updating rapidsmpf options."""
self.rapidsmpf_options = resolve_rapidsmpf_options(rapidsmpf_options)
rapidsmpf_options_as_bytes = self.rapidsmpf_options.serialize()
# ... rest of the method
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/cudf_polars/cudf_polars/experimental/rapidsmpf/frontend/dask.py`
around lines 619 - 620, _reset() rebuilds worker contexts from newly resolved
options but doesn't update the persisted field self.rapidsmpf_options (and its
serialized bytes), causing stale options to be emitted. In the _reset()
implementation, after calling resolve_rapidsmpf_options(...) and before
rebuilding contexts, assign the result to self.rapidsmpf_options and reserialize
(e.g., update rapidsmpf_options_as_bytes = self.rapidsmpf_options.serialize() or
the instance field that holds the bytes) so both the in-memory options and their
serialized representation remain synchronized with the newly resolved options
used to recreate worker contexts.

Comment on lines +553 to +554
self.rapidsmpf_options = resolve_rapidsmpf_options(rapidsmpf_options)
rapidsmpf_options_as_bytes = self.rapidsmpf_options.serialize()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Update persisted RapidsMPF options in RayEngine._reset().

self.rapidsmpf_options is now part of engine state, but _reset() still computes fresh options only as local bytes. That leaves self.rapidsmpf_options stale and can serialize incorrect post-reset config.

Suggested fix
 def _reset(
@@
-        rapidsmpf_options_as_bytes = resolve_rapidsmpf_options(
-            rapidsmpf_options
-        ).serialize()
+        self.rapidsmpf_options = resolve_rapidsmpf_options(rapidsmpf_options)
+        rapidsmpf_options_as_bytes = self.rapidsmpf_options.serialize()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/cudf_polars/cudf_polars/experimental/rapidsmpf/frontend/ray.py` around
lines 553 - 554, In RayEngine._reset() the resolved options are only converted
to bytes (rapidsmpf_options_as_bytes) and self.rapidsmpf_options is left stale;
change _reset() to call resolve_rapidsmpf_options(rapidsmpf_options), assign the
result back to self.rapidsmpf_options, then call
self.rapidsmpf_options.serialize() (updating rapidsmpf_options_as_bytes) so the
engine state and persisted bytes reflect the fresh config; reference the
resolve_rapidsmpf_options, self.rapidsmpf_options, rapidsmpf_options_as_bytes
and serialize() symbols when making the change.

@@ -350,7 +350,7 @@ def __init__(
)
bind_to_gpu(hw_binding)

rapidsmpf_options = resolve_rapidsmpf_options(rapidsmpf_options)
self.rapidsmpf_options = resolve_rapidsmpf_options(rapidsmpf_options)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Persisted options become stale after _reset().

SPMDEngine now uses self.rapidsmpf_options for init-time construction, but _reset() rebuilds the context from a local resolved variable and does not refresh the instance attribute. That can cause benchmark serialization to report old options.

Suggested fix
-        rapidsmpf_options = resolve_rapidsmpf_options(rapidsmpf_options)
+        self.rapidsmpf_options = resolve_rapidsmpf_options(rapidsmpf_options)
@@
-        self._ctx = Context.from_options(self._comm.logger, self._mr, rapidsmpf_options)
+        self._ctx = Context.from_options(
+            self._comm.logger, self._mr, self.rapidsmpf_options
+        )

Also applies to: 364-364, 369-369, 383-383

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/cudf_polars/cudf_polars/experimental/rapidsmpf/frontend/spmd.py` at
line 353, SPMDEngine stores init-time options in self.rapidsmpf_options but
_reset() resolves options into a local variable and never updates the instance
attribute, causing stale persisted options; modify the _reset() implementation
(and the other occurrences where resolve_rapidsmpf_options(...) is called) to
assign the resolved value back to self.rapidsmpf_options (e.g.,
self.rapidsmpf_options = resolve_rapidsmpf_options(rapidsmpf_options)) and use
that instance attribute everywhere the local resolved variable is currently used
so the engine and serialization always reflect the latest options.

@TomAugspurger TomAugspurger added bug Something isn't working non-breaking Non-breaking change labels May 19, 2026
@TomAugspurger

Copy link
Copy Markdown
Contributor Author

/merge

@rapids-bot
rapids-bot Bot merged commit 12707ae into NVIDIA:release/26.06 May 19, 2026
88 of 89 checks passed
@github-project-automation github-project-automation Bot moved this from In Progress to Done in cuDF Python May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working cudf-polars Issues specific to cudf-polars non-breaking Non-breaking change Python Affects Python cuDF API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants