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 ("\n Copying 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 ("\n DLPack 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