Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cuda-oxide/crates/cuda-host/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ mod kernels {
#[kernel]
pub fn vecadd(a: &[f32], b: &[f32], mut c: DisjointSlice<f32>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(c_elem) = c.get_mut(idx) {
*c_elem = a[idx.get()] + b[idx.get()];
*c_elem = a[i] + b[i];
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,9 @@ use core::ops::Mul;
#[kernel]
pub fn scale<T: Copy + Mul<Output = T>>(factor: T, input: &[T], mut out: DisjointSlice<T>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(out_elem) = out.get_mut(idx) {
*out_elem = input[idx.get()] * factor;
*out_elem = input[i] * factor;
}
}
```
Expand Down
14 changes: 9 additions & 5 deletions cuda-oxide/crates/rustc-codegen-cuda/examples/debug/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ pub fn clock_test(mut output: DisjointSlice<u64>) {
#[kernel]
pub fn trap_test(input: &[i32], mut output: DisjointSlice<i32>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(output_elem) = output.get_mut(idx) {
let val = input[idx.get()];
let val = input[i];

if val < 0 {
debug::trap(); // Kernel aborts here
Expand All @@ -60,8 +61,9 @@ pub fn trap_test(input: &[i32], mut output: DisjointSlice<i32>) {
#[kernel]
pub fn assert_test(input: &[i32], mut output: DisjointSlice<i32>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(output_elem) = output.get_mut(idx) {
let val = input[idx.get()];
let val = input[i];

// With message
gpu_assert!(val >= 0, "Expected non-negative value");
Expand All @@ -86,11 +88,12 @@ The two forms intentionally use different failure mechanisms:
#[kernel]
pub fn breakpoint_test(mut output: DisjointSlice<i32>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(output_elem) = output.get_mut(idx) {
if idx.get() == 0 {
if i == 0 {
debug::breakpoint(); // cuda-gdb stops here
}
*output_elem = idx.get() as i32;
*output_elem = i as i32;
}
}
```
Expand All @@ -101,10 +104,11 @@ pub fn breakpoint_test(mut output: DisjointSlice<i32>) {
#[kernel]
pub fn profiler_test(input: &[f32], mut output: DisjointSlice<f32>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(output_elem) = output.get_mut(idx) {
debug::prof_trigger::<0>(); // Region start marker

let val = input[idx.get()];
let val = input[i];
let result = val * val;

debug::prof_trigger::<1>(); // Region end marker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@
//! fn scale_kernel(factor: u32, input: &[u32], mut out: DisjointSlice<u32>) {
//! // 'factor' is the closure capture, passed as scalar argument
//! let idx = thread::index_1d();
//! let i = idx.get();
//! if let Some(slot) = out.get_mut(idx) {
//! *slot = input[idx.get()] * factor;
//! *slot = input[i] * factor;
//! }
//! }
//! ```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ This is a **negative test** - it verifies that:
#[kernel]
pub fn valid_f64_to_f32_kernel(a: &[f64], b: &[f64], mut c: DisjointSlice<f32>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(c_elem) = c.get_mut(idx) {
// Valid: explicit f64 to f32 cast
*c_elem = (a[idx.get()] + b[idx.get()]) as f32;
*c_elem = (a[i] + b[i]) as f32;
}
}
```
Expand All @@ -38,13 +39,14 @@ pub fn valid_f64_to_f32_kernel(a: &[f64], b: &[f64], mut c: DisjointSlice<f32>)
#[kernel]
pub fn unsupported_format_kernel(a: &[f32], mut c: DisjointSlice<f32>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(c_elem) = c.get_mut(idx) {
// INVALID: format_args! uses core::fmt which requires:
// - Dynamic dispatch (dyn Trait)
// - Heap allocation
// - Complex runtime machinery
let _formatted = core::format_args!("{}", a[idx.get()]);
*c_elem = a[idx.get()];
let _formatted = core::format_args!("{}", a[i]);
*c_elem = a[i];
}
}
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,18 @@ Tests whether the collector correctly handles monomorphized generic kernels. Thi
#[kernel]
pub fn scale<T: Copy + Mul<Output = T>>(factor: T, input: &[T], mut out: DisjointSlice<T>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(out_elem) = out.get_mut(idx) {
*out_elem = input[idx.get()] * factor;
*out_elem = input[i] * factor;
}
}

#[kernel]
pub fn add<T: Copy + Add<Output = T>>(a: &[T], b: &[T], mut c: DisjointSlice<T>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(c_elem) = c.get_mut(idx) {
*c_elem = a[idx.get()] + b[idx.get()];
*c_elem = a[i] + b[i];
}
}
```
Expand Down Expand Up @@ -98,8 +100,9 @@ pub fn saxpy<T: Copy + Mul<Output = T> + Add<Output = T>>(
a: T, x: &[T], y: &[T], mut out: DisjointSlice<T>
) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(out_elem) = out.get_mut(idx) {
*out_elem = a * x[idx.get()] + y[idx.get()];
*out_elem = a * x[i] + y[i];
}
}

Expand All @@ -116,8 +119,9 @@ pub fn saxpy<T: Copy + Mul<Output = T> + Add<Output = T>>(
#[kernel]
pub fn map<T: Copy, F: Fn(T) -> T + Copy>(f: F, input: &[T], mut out: DisjointSlice<T>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(out_elem) = out.get_mut(idx) {
*out_elem = f(input[idx.get()]);
*out_elem = f(input[i]);
}
}
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ Demonstrates the `#[device]` attribute for helper functions that are called from
#[device]
pub fn vecadd_device(a: &[f32], b: &[f32], mut c: DisjointSlice<f32>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(c_elem) = c.get_mut(idx) {
let i = idx.get();
*c_elem = a[i] + b[i];
}
}
Expand Down Expand Up @@ -90,11 +90,12 @@ fn clamp(x: f32, lo: f32, hi: f32) -> f32 {
#[kernel]
pub fn apply_clamp(input: &[f32], mut out: DisjointSlice<f32>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(out_elem) = out.get_mut(idx) {
// Call the device function by its original name. The macro
// expands this to the reserved internal symbol behind the
// scenes; users never type the mangled name themselves.
*out_elem = clamp(input[idx.get()], 0.0, 1.0);
*out_elem = clamp(input[i], 0.0, 1.0);
}
}
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ Tests passing closures from host code to generic GPU kernels. This enables funct
#[kernel]
pub fn map<T: Copy, F: Fn(T) -> T + Copy>(f: F, input: &[T], mut out: DisjointSlice<T>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(out_elem) = out.get_mut(idx) {
*out_elem = f(input[idx.get()]);
*out_elem = f(input[i]);
}
}
```
Expand Down
3 changes: 2 additions & 1 deletion cuda-oxide/crates/rustc-codegen-cuda/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,9 @@
//! #[kernel]
//! pub fn vecadd(a: &[f32], b: &[f32], mut c: DisjointSlice<f32>) {
//! let idx = thread::index_1d();
//! let i = idx.get();
//! if let Some(c_elem) = c.get_mut(idx) {
//! *c_elem = a[idx.get()] + b[idx.get()];
//! *c_elem = a[i] + b[i];
//! }
//! }
//!
Expand Down
3 changes: 2 additions & 1 deletion cuda-oxide/cuda-oxide-book/compiler/mir-importer.md
Original file line number Diff line number Diff line change
Expand Up @@ -401,8 +401,9 @@ pieces connect. Here is a vector addition kernel:
#[kernel]
pub fn vecadd(a: &[f32], b: &[f32], mut c: DisjointSlice<f32>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(c_elem) = c.get_mut(idx) {
*c_elem = a[idx.get()] + b[idx.get()];
*c_elem = a[i] + b[i];
}
}
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,9 @@ pub fn apply_transform(input: &[f32], mut out: DisjointSlice<f32>) {
clamped * clamped
};

let i = idx.get();
if let Some(out_elem) = out.get_mut(idx) {
*out_elem = transform(input[idx.get()]);
*out_elem = transform(input[i]);
}
}
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ pub fn debug_kernel(data: &[f32], mut out: DisjointSlice<f32>) {
if idx.get() < 4 {
gpu_printf!("Thread {} sees value {}\n", idx.get(), data[idx.get()]);
}
let i = idx.get();
if let Some(out_elem) = out.get_mut(idx) {
*out_elem = data[idx.get()] * 2.0;
*out_elem = data[i] * 2.0;
}
}
```
Expand Down Expand Up @@ -81,7 +82,7 @@ the GPU. `gpu_printf!` bypasses all of this by lowering directly to a CUDA
For fatal error checking on the device, use `gpu_assert!` or `debug::trap()`:

```rust
use cuda_device::{DisjointSlice, debug, gpu_assert, kernel, thread};
use cuda_device::{DisjointSlice, gpu_assert, kernel, thread};

#[kernel]
pub fn checked_kernel(data: &[f32], len: u32, mut out: DisjointSlice<f32>) {
Expand All @@ -96,8 +97,9 @@ pub fn checked_kernel(data: &[f32], len: u32, mut out: DisjointSlice<f32>) {
"expected non-negative input"
);

let i = idx.get();
if let Some(out_elem) = out.get_mut(idx) {
*out_elem = data[idx.get()];
*out_elem = data[i];
}
}
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ use cuda_device::{DisjointSlice, kernel, thread};
#[kernel]
pub fn vecadd(a: &[f32], b: &[f32], mut c: DisjointSlice<f32>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(c_elem) = c.get_mut(idx) {
*c_elem = a[idx.get()] + b[idx.get()];
*c_elem = a[i] + b[i];
}
}
```
Expand Down Expand Up @@ -238,8 +239,9 @@ returns `None` for out-of-bounds indices, so those threads simply do nothing:
#[kernel]
pub fn vecadd(a: &[f32], b: &[f32], mut c: DisjointSlice<f32>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(c_elem) = c.get_mut(idx) { // out-of-bounds threads skip
*c_elem = a[idx.get()] + b[idx.get()];
*c_elem = a[i] + b[i];
}
}
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ use cuda_device::{DisjointSlice, kernel, thread};
#[kernel]
pub fn vecadd(a: &[f32], b: &[f32], mut c: DisjointSlice<f32>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(c_elem) = c.get_mut(idx) {
*c_elem = a[idx.get()] + b[idx.get()];
*c_elem = a[i] + b[i];
}
}
```
Expand Down Expand Up @@ -152,8 +153,9 @@ fn clamp(x: f32, lo: f32, hi: f32) -> f32 {
#[kernel]
pub fn apply_clamp(input: &[f32], mut out: DisjointSlice<f32>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(out_elem) = out.get_mut(idx) {
*out_elem = clamp(input[idx.get()], 0.0, 1.0);
*out_elem = clamp(input[i], 0.0, 1.0);
}
}
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ on multiple slices:
#[kernel]
pub fn vecadd(a: &[f32], b: &[f32], mut c: DisjointSlice<f32>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(c_elem) = c.get_mut(idx) {
let i = idx.get();
*c_elem = a[i] + b[i];
}
}
Expand Down
6 changes: 4 additions & 2 deletions cuda-oxide/cuda-oxide-book/projects/async-mlp-pipeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,13 @@ pub fn matvec_naive(
mut vec_out: DisjointSlice<f32>,
) {
let row = thread::index_1d();
let i = row.get();
if let Some(out_elem) = vec_out.get_mut(row) {
let n_sz = n as usize;
let mut sum = 0.0f32;
let mut j = 0usize;
while j < n_sz {
sum = sum + mat[row.get() * n_sz + j] * vec_in[j];
sum = sum + mat[i * n_sz + j] * vec_in[j];
j = j + 1;
}
*out_elem = sum;
Expand All @@ -181,8 +182,9 @@ interfaces.
#[kernel]
pub fn relu(input: &[f32], mut output: DisjointSlice<f32>) {
let idx = thread::index_1d();
let i = idx.get();
if let Some(out_elem) = output.get_mut(idx) {
let val = input[idx.get()];
let val = input[i];
*out_elem = if val > 0.0f32 { val } else { 0.0f32 };
}
}
Expand Down
Loading