Skip to content

cuda.core: Add copy_batch to cuda.core.utils - #2593

Open
juenglin wants to merge 8 commits into
NVIDIA:mainfrom
juenglin:batched-memcpy
Open

cuda.core: Add copy_batch to cuda.core.utils#2593
juenglin wants to merge 8 commits into
NVIDIA:mainfrom
juenglin:batched-memcpy

Conversation

@juenglin

@juenglin juenglin commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds copy_batch to cuda.core.utils, wrapping cuMemcpyBatchAsync so a set of
transfers is issued in a single driver call. This is the P0 item of #1333; the P1
items (prefetch / discard / discard-prefetch) landed in #1775. Closes #1333.
Batched-only, mirroring the *_batch functions from #1775: a lone Buffer is
rejected in favour of Buffer.copy_to / Buffer.copy_from.

Public API

from cuda.core import Device, Host
from cuda.core.utils import CopyOptions, MemcpySrcAccessOrder, copy_batch
# One option applies to every copy...
copy_batch(stream, srcs, dsts, options=CopyOptions(src_access_order=MemcpySrcAccessOrder.STREAM))
# ...or one per copy, paired by index.
copy_batch(stream, srcs, dsts, options=[opt_a, opt_b, opt_c])
# Location hints, for managed-memory operands.
copy_batch(stream, srcs, dsts, options=CopyOptions(
    src_access_order=MemcpySrcAccessOrder.STREAM,
    src_location_hint=Device(0),
    dst_location_hint=Host(),
))

New exports from cuda.core.utils: copy_batch, CopyOptions,
MemcpySrcAccessOrder, MemcpyOverlapMode. Nothing is added to top-level
cuda.core.
CopyOptions is a frozen dataclass mapping onto CUmemcpyAttributes:
src_access_order, src_location_hint, dst_location_hint, overlap_mode.
options=None selects stream-ordered defaults.

Behaviour

  • Source and destination sizes must match, that is src.size must equal dst.size.
    Partial-buffer copies are out of scope.
  • A scalar CopyOptions broadcasts to every copy; a sequence pairs by index and
    must match len(srcs), otherwise ValueError. Non-default CopyOptions require
  • Options are run-length encoded into the driver's attrs / attrsIdxs pair, so
    a broadcast reaches the driver as numAttrs == 1 instead of being repeated per
    copy.
  • On a CUDA 12 build of cuda.bindings or when using an older driver, copy_batch is emulated by a sequence of cuMemcpyAsync calls, consistent with prefetch_batch.
  • Not capturable into a graph. Use GraphNode.memcpy for graph copies.
  • overlap_mode="prefer_overlap_with_compute" is a Tegra-only hint. On a
    non-integrated GPU the driver silently ignores it, so a UserWarning is emitted
    and the copy proceeds with default behaviour.

Refactor to existing files

