Skip to content

Fix use-after-destroy and stream ordering in Parquet IO utils - #22529

Merged
rapids-bot[bot] merged 7 commits into
NVIDIA:release/26.06from
mhaseeb123:fix/parquet-io-utils-stream
May 19, 2026
Merged

Fix use-after-destroy and stream ordering in Parquet IO utils#22529
rapids-bot[bot] merged 7 commits into
NVIDIA:release/26.06from
mhaseeb123:fix/parquet-io-utils-stream

Conversation

@mhaseeb123

@mhaseeb123 mhaseeb123 commented May 15, 2026

Copy link
Copy Markdown
Contributor

Description

This PR fixes the use-after-destroy and stream ordering (with PTDS input) issue (with host buffer source) in the fetch_byte_ranges_to_device_async IO utility used by parquet and hybrid scan.

See follow up PR #22550 that reduces the locked region size by moving all host_read_async outside it.

Checklist

  • I am familiar with the Contributing Guidelines.
  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

@mhaseeb123
mhaseeb123 requested a review from a team as a code owner May 15, 2026 20:50
@mhaseeb123
mhaseeb123 requested review from shrshi and ttnghia May 15, 2026 20:50
@github-actions github-actions Bot added the libcudf Affects libcudf (C++/CUDA) code. label May 15, 2026
@mhaseeb123 mhaseeb123 changed the title Fix the parquet io utils Fix use-after-destroy and stream ordering in Parquet IO util May 15, 2026
@mhaseeb123 mhaseeb123 changed the title Fix use-after-destroy and stream ordering in Parquet IO util Fix use-after-destroy and stream ordering in Parquet IO utils May 15, 2026
@mhaseeb123
mhaseeb123 requested a review from vuule May 15, 2026 20:52
@mhaseeb123 mhaseeb123 added bug Something isn't working 3 - Ready for Review Ready for review by team non-breaking Non-breaking change labels May 15, 2026
@mhaseeb123 mhaseeb123 moved this to Burndown in libcudf May 15, 2026
@coderabbitai

coderabbitai Bot commented May 15, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Batches host reads for parquet byte-range transfers: adds CUDA memcpy and tuple includes, reserves merged-range vectors, collects host-read futures returning owning buffers, resolves them to extract source pointers, and enqueues a single cudf::detail::memcpy_batch_async to copy to device destinations. Deferred return waits only on device-read futures.

Changes

Host-to-Device Batched Transfer

Layer / File(s) Summary
Dependencies and vector pre-reservation
cpp/src/io/parquet/io_utils/parquet_io_utils.cpp
CUDA memcpy include and <tuple> are added; capacity is reserved for merged I/O metadata vectors (io_offsets, io_sizes, destinations).
Host-read batch transfer data structures
cpp/src/io/parquet/io_utils/parquet_io_utils.cpp
Replaces prior host-read worker task with std::future<host_read_buffer> futures (owning std::unique_ptr buffers) and adds vectors to accumulate batched-copy destinations, sizes, and resolved host-buffer pointers.
Batched host-to-device memcpy implementation
cpp/src/io/parquet/io_utils/parquet_io_utils.cpp
Queues datasource.host_read_async futures, resolves them to obtain host data pointers, schedules a single cudf::detail::memcpy_batch_async for all host->device copies while keeping host buffers alive until enqueue, and returns a future that waits only on device-read futures.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes


Suggested labels

cuIO, 4 - Needs Review


Suggested reviewers

  • ttnghia
  • vuule
  • pmattione-nvidia
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 fix: addressing use-after-destroy and stream ordering issues in Parquet IO utilities, which aligns with the code changes.
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.
Description check ✅ Passed The PR description clearly relates to the changeset, explaining the fix for use-after-destroy and stream ordering issues in fetch_byte_ranges_to_device_async, which aligns with the code modifications.

✏️ 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cpp/src/io/parquet/io_utils/parquet_io_utils.cpp (1)

136-184: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Gate the blocking synchronizations to the paths that need them.

Line 137 now blocks even when every range uses host_read_async, and Lines 174-175 block even when every range uses device_read_async, so this *_async helper can end up fully synchronous before it returns. Those waits also happen while the static mutex from Line 142 is held, which serializes concurrent callers for the entire host-read/H2D phase.

Please restrict the pre-sync to the device-read path, keep the post-copy sync inside the host-read branch, and release the mutex once the async reads have been enqueued. As per coding guidelines, "Avoid unnecessary host-device synchronization that blocks the GPU pipeline".

🤖 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 `@cpp/src/io/parquet/io_utils/parquet_io_utils.cpp` around lines 136 - 184, The
current implementation calls stream.synchronize() unconditionally and holds
mutex across async enqueues and waits, causing unnecessary blocking; change the
logic in the function that builds device_read_tasks/host_read_tasks so that (1)
the initial stream.synchronize() is only invoked when at least one device read
is scheduled (i.e. when datasource.supports_device_read() &&
is_device_read_preferred(...) leads to any device_read_tasks), (2) release the
std::lock_guard<std::mutex> mutex immediately after enqueuing both
device_read_tasks and host_read_tasks so the critical section does not cover
subsequent waits or host-device copies, and (3) move the second
stream.synchronize() so it only runs inside the branch that performed host reads
(immediately after calling cudf::detail::memcpy_batch_async and before
host_read_buffers/other temporaries go out of scope); keep the deferred
sync_function that waits on device_read_tasks unchanged but ensure it is created
after the mutex is released.
🤖 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.

