Class: Cumo::CUDA::PinnedMemory

Inherits:
Object
  • Object
show all
Defined in:
lib/cumo/cuda/pinned_memory.rb

Overview

Page-locked host memory, which a copy to or from the device can be asynchronous with. NArray#set and NArray#get copy through it.

pinned = Cumo::CUDA::PinnedMemory.new(a.byte_size)
s.with { a.get(pinned) }        # queued on s, complete when with returns
Cumo::SFloat.from_binary(pinned.read, a.shape)

A copy in flight keeps the array alive and is waited for by read, write, free and the next copy, so the bytes read are the copy's.

Constant Summary collapse

LIVE =
ObjectSpace::WeakMap.new

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(bytesize, flags: Runtime::CUDA_HOST_ALLOC_DEFAULT) ⇒ PinnedMemory

Returns a new instance of PinnedMemory.



33
34
35
36
37
38
39
40
# File 'lib/cumo/cuda/pinned_memory.rb', line 33

def initialize(bytesize, flags: Runtime::CUDA_HOST_ALLOC_DEFAULT)
  @ptr = Runtime.cudaHostAlloc(bytesize, flags)
  @bytesize = bytesize
  @state = [@ptr, nil]
  @busy_with = nil
  LIVE[@ptr] = self
  ObjectSpace.define_finalizer(self, self.class.finalizer(@state))
end

Instance Attribute Details

#bytesizeObject (readonly)

Returns the value of attribute bytesize.



16
17
18
# File 'lib/cumo/cuda/pinned_memory.rb', line 16

def bytesize
  @bytesize
end

Class Method Details

.finalizer(state) ⇒ Object

The state is shared with the finalizer, so a copy still in flight when the buffer is dropped is waited for before the memory goes.



25
26
27
28
29
30
31
# File 'lib/cumo/cuda/pinned_memory.rb', line 25

def self.finalizer(state)
  proc do
    ptr, event = state
    event.synchronize rescue nil if event
    Runtime.cudaFreeHost(ptr) rescue nil unless LIVE[ptr]
  end
end

.from_binary(bytes) ⇒ Object

A buffer holding the bytes of a String.



19
20
21
# File 'lib/cumo/cuda/pinned_memory.rb', line 19

def self.from_binary(bytes)
  new(bytes.bytesize).write(bytes)
end

Instance Method Details

#copy(narray, direction, stream) ⇒ Object

Queues a copy between the buffer and an array on a stream, the current one when nil, and records where it ends. NArray#set and #get call this.

Raises:

  • (TypeError)


80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/cumo/cuda/pinned_memory.rb', line 80

def copy(narray, direction, stream)
  raise TypeError, "stream: takes a Stream, got a #{stream.class}" unless stream.nil? || stream.is_a?(Stream)
  synchronize
  if direction == :to_narray
    Runtime.memcpy_pinned_to_narray(handle, narray, stream&.handle)
  else
    Runtime.memcpy_narray_to_pinned(narray, handle, stream&.handle)
  end
  @busy_with = narray
  @state[1] = Event.new(timing: false).record(stream || Stream.current)
  self
end

#freeObject



70
71
72
73
74
75
76
# File 'lib/cumo/cuda/pinned_memory.rb', line 70

def free
  return if @ptr.nil?
  synchronize
  Runtime.cudaFreeHost(@ptr)
  ObjectSpace.undefine_finalizer(self)
  @ptr = nil
end

#handleObject

The handle of a buffer that has not been freed.

Raises:

  • (ArgumentError)


43
44
45
46
# File 'lib/cumo/cuda/pinned_memory.rb', line 43

def handle
  raise ArgumentError, "the pinned host buffer is freed" if @ptr.nil?
  @ptr
end

#read(length = nil, offset = 0) ⇒ Object Also known as: to_binary

The bytes, or length of them from offset, as a String.



57
58
59
60
# File 'lib/cumo/cuda/pinned_memory.rb', line 57

def read(length = nil, offset = 0)
  synchronize
  Runtime.pinned_read(handle, offset, length || @bytesize - offset)
end

#synchronizeObject

Waits for the copy in flight, if any.



49
50
51
52
53
54
# File 'lib/cumo/cuda/pinned_memory.rb', line 49

def synchronize
  @state[1]&.synchronize
  @state[1] = nil
  @busy_with = nil
  self
end

#write(bytes, offset = 0) ⇒ Object

Writes the bytes of a String at offset.



64
65
66
67
68
# File 'lib/cumo/cuda/pinned_memory.rb', line 64

def write(bytes, offset = 0)
  synchronize
  Runtime.pinned_write(handle, offset, bytes)
  self
end