_coerce_batch_buffers was duplicated between the new _copy_ops.pyx and _managed_memory_ops.pyx, so it now lives once as Buffer_coerce_batch in _buffer.pyx / _buffer.pxd, parameterized by the per-buffer API to suggest. That accounts for the changes to _buffer.* and _managed_memory_ops.pyx (no behaviour changes for the #1775 functions).

Relation to the #1775 batched-API contract

Follows the contract on pairing, scalar broadcast, ValueError on length mismatch, and options as a frozen dataclass. Three deliberate deviations, which match what #1775 shipped
rather than what that comment described:

  • No unified copy() accepting one-or-many. Add managed-memory advise, prefetch, and discard-prefetch free functions #1775 shipped batch-only free
    functions with instance methods for N=1; this mirrors that split.
  • Parallel srcs / dsts sequences rather than a sequence of pairs, matching
    prefetch_batch(stream, buffers, locations).
  • A single stream argument: cuMemcpyBatchAsync takes one CUstream, so there
    is no per-copy stream array to mirror.

Tests

tests/memory/test_copy_batch.py covers data movement — H2D, D2H, D2D, mixed
sizes, agreement with sequential Buffer.copy_to, stream ordering, and the
graph-capture rejection. tests/memory/test_copy_batch_options.py covers the
options surface, the attribute run-length encoding, and every validation path.
Shared fixtures live in tests/memory/conftest.py. The new
examples/batched_memcpy.py is exercised by the existing example-test glob.

@copy-pr-bot

copy-pr-bot Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

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.

@github-actions github-actions Bot added the cuda.core Everything related to the cuda.core module label Aug 10, 2026
@juenglin

Copy link
Copy Markdown
Contributor Author

/ok to test fd58e8f

@juenglin juenglin added the P0 High priority - Must do! label Aug 10, 2026
@juenglin juenglin self-assigned this Aug 10, 2026
@juenglin juenglin added this to the cuda.core 1.2.0 milestone Aug 10, 2026
@juenglin

Copy link
Copy Markdown
Contributor Author

/ok to test 9e14ce1

@juenglin
juenglin requested a review from Andy-Jost August 11, 2026 00:24
@juenglin

Copy link
Copy Markdown
Contributor Author

/ok to test fbf7572

@juenglin

Copy link
Copy Markdown
Contributor Author

/ok to test da4a376

@NVIDIA NVIDIA deleted a comment from copy-pr-bot Bot Aug 11, 2026
@NVIDIA NVIDIA deleted a comment from copy-pr-bot Bot Aug 11, 2026
@github-actions

Copy link
Copy Markdown

@juenglin
juenglin marked this pull request as ready for review August 11, 2026 21:30
@juenglin

Copy link
Copy Markdown
Contributor Author

/ok to test b811960

@Andy-Jost Andy-Jost added the feature New feature or request label Aug 11, 2026
@juenglin

Copy link
Copy Markdown
Contributor Author

/ok to test 44715f1

@Andy-Jost

Copy link
Copy Markdown
Contributor
  1. Reject LEGACY_DEFAULT_STREAM in copy_batch before dispatch, so both paths behave alike. The native call fails with an unhelpful driver error, and the CUDA 12 fallback accepts the stream and succeeds.

  2. State the ordering contract in the docstring, and say that the fallback's ordering is an artifact. The driver may run batch items concurrently and in any order, so a batch must not contain copies that read and write the same bytes. Detecting this at runtime is impractical; documentation plus a release-note warning is enough.

  3. Correct graph handling in three places. Allow GraphBuilder, because CUDA 13.1 and later support capture of the batch call. Reject DURING_API_CALL during capture, because the driver does not allow it. The current GraphBuilder rejection is also incomplete, because a caller can pass the builder's active stream and reach the same path.

  4. Remove or version-gate the discrete-GPU overlap warning. CUDA 13.1 added non-Tegra support for PREFER_OVERLAP_WITH_COMPUTE. The check should also test the stream device instead of the current device.

  5. State the source-access contract for each value, not only its performance effect. STREAM keeps source reads in stream order. DURING_API_CALL lets the driver read the source out of stream order, but all reads finish before the call returns; no earlier stream work may touch the source. ANY lets the driver read the source after the call returns, so the caller must keep the source unchanged until the copy completes in stream order.

  6. Document the limits of location hints. State which memory types honor them, and state that they neither prefetch memory nor set persistent advice.

  7. Make the NUMA tests capability-aware. Do not assume that NUMA node 0 is valid, and cover Host.numa_current().

  8. Complete the eager enum validation in CopyOptions.__post_init__. Reject values that are neither the applicable enum nor a string, as newer option classes do.

  9. Make the public annotations resolvable at runtime. Import Device and Host outside TYPE_CHECKING if no import cycle results, then test typing.get_type_hints(CopyOptions).

  10. Correct the specific claims in cuda_core/docs/source/api.rst and cuda_core/docs/source/release/1.2.0-notes.rst. Remove the statement that graph capture is unavailable, and replace "semantically equivalent" for the CUDA 12 fallback with the ordering and stream limits from items 1 and 2.

Items 6, 8, and 9 are minor and can follow in a later change.

@Andy-Jost Andy-Jost 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.

Looks good in general. Requested changes are detailed in a separate comment.

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

Labels

cuda.core Everything related to the cuda.core module feature New feature or request P0 High priority - Must do!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support batched memory movement

2 participants