Repository navigation
Conversation
DeviceBuffer::cast_elem, DeviceBuffer::cast_chunks, and Tensor::reinterpret reinterpreted device bytes as any element type of the right size and alignment, which let a u8 buffer become a DeviceBuffer<bool> or Tensor<bool> holding values other than 0 and 1 (NVIDIA#1506). The casts now require bytemuck::AnyBitPattern of their target, so bool is rejected at compile time, and bool implements DeviceCopy: a typed buffer holds valid values by construction, so bool buffers can be allocated, filled, launched, and read back like any other element type. cuda-core re-exports bytemuck, implements Pod for the DType newtypes, and enables half's bytemuck feature for f16 and bf16. The atomic wrappers in cuda-device are not Copy, so they cannot be AnyBitPattern. DeviceBuffer gains wrap_elem and peel_elem, bounded on bytemuck::TransparentWrapper, to view a scalar buffer as its atomic wrapper and back. cuda-device implements TransparentWrapper for its atomic types and Pod for its vector types, and the examples that cast into atomics use the new methods. Every example lock gains the bytemuck dependency of cuda-device. Signed-off-by: Melih Elibol <1884921+elibol@users.noreply.github.com>
|
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. |
|
So, as a first step I think the But we need to address two safety issues that popped up from trying to break the above setup via adversarial examples. 1. The first one is the atomic The intended operation is converting an owned integer buffer into an atomic buffer. But implementing use bytemuck::TransparentWrapper;
// Device code:
fn overwrite(value: &u32) {
let atomic = DeviceAtomicU32::wrap_ref(value);
atomic.store(7, AtomicOrdering::Relaxed);
}The conversion aliases the same memory: The original Proposed fix: remove the atomic pub unsafe trait DeviceRepr<Inner>: Sized {}Its documented contract would require matching layout, valid initialized representations in both directions, and no additional ownership or destruction obligations. It would provide no reference-conversion methods. The buffer’s let atomics = integers.wrap_elem::<DeviceAtomicU32>();
// Run the kernel and complete its accesses.
let integers = atomics.peel_elem::<u32>();
|
|
2. Suppose an allocation still contains old byte // writer and reader are independent GPU streams.
let flags = DeviceBuffer::<bool>::zeroed(&writer, 1)?;
let values = flags.to_host_vec(&reader)?;Both calls are safe Rust. However,
Proposed fix: the simplest repair is to finish initialization before safe // After queuing the zero-fill:
stream.synchronize()?;
Ok(buf)To preserve asynchronous initialization, retain its completion dependency and make every safe consumer honor it, including readback and kernel launches. Asking callers to synchronize in documentation does not repair the safe API. Our GPU probe observed byte I think the initialization-ordering code predates this PR and it only surfaced after admitting |
Signed-off-by: Melih Elibol <1884921+elibol@users.noreply.github.com>
Signed-off-by: Melih Elibol <1884921+elibol@users.noreply.github.com>
|
@nihalpasham Agreed on both points. Fixed in f42ed4f (and brought the branch up to date with main).
Added compile-fail coverage for integer/float atomic The previously documented Tile UI snapshot-path mismatch remains the only failing case in that suite; |
Signed-off-by: Melih Elibol <1884921+elibol@users.noreply.github.com>
Signed-off-by: Melih Elibol <1884921+elibol@users.noreply.github.com>
Signed-off-by: Melih Elibol <1884921+elibol@users.noreply.github.com>
|
Added the two remaining host-side audit fixes in 2788c6c:
Both regressions were checked before and after the fixes. Full cuda-core tests passed (105); selected Tile library/GPU tests passed (168), as did all 9 submission-lifetime tests. Clippy, formatting, and SPDX checks passed. Tile rustdoc builds with 12 existing link warnings; the known unrelated Tile UI snapshot mismatch remains. The remaining duplicate-runtime findings are covered by #1460/#1461 and are excluded from this PR's follow-up scope. |
Signed-off-by: Melih Elibol <1884921+elibol@users.noreply.github.com>
…ybitpattern-casts Signed-off-by: Melih Elibol <1884921+elibol@users.noreply.github.com> # Conflicts: # cutile-rs/CHANGELOG.md
Signed-off-by: Melih Elibol <1884921+elibol@users.noreply.github.com>
Signed-off-by: Melih Elibol <1884921+elibol@users.noreply.github.com>
|
@nihalpasham Both of your requests are addressed:
The compile-fail and gated-stream regressions pass. The previously reported Tile UI snapshot mismatch is also fixed. The follow-up audit added the host-side argument-contract and pinned-buffer alignment fixes, and the latest changes fix tensor alias accounting during completion-lease creation and retirement. All 63 active CI checks now pass at |
Signed-off-by: Melih Elibol <1884921+elibol@users.noreply.github.com>
Closes #1506. First change under #1460; implements the
booldecision recorded there and in #1461 and #1503.Safe element casts previously checked size and alignment but could turn a byte containing
2into a Rustbool. This PR rejects those casts, supports initializedboolbuffers, and closes the host-side initialization, atomic-reference, kernel-argument, and pinned-alignment holes found during review and follow-up auditing.Element validity
DeviceBuffer::cast_elem,cast_chunks,can_cast_chunks, andTensor::reinterpretrequirebytemuck::AnyBitPatternon the target. Casting intoboolis therefore a compile error.boolimplementsDeviceCopy: valid values can be copied between host and device, and its all-zero representation is valid.DeviceCopydoes not promise that every bit pattern is valid. It remains independent ofDType.The numeric
DTypenewtypes implementPod, andhalfenables its bytemuck feature, preserving numeric reinterpretation targets. cuda-core re-exportsbytemuckfor downstream marker implementations. Vector types in cuda-device also implementPod, preservingcast_chunksusage.Owned atomic-buffer conversions
wrap_elemandpeel_elemuse the unsafe markerDeviceRepr<Inner>. Its contract requires identical layout, valid initialized representations in both directions, no element destruction, and no additional ownership obligations. It has no methods and grants no reference conversions.The integer and floating-point atomic macros implement
DeviceRepr, notTransparentWrapper. Consequently, safeDeviceAtomicU32::wrap_ref(&u32)and the reversepeel_refconversion are unavailable. Owned scalar buffers can still be wrapped for atomic kernel access and peeled for readback, retaining their allocation, context, and deallocation stream. Kernel accesses must obey the existing borrowing and synchronization contracts.The marker lives in the dependency-free,
no_stdcuda-repr crate and is re-exported by cuda-core and cuda-device. This lets both sides share one trait without making kernel-only crates depend on the host runtime. The dependent lockfiles add this local package without changing registry or git dependencies. CI path filters include the new crate.The atomic examples use
wrap_elem/peel_elem.KernelSliceArgis not restricted toDeviceCopy, since atomic wrappers are legitimate kernel element types that cannot implementCopy.Completed zero-initialization
DeviceBuffer::zeroedqueues the zero-fill and synchronizes its stream before returning. A safe readback or launch on another stream can therefore rely on initialization having completed, including forbool. Empty allocations retain their fast path.This makes nonempty
zeroeda blocking constructor. Asynchronous initialization with automatically retained completion dependencies belongs to the subsequent runtime work; callers are not asked to repair a safe API through manual synchronization.Host-side argument contracts and pinned alignment
KernelInputStoredandKernelOutputStorednow requireunsafe impl. Their contracts cover truthful dtype/layout/specialization metadata, argument ABI, addressable extent, and storage/access retention through completion and graph replay. Previously an entirely safe custom binding could presentTensor<bool>storage asu8output, so a normal byte kernel could write invalid bool values. The input counterpart could similarly mislabel arbitrary byte storage as booleans. The safeKernelInput/KernelOutputconversion traits remain available and must return stored bindings satisfying those contracts. Existing owned, borrowed, view, and mapped bindings retain their behavior.PinnedHostBufferreserves alignment slack, exposes an aligned interior pointer, and retains the original CUDA pointer for deallocation. It also rejects allocation sizes that exceed Rust slice/pointer-arithmetic limits. Empty and zero-sized buffers keep their aligned dangling pointers and allocation-free behavior.Tensor alias accounting
Tensor aliases and lazy copy operations share a separate ownership token. Completion leases retain the storage itself without contributing to that token. Uniqueness therefore stays correct while a lease is being registered or destroyed: a real alias cannot become a mutable partition, and retiring a lease cannot spuriously reject a unique tensor. Access exclusion and completion retention remain enforced.
The acquisition and destruction regressions fail on the previous implementation and pass with this change. A separate test preserves ownership held by an unsubmitted copy operation.
Compatibility and validation
The new
AnyBitPatternbounds are a breaking change for reinterpretation targets that do not implement that trait. Numeric targets remain supported; atomics use the owned-buffer conversions. Tuple types remain usable as buffer elements but are not reinterpretation targets. Custom stored Tile argument implementations must now explicitly uphold the documented unsafe contract.Validated after updating this branch against main:
legacy_atomic_rmw_cas,legacy_atomic_fadd, andhashmapon an RTX 5090; all six Tile tensor reinterpretation tests.The Tile UI snapshot now uses the normalized external-crate path. Both UI harness tests (all 12 compile-fail cases) pass, and the CPU CI script now runs them. The version-only update to the planned v0.5.0 API boundary has landed on main in #1614; host and Tile semver checks pass. SIMT workflow branch filters now include stacked PRs targeting
pull-request/<n>prerequisite mirrors.Follow-up validation for the host-side argument and pinned-buffer fixes:
unsafe implis required; snapshots were reviewed and rerun without overwrite.Current follow-up validation: the complete CPU runner passes (1,408 tests, 98 intentionally ignored), including the Tile UI suites. All 25 targeted GPU buffer and pinned-host-buffer tests pass, including the cross-stream initialization regression. The branch includes the #1602 debug-source fixes and the same version metadata as #1614.
Current-main integration: Merged current main after the CuTe preview import and reconciled the dependency lockfiles and license inventory, retaining cuda-repr. CuTe library tests and doctests pass (229 tests), as do affected-package Clippy, lockfile/license guards, and dependency checks. Fresh CI is running at
93dd50704b; the preceding head had all 63 active checks passing.