gorgonia.org/gorgonia@v0.9.17/noextern.go (about) 1 // +build !cuda 2 3 package gorgonia 4 5 import "gorgonia.org/tensor" 6 7 // CUDA indicates if this build is using CUDA 8 const CUDA = false 9 10 var _ tensor.Engine = ExternMetadata{} 11 12 // ExternMetadata is used to hold metadata about external execution devices. 13 // In this build, it's an empty struct because the default build doesn't use external devices to execute the graph on 14 type ExternMetadata struct { 15 tensor.Engine 16 b batchedBLAS 17 workAvailable chan bool 18 syncChan chan struct{} 19 } 20 21 func (m *ExternMetadata) init() error { 22 m.syncChan = make(chan struct{}) 23 if m.b != nil { 24 m.workAvailable = make(chan bool) 25 go m.collectBLASWork() 26 } 27 return nil 28 } 29 30 // initFail is a no-op 31 func (m *ExternMetadata) initFail() {} 32 33 // HasFunc will always return false in this build 34 func (m ExternMetadata) HasFunc(name string) bool { return false } 35 36 // WorkAvailable returns a channel of empty struct, which is used to signal to the VM when there is work available. The VM will then call the DoWork method. 37 func (m *ExternMetadata) WorkAvailable() <-chan bool { 38 if m.b != nil { 39 return m.workAvailable 40 } 41 42 return nil 43 } 44 45 // Sync returns the sync channel 46 func (m *ExternMetadata) Sync() chan struct{} { return m.syncChan } 47 48 // DoWork flushes any batched cgo calls. In this build it only flushes the batched BLAS calls. 49 func (m *ExternMetadata) DoWork() error { 50 if m.b != nil { 51 m.b.DoWork() 52 } 53 return nil 54 } 55 56 // Get allocates a memory of the size. In this build it returns a NoOpError. 57 func (m *ExternMetadata) Get(dev Device, size int64) (tensor.Memory, error) { return nil, noopError{} } 58 59 // GetFromValue allocates a memory of the size of v. In this build it returns a NoOpError, and v itself 60 func (m *ExternMetadata) GetFromValue(dev Device, v Value) (tensor.Memory, error) { 61 return v, noopError{} 62 } 63 64 // Put puts a previously allocated memory slab of the provided size back into the pool. Currently this is a No-op in this build. 65 func (m *ExternMetadata) Put(dev Device, mem tensor.Memory, size int64) {} 66 67 // PutValue puts a previously allocated value into the pool. In this build, it is a noop. 68 func (m *ExternMetadata) PutValue(dev Device, v Value) {} 69 70 // Transfer transfers a value from device to device. In this build, it's a noop, returning the input value, and a nil error 71 func (m *ExternMetadata) Transfer(toDev, fromDev Device, v Value, synchronous bool) (retVal Value, err error) { 72 return v, nil 73 } 74 75 // Reset is a noop function for compatibility with the Cuda build 76 func (m *ExternMetadata) Reset() {} 77 78 // Cleanup cleans up the ancillary allocations made during the calling of batched external device function. 79 // 80 // The reason for this method is due to the fact that there is currently no way to free memory while the context is still running without causing 81 // some weirdness to the CUDA calls. 82 // 83 // This is a No-op in this build 84 func (m *ExternMetadata) Cleanup() {} 85 86 // Signal sends a signal down the workavailable channel, telling the VM to call the DoWork method. Signal is a synchronous method 87 func (m *ExternMetadata) Signal() { 88 m.signal() 89 if m.workAvailable != nil { 90 <-m.syncChan 91 } 92 } 93 94 // collectBLASWork is a muxer for CBLAS/CuBLAS (if any) and the devices 95 func (m *ExternMetadata) collectBLASWork() { 96 if m.b != nil { 97 for range m.b.WorkAvailable() { 98 m.workAvailable <- false 99 } 100 } 101 } 102 103 func (m *ExternMetadata) signal() { 104 if m.workAvailable != nil { 105 m.workAvailable <- true 106 } 107 } 108 109 func (m *ExternMetadata) setEngine(e tensor.Engine) { m.Engine = e } 110 111 // ValueOnDevice gets the value of the node as a Value but on the desired device. In this build the device is always CPU, so it's equivalent to calling .Value() 112 func (n *Node) ValueOnDevice(dev Device, extern External) (retVal Value, allocOnExtern bool, err error) { 113 return n.Value(), false, nil 114 } 115 116 // GradOnDevice gets the gradient value of the node as a Value but on the desired device. In this build the device is always CPU, so it's equivalent to calling .Grad() 117 func (n *Node) GradOnDevice(dev Device, extern External) (retVal Value, allocOnExtern bool, err error) { 118 retVal, err = n.Grad() 119 return retVal, false, err 120 }