Skip to content

Commit 0784b39

Browse files
committed
Add memory ops example
1 parent 24fde17 commit 0784b39

1 file changed

Lines changed: 163 additions & 0 deletions

File tree

cuda_core/examples/memory_ops.py

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import cupy as cp
2+
import numpy as np
3+
from cuda.core.experimental import (
4+
Device, LaunchConfig, Program, ProgramOptions, launch,
5+
DeviceMemoryResource, LegacyPinnedMemoryResource, Buffer
6+
)
7+
from cuda.core.experimental._memory import MemoryResource
8+
from cuda.core.experimental._utils.cuda_utils import handle_return
9+
from cuda.bindings import driver
10+
11+
# Kernel for memory operations
12+
code = """
13+
extern "C"
14+
__global__ void memory_ops(float* device_data,
15+
float* pinned_data,
16+
size_t N) {
17+
const unsigned int tid = threadIdx.x + blockIdx.x * blockDim.x;
18+
if (tid < N) {
19+
// Access device memory
20+
device_data[tid] = device_data[tid] + 1.0f;
21+
22+
// Access pinned memory (zero-copy from GPU)
23+
pinned_data[tid] = pinned_data[tid] * 3.0f;
24+
}
25+
}
26+
"""
27+
28+
dev = Device()
29+
dev.set_current()
30+
stream = dev.create_stream()
31+
32+
# Compile kernel
33+
arch = "".join(f"{i}" for i in dev.compute_capability)
34+
program_options = ProgramOptions(std="c++17", arch=f"sm_{arch}")
35+
prog = Program(code, code_type="c++", options=program_options)
36+
mod = prog.compile("cubin")
37+
kernel = mod.get_kernel("memory_ops")
38+
39+
# Create different memory resources
40+
device_mr = DeviceMemoryResource(dev.device_id)
41+
pinned_mr = LegacyPinnedMemoryResource()
42+
43+
# Allocate different types of memory
44+
size = 1024
45+
dtype = cp.float32
46+
element_size = dtype().itemsize
47+
total_size = size * element_size
48+
49+
# 1. Device Memory (GPU-only)
50+
device_buffer = device_mr.allocate(total_size, stream=stream)
51+
device_array = cp.ndarray(
52+
size, dtype=dtype,
53+
memptr=cp.cuda.MemoryPointer(
54+
cp.cuda.UnownedMemory(int(device_buffer.handle), device_buffer.size, device_buffer), 0
55+
)
56+
)
57+
58+
# 2. Pinned Memory (CPU memory, GPU accessible)
59+
pinned_buffer = pinned_mr.allocate(total_size, stream=stream)
60+
pinned_array = cp.ndarray(
61+
size, dtype=dtype,
62+
memptr=cp.cuda.MemoryPointer(
63+
cp.cuda.UnownedMemory(int(pinned_buffer.handle), pinned_buffer.size, pinned_buffer), 0
64+
)
65+
)
66+
67+
# Initialize data
68+
rng = cp.random.default_rng()
69+
device_array[:] = rng.random(size, dtype=dtype)
70+
pinned_array[:] = rng.random(size, dtype=dtype)
71+
72+
# Store original values for verification
73+
device_original = device_array.copy()
74+
pinned_original = pinned_array.copy()
75+
76+
# Sync before kernel launch
77+
dev.sync()
78+
79+
# Launch kernel
80+
block = 256
81+
grid = (size + block - 1) // block
82+
config = LaunchConfig(grid=grid, block=block)
83+
84+
launch(stream, config, kernel,
85+
device_buffer, pinned_buffer, cp.uint64(size))
86+
stream.sync()
87+
88+
# Verify kernel operations
89+
assert cp.allclose(device_array, device_original + 1.0), "Device memory operation failed"
90+
assert cp.allclose(pinned_array, pinned_original * 3.0), "Pinned memory operation failed"
91+
92+
# Demonstrate buffer copying operations
93+
print("Memory buffer properties:")
94+
print(f"Device buffer - Device accessible: {device_buffer.is_device_accessible}")
95+
print(f"Pinned buffer - Device accessible: {pinned_buffer.is_device_accessible}")
96+
97+
# Assert memory properties
98+
assert device_buffer.is_device_accessible, "Device buffer should be device accessible"
99+
assert not device_buffer.is_host_accessible, "Device buffer should not be host accessible"
100+
assert pinned_buffer.is_device_accessible, "Pinned buffer should be device accessible"
101+
assert pinned_buffer.is_host_accessible, "Pinned buffer should be host accessible"
102+
103+
# Copy data between different memory types
104+
print("\nCopying data between memory types...")
105+
106+
# Copy from device to pinned memory
107+
device_buffer.copy_to(pinned_buffer, stream=stream)
108+
stream.sync()
109+
110+
# Verify the copy operation
111+
assert cp.allclose(pinned_array, device_array), "Device to pinned copy failed"
112+
113+
# Create a new device buffer and copy from pinned
114+
new_device_buffer = device_mr.allocate(total_size, stream=stream)
115+
new_device_array = cp.ndarray(
116+
size, dtype=dtype,
117+
memptr=cp.cuda.MemoryPointer(
118+
cp.cuda.UnownedMemory(int(new_device_buffer.handle), new_device_buffer.size, new_device_buffer), 0
119+
)
120+
)
121+
122+
pinned_buffer.copy_to(new_device_buffer, stream=stream)
123+
stream.sync()
124+
125+
# Verify the copy operation
126+
assert cp.allclose(new_device_array, pinned_array), "Pinned to device copy failed"
127+
128+
# Demonstrate DLPack integration
129+
print("\nDLPack device information:")
130+
print(f"Device buffer DLPack device: {device_buffer.__dlpack_device__()}")
131+
print(f"Pinned buffer DLPack device: {pinned_buffer.__dlpack_device__()}")
132+
133+
# Assert DLPack device types
134+
from cuda.core.experimental._memory import DLDeviceType
135+
136+
device_dlpack = device_buffer.__dlpack_device__()
137+
pinned_dlpack = pinned_buffer.__dlpack_device__()
138+
139+
assert device_dlpack[0] == DLDeviceType.kDLCUDA, "Device buffer should have CUDA device type"
140+
assert pinned_dlpack[0] == DLDeviceType.kDLCUDAHost, "Pinned buffer should have CUDA host device type"
141+
142+
# Test buffer size properties
143+
assert device_buffer.size == total_size, f"Device buffer size mismatch: expected {total_size}, got {device_buffer.size}"
144+
assert pinned_buffer.size == total_size, f"Pinned buffer size mismatch: expected {total_size}, got {pinned_buffer.size}"
145+
assert new_device_buffer.size == total_size, f"New device buffer size mismatch: expected {total_size}, got {new_device_buffer.size}"
146+
147+
# Test memory resource properties
148+
assert device_buffer.memory_resource == device_mr, "Device buffer should use device memory resource"
149+
assert pinned_buffer.memory_resource == pinned_mr, "Pinned buffer should use pinned memory resource"
150+
assert new_device_buffer.memory_resource == device_mr, "New device buffer should use device memory resource"
151+
152+
# Clean up
153+
device_buffer.close(stream)
154+
pinned_buffer.close(stream)
155+
new_device_buffer.close(stream)
156+
stream.close()
157+
158+
# Verify buffers are properly closed
159+
assert device_buffer.handle == 0, "Device buffer should be closed"
160+
assert pinned_buffer.handle == 0, "Pinned buffer should be closed"
161+
assert new_device_buffer.handle == 0, "New device buffer should be closed"
162+
163+
print("Memory management example completed!")

0 commit comments

Comments
 (0)