Outside diff comments:
In `@cpp/src/io/parquet/io_utils/parquet_io_utils.cpp`:
- Around line 136-184: The current implementation calls stream.synchronize()
unconditionally and holds mutex across async enqueues and waits, causing
unnecessary blocking; change the logic in the function that builds
device_read_tasks/host_read_tasks so that (1) the initial stream.synchronize()
is only invoked when at least one device read is scheduled (i.e. when
datasource.supports_device_read() && is_device_read_preferred(...) leads to any
device_read_tasks), (2) release the std::lock_guard<std::mutex> mutex
immediately after enqueuing both device_read_tasks and host_read_tasks so the
critical section does not cover subsequent waits or host-device copies, and (3)
move the second stream.synchronize() so it only runs inside the branch that
performed host reads (immediately after calling cudf::detail::memcpy_batch_async
and before host_read_buffers/other temporaries go out of scope); keep the
deferred sync_function that waits on device_read_tasks unchanged but ensure it
is created after the mutex is released.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 3ecc1eea-9a86-4ce3-aed7-7b7a5e03514c

📥 Commits

Reviewing files that changed from the base of the PR and between 18af3a4 and 3d54fcf.

📒 Files selected for processing (1)
  • cpp/src/io/parquet/io_utils/parquet_io_utils.cpp

@mhaseeb123
mhaseeb123 force-pushed the fix/parquet-io-utils-stream branch from 3d54fcf to be7694a Compare May 15, 2026 21:29
@mhaseeb123
mhaseeb123 requested review from a team as code owners May 15, 2026 21:29
@copy-pr-bot

copy-pr-bot Bot commented May 15, 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.

@mhaseeb123
mhaseeb123 changed the base branch from main to release/26.06 May 15, 2026 21:30
@github-actions github-actions Bot added Python Affects Python cuDF API. Java Affects Java cuDF API. cudf.pandas Issues specific to cudf.pandas cudf-polars Issues specific to cudf-polars labels May 15, 2026
@mhaseeb123

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented May 15, 2026

Copy link
Copy Markdown
✅ Actions performed

Full review triggered.

@mhaseeb123 mhaseeb123 removed Python Affects Python cuDF API. Java Affects Java cuDF API. cudf.pandas Issues specific to cudf.pandas cudf-polars Issues specific to cudf-polars pylibcudf Issues specific to the pylibcudf package labels May 15, 2026
@mhaseeb123 mhaseeb123 removed this from cuDF Python May 15, 2026
@mhaseeb123 mhaseeb123 added 4 - Needs Review Waiting for reviewer to review or respond and removed 3 - Ready for Review Ready for review by team labels May 15, 2026

@aminaramoon aminaramoon 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.

LGTM!

@vuule vuule left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Having a hard time convincing myself that there's no performance impact here in any case, but the changes look good.
Do you have any performance numbers?

@mhaseeb123

Copy link
Copy Markdown
Contributor Author

Do you have any performance numbers?

Let me gather and paste some here

@mhaseeb123

mhaseeb123 commented May 19, 2026

Copy link
Copy Markdown
Contributor Author

Performance Impact

This PR shows a rough ~12% end-to-end improvement when reading 16 x (1GB disk size) Parquet files (clickbench) using the hybrid_scan_multifile_single_step example with HOST_BUFFER datasource.

Note: Perf for FILEPATH datasource remains unchanged.

image

CC: @vuule

@mhaseeb123

Copy link
Copy Markdown
Contributor Author

/merge

@rapids-bot
rapids-bot Bot merged commit 65f8363 into NVIDIA:release/26.06 May 19, 2026
225 of 227 checks passed
@mhaseeb123
mhaseeb123 deleted the fix/parquet-io-utils-stream branch May 19, 2026 00:21
@vuule vuule moved this from Burndown to Landed in libcudf May 19, 2026
madsbk pushed a commit to madsbk/cudf that referenced this pull request May 19, 2026
…#22529)

This PR fixes the use-after-destroy and stream ordering (with PTDS input) issue (with host buffer source) in the `fetch_byte_ranges_to_device_async` IO utility used by parquet and hybrid scan.

See follow up PR NVIDIA#22550 that reduces the locked region size by moving all `host_read_async` outside it.

Authors:
  - Muhammad Haseeb (https://github.com/mhaseeb123)

Approvers:
  - Bradley Dice (https://github.com/bdice)
  - Amin Aramoon (https://github.com/aminaramoon)
  - Vukasin Milovanovic (https://github.com/vuule)

URL: NVIDIA#22529
@mhaseeb123 mhaseeb123 added 5 - Ready to Merge Testing and reviews complete, ready to merge and removed 4 - Needs Review Waiting for reviewer to review or respond labels May 19, 2026
rapids-bot Bot pushed a commit that referenced this pull request May 22, 2026
Follow up #22529

This PR optimizes the `fetch_byte_ranges_to_device_async` parquet IO utility by moving all host buffer reads outside the locked region. This PR adds another ~5% end to end speed improvement over the results posted at #22529 (comment)

Authors:
  - Muhammad Haseeb (https://github.com/mhaseeb123)

Approvers:
  - Vukasin Milovanovic (https://github.com/vuule)
  - Vyas Ramasubramani (https://github.com/vyasr)

URL: #22550
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

5 - Ready to Merge Testing and reviews complete, ready to merge bug Something isn't working libcudf Affects libcudf (C++/CUDA) code. non-breaking Non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants