Class: Ignis::CUDA::Memory
- Inherits:
-
Object
- Object
- Ignis::CUDA::Memory
- Defined in:
- lib/nvruby/cuda/memory.rb
Overview
Manages GPU device memory allocation and transfers.
Refactored to use Fiddle-based RuntimeAPI hot-path methods. No FFI::MemoryPointer usage — all pointers via Fiddle::Pointer.
Instance Attribute Summary collapse
-
#device_index ⇒ Integer
readonly
Device index.
-
#device_ptr ⇒ Fiddle::Pointer
readonly
Device pointer.
-
#size ⇒ Integer
readonly
Size in bytes.
Class Method Summary collapse
-
.release_finalizer(ptr, device_index) ⇒ Proc
Create a finalizer proc for releasing device memory.
Instance Method Summary collapse
-
#address ⇒ Integer
Raw address.
-
#copy_from_device(source, count: nil, stream: nil) ⇒ void
Copy data from another device memory.
-
#copy_from_host(host_data, count: nil, stream: nil) ⇒ void
Copy data from host to device.
-
#copy_to_host(host_buffer: nil, count: nil, stream: nil) ⇒ Fiddle::Pointer
Copy data from device to host.
-
#ffi_ptr ⇒ FFI::Pointer
Device pointer wrapped as an FFI::Pointer.
-
#free! ⇒ void
Free the device memory.
- #freed? ⇒ Boolean
-
#initialize(size, device: nil, ptr: nil, owned: true) ⇒ Memory
constructor
A new instance of Memory.
- #inspect ⇒ String
-
#memset(value, count: nil, stream: nil) ⇒ void
Set memory to a value.
-
#to_ptr ⇒ Fiddle::Pointer
Pointer for interop.
- #to_s ⇒ String
-
#zero!(stream: nil) ⇒ void
Zero out the memory.
Constructor Details
#initialize(size, device: nil, ptr: nil, owned: true) ⇒ Memory
Returns a new instance of Memory.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/nvruby/cuda/memory.rb', line 25 def initialize(size, device: nil, ptr: nil, owned: true) @size = size @device_index = resolve_device_index(device) @owned = owned if ptr @device_ptr = ptr.is_a?(Fiddle::Pointer) ? ptr : Fiddle::Pointer.new(ptr.to_i) else @device_ptr = allocate_device_memory end @freed = false if @owned captured_ptr = @device_ptr captured_device = @device_index ObjectSpace.define_finalizer(self, self.class.release_finalizer(captured_ptr, captured_device)) end end |
Instance Attribute Details
#device_index ⇒ Integer (readonly)
Returns Device index.
19 20 21 |
# File 'lib/nvruby/cuda/memory.rb', line 19 def device_index @device_index end |
#device_ptr ⇒ Fiddle::Pointer (readonly)
Returns Device pointer.
13 14 15 |
# File 'lib/nvruby/cuda/memory.rb', line 13 def device_ptr @device_ptr end |
#size ⇒ Integer (readonly)
Returns Size in bytes.
16 17 18 |
# File 'lib/nvruby/cuda/memory.rb', line 16 def size @size end |
Class Method Details
.release_finalizer(ptr, device_index) ⇒ Proc
Create a finalizer proc for releasing device memory.
230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/nvruby/cuda/memory.rb', line 230 def release_finalizer(ptr, device_index) ptr_addr = ptr.to_i proc do begin RuntimeAPI.ensure_loaded! current = RuntimeAPI.get_device RuntimeAPI.set_device(device_index) if current != device_index RuntimeAPI.free(Fiddle::Pointer.new(ptr_addr)) RuntimeAPI.set_device(current) if current != device_index rescue StandardError # Silently ignore errors during finalization end end end |
Instance Method Details
#address ⇒ Integer
Returns raw address.
62 63 64 |
# File 'lib/nvruby/cuda/memory.rb', line 62 def address @device_ptr.to_i end |
#copy_from_device(source, count: nil, stream: nil) ⇒ void
This method returns an undefined value.
Copy data from another device memory.
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/nvruby/cuda/memory.rb', line 162 def copy_from_device(source, count: nil, stream: nil) raise MemoryError, 'Memory has been freed' if @freed raise MemoryError, 'Source memory has been freed' if source.freed? count ||= [source.size, @size].min raise MemoryError, "Copy count #{count} exceeds allocation size #{@size}" if count > @size RuntimeAPI.ensure_loaded! if stream RuntimeAPI.memcpy_async( @device_ptr, source.device_ptr, count, RuntimeAPI::MEMCPY_DEVICE_TO_DEVICE, stream.to_ptr ) else RuntimeAPI.memcpy( @device_ptr, source.device_ptr, count, RuntimeAPI::MEMCPY_DEVICE_TO_DEVICE ) end end |
#copy_from_host(host_data, count: nil, stream: nil) ⇒ void
This method returns an undefined value.
Copy data from host to device.
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/nvruby/cuda/memory.rb', line 91 def copy_from_host(host_data, count: nil, stream: nil) raise MemoryError, 'Memory has been freed' if @freed count ||= @size raise MemoryError, "Copy count #{count} exceeds allocation size #{@size}" if count > @size RuntimeAPI.ensure_loaded! host_ptr = prepare_host_pointer(host_data) ensure_correct_device do if stream RuntimeAPI.memcpy_async( @device_ptr, host_ptr, count, RuntimeAPI::MEMCPY_HOST_TO_DEVICE, stream.to_ptr ) else RuntimeAPI.memcpy( @device_ptr, host_ptr, count, RuntimeAPI::MEMCPY_HOST_TO_DEVICE ) end end end |
#copy_to_host(host_buffer: nil, count: nil, stream: nil) ⇒ Fiddle::Pointer
Copy data from device to host.
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/nvruby/cuda/memory.rb', line 120 def copy_to_host(host_buffer: nil, count: nil, stream: nil) raise MemoryError, 'Memory has been freed' if @freed count ||= @size raise MemoryError, "Copy count #{count} exceeds allocation size #{@size}" if count > @size RuntimeAPI.ensure_loaded! host_buffer ||= Fiddle::Pointer.malloc(count) # The destination may be an FFI::MemoryPointer (NvArray host buffer); # bridge it to a Fiddle address for the Fiddle-based memcpy, but return # the original object so the caller can read it back with its own API. dst_ptr = if host_buffer.is_a?(Fiddle::Pointer) host_buffer elsif host_buffer.respond_to?(:address) Fiddle::Pointer.new(host_buffer.address) else host_buffer end ensure_correct_device do if stream RuntimeAPI.memcpy_async( dst_ptr, @device_ptr, count, RuntimeAPI::MEMCPY_DEVICE_TO_HOST, stream.to_ptr ) else RuntimeAPI.memcpy( dst_ptr, @device_ptr, count, RuntimeAPI::MEMCPY_DEVICE_TO_HOST ) end end host_buffer end |
#ffi_ptr ⇒ FFI::Pointer
Device pointer wrapped as an FFI::Pointer.
The hot path (this class’ own cudaMemcpy etc.) is Fiddle-based, but the CUDA-X library bindings (cuBLAS/cuSOLVER/cuFFT/cuRAND/cuSPARSE) are FFI and cannot accept a Fiddle::Pointer. Use this when handing a device buffer to an FFI-bound library call.
57 58 59 |
# File 'lib/nvruby/cuda/memory.rb', line 57 def ffi_ptr FFI::Pointer.new(@device_ptr.to_i) end |
#free! ⇒ void
This method returns an undefined value.
Free the device memory.
73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/nvruby/cuda/memory.rb', line 73 def free! return if @freed return unless @owned RuntimeAPI.ensure_loaded! ensure_correct_device do RuntimeAPI.free(@device_ptr) end @freed = true ObjectSpace.undefine_finalizer(self) end |
#freed? ⇒ Boolean
67 68 69 |
# File 'lib/nvruby/cuda/memory.rb', line 67 def freed? @freed end |
#inspect ⇒ String
220 221 222 223 |
# File 'lib/nvruby/cuda/memory.rb', line 220 def inspect "#<Ignis::CUDA::Memory:#{object_id} size=#{@size} device=#{@device_index} " \ "ptr=0x#{@device_ptr.to_i.to_s(16)} freed=#{@freed}>" end |
#memset(value, count: nil, stream: nil) ⇒ void
This method returns an undefined value.
Set memory to a value.
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/nvruby/cuda/memory.rb', line 189 def memset(value, count: nil, stream: nil) raise MemoryError, 'Memory has been freed' if @freed count ||= @size raise MemoryError, "Memset count #{count} exceeds allocation size #{@size}" if count > @size RuntimeAPI.ensure_loaded! ensure_correct_device do if stream RuntimeAPI.memset_async(@device_ptr, value, count, stream.to_ptr) else RuntimeAPI.memset(@device_ptr, value, count) end end end |
#to_ptr ⇒ Fiddle::Pointer
Returns pointer for interop.
46 47 48 |
# File 'lib/nvruby/cuda/memory.rb', line 46 def to_ptr @device_ptr end |
#to_s ⇒ String
214 215 216 217 |
# File 'lib/nvruby/cuda/memory.rb', line 214 def to_s status = @freed ? 'freed' : 'allocated' "DeviceMemory[#{@size} bytes, device #{@device_index}, #{status}]" end |
#zero!(stream: nil) ⇒ void
This method returns an undefined value.
Zero out the memory.
209 210 211 |
# File 'lib/nvruby/cuda/memory.rb', line 209 def zero!(stream: nil) memset(0, stream: stream) end |