mirror of
https://github.com/pseXperiments/icicle.git
synced 2026-01-09 23:48:10 -05:00
This PR introduces major updates for ICICLE Core, Rust and Golang bindings --------- Co-authored-by: Yuval Shekel <yshekel@gmail.com> Co-authored-by: DmytroTym <dmytrotym1@gmail.com> Co-authored-by: Otsar <122266060+Otsar-Raikou@users.noreply.github.com> Co-authored-by: VitaliiH <vhnatyk@gmail.com> Co-authored-by: release-bot <release-bot@ingonyama.com> Co-authored-by: Stas <spolonsky@icloud.com> Co-authored-by: Jeremy Felder <jeremy.felder1@gmail.com> Co-authored-by: ImmanuelSegol <3ditds@gmail.com> Co-authored-by: JimmyHongjichuan <45908291+JimmyHongjichuan@users.noreply.github.com> Co-authored-by: pierre <pierreuu@gmail.com> Co-authored-by: Leon Hibnik <107353745+LeonHibnik@users.noreply.github.com> Co-authored-by: nonam3e <timur@ingonyama.com> Co-authored-by: Vlad <88586482+vladfdp@users.noreply.github.com> Co-authored-by: LeonHibnik <leon@ingonyama.com> Co-authored-by: nonam3e <71525212+nonam3e@users.noreply.github.com> Co-authored-by: vladfdp <vlad.heintz@gmail.com>
247 lines
5.6 KiB
Go
247 lines
5.6 KiB
Go
package core
|
|
|
|
import (
|
|
"unsafe"
|
|
|
|
cr "github.com/ingonyama-zk/icicle/wrappers/golang/cuda_runtime"
|
|
)
|
|
|
|
type HostOrDeviceSlice interface {
|
|
Len() int
|
|
Cap() int
|
|
IsEmpty() bool
|
|
IsOnDevice() bool
|
|
AsUnsafePointer() unsafe.Pointer
|
|
}
|
|
|
|
type DevicePointer = unsafe.Pointer
|
|
|
|
type DeviceSlice struct {
|
|
inner unsafe.Pointer
|
|
// capacity is the number of bytes that have been allocated
|
|
capacity int
|
|
// length is the number of elements that have been written
|
|
length int
|
|
}
|
|
|
|
func (d DeviceSlice) Len() int {
|
|
return d.length
|
|
}
|
|
|
|
func (d DeviceSlice) Cap() int {
|
|
return d.capacity
|
|
}
|
|
|
|
func (d DeviceSlice) IsEmpty() bool {
|
|
return d.length == 0
|
|
}
|
|
|
|
func (d DeviceSlice) AsUnsafePointer() unsafe.Pointer {
|
|
return d.inner
|
|
}
|
|
|
|
func (d DeviceSlice) IsOnDevice() bool {
|
|
return true
|
|
}
|
|
|
|
func (d DeviceSlice) GetDeviceId() int {
|
|
return cr.GetDeviceFromPointer(d.inner)
|
|
}
|
|
|
|
// CheckDevice is used to ensure that the DeviceSlice about to be used resides on the currently set device
|
|
func (d DeviceSlice) CheckDevice() {
|
|
if currentDeviceId, err := cr.GetDevice(); err != cr.CudaSuccess || d.GetDeviceId() != currentDeviceId {
|
|
panic("Attempt to use DeviceSlice on a different device")
|
|
}
|
|
}
|
|
|
|
func (d *DeviceSlice) Range(start, end int, endInclusive bool) DeviceSlice {
|
|
if end <= start {
|
|
panic("Cannot have negative or zero size slices")
|
|
}
|
|
|
|
if end >= d.length {
|
|
panic("Cannot increase slice size from Range")
|
|
}
|
|
|
|
var newSlice DeviceSlice
|
|
switch {
|
|
case start < 0:
|
|
panic("Negative value for start is not supported")
|
|
case start == 0:
|
|
newSlice = d.RangeTo(end, endInclusive)
|
|
case start > 0:
|
|
tempSlice := d.RangeFrom(start)
|
|
newSlice = tempSlice.RangeTo(end-start, endInclusive)
|
|
}
|
|
return newSlice
|
|
}
|
|
|
|
func (d *DeviceSlice) RangeTo(end int, inclusive bool) DeviceSlice {
|
|
if end <= 0 {
|
|
panic("Cannot have negative or zero size slices")
|
|
}
|
|
|
|
if end >= d.length {
|
|
panic("Cannot increase slice size from Range")
|
|
}
|
|
|
|
var newSlice DeviceSlice
|
|
sizeOfElement := d.capacity / d.length
|
|
newSlice.length = end
|
|
if inclusive {
|
|
newSlice.length += 1
|
|
}
|
|
newSlice.capacity = newSlice.length * sizeOfElement
|
|
newSlice.inner = d.inner
|
|
return newSlice
|
|
}
|
|
|
|
func (d *DeviceSlice) RangeFrom(start int) DeviceSlice {
|
|
if start >= d.length {
|
|
panic("Cannot have negative or zero size slices")
|
|
}
|
|
|
|
if start < 0 {
|
|
panic("Negative value for start is not supported")
|
|
}
|
|
|
|
var newSlice DeviceSlice
|
|
sizeOfElement := d.capacity / d.length
|
|
|
|
newSlice.inner = unsafe.Pointer(uintptr(d.inner) + uintptr(start)*uintptr(sizeOfElement))
|
|
newSlice.length = d.length - start
|
|
newSlice.capacity = d.capacity - start*sizeOfElement
|
|
|
|
return newSlice
|
|
}
|
|
|
|
// TODO: change signature to be Malloc(element, numElements)
|
|
// calc size internally
|
|
func (d *DeviceSlice) Malloc(size, sizeOfElement int) (DeviceSlice, cr.CudaError) {
|
|
dp, err := cr.Malloc(uint(size))
|
|
d.inner = dp
|
|
d.capacity = size
|
|
d.length = size / sizeOfElement
|
|
return *d, err
|
|
}
|
|
|
|
func (d *DeviceSlice) MallocAsync(size, sizeOfElement int, stream cr.CudaStream) (DeviceSlice, cr.CudaError) {
|
|
dp, err := cr.MallocAsync(uint(size), stream)
|
|
d.inner = dp
|
|
d.capacity = size
|
|
d.length = size / sizeOfElement
|
|
return *d, err
|
|
}
|
|
|
|
func (d *DeviceSlice) Free() cr.CudaError {
|
|
d.CheckDevice()
|
|
err := cr.Free(d.inner)
|
|
if err == cr.CudaSuccess {
|
|
d.length, d.capacity = 0, 0
|
|
d.inner = nil
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (d *DeviceSlice) FreeAsync(stream cr.Stream) cr.CudaError {
|
|
d.CheckDevice()
|
|
err := cr.FreeAsync(d.inner, stream)
|
|
if err == cr.CudaSuccess {
|
|
d.length, d.capacity = 0, 0
|
|
d.inner = nil
|
|
}
|
|
return err
|
|
}
|
|
|
|
type HostSlice[T any] []T
|
|
|
|
func HostSliceFromElements[T any](elements []T) HostSlice[T] {
|
|
return elements
|
|
}
|
|
|
|
func HostSliceWithValue[T any](underlyingValue T, size int) HostSlice[T] {
|
|
slice := make(HostSlice[T], size)
|
|
for i := range slice {
|
|
slice[i] = underlyingValue
|
|
}
|
|
|
|
return slice
|
|
}
|
|
|
|
func (h HostSlice[T]) Len() int {
|
|
return len(h)
|
|
}
|
|
|
|
func (h HostSlice[T]) Cap() int {
|
|
return cap(h)
|
|
}
|
|
|
|
func (h HostSlice[T]) IsEmpty() bool {
|
|
return len(h) == 0
|
|
}
|
|
|
|
func (h HostSlice[T]) IsOnDevice() bool {
|
|
return false
|
|
}
|
|
|
|
func (h HostSlice[T]) SizeOfElement() int {
|
|
return int(unsafe.Sizeof(h[0]))
|
|
}
|
|
|
|
func (h HostSlice[T]) AsPointer() *T {
|
|
return &h[0]
|
|
}
|
|
|
|
func (h HostSlice[T]) AsUnsafePointer() unsafe.Pointer {
|
|
return unsafe.Pointer(&h[0])
|
|
}
|
|
|
|
func (h HostSlice[T]) CopyToDevice(dst *DeviceSlice, shouldAllocate bool) *DeviceSlice {
|
|
size := h.Len() * h.SizeOfElement()
|
|
if shouldAllocate {
|
|
dst.Malloc(size, h.SizeOfElement())
|
|
}
|
|
dst.CheckDevice()
|
|
if size > dst.Cap() {
|
|
panic("Number of bytes to copy is too large for destination")
|
|
}
|
|
|
|
cr.CopyToDevice(dst.inner, h.AsUnsafePointer(), uint(size))
|
|
dst.length = h.Len()
|
|
return dst
|
|
}
|
|
|
|
func (h HostSlice[T]) CopyToDeviceAsync(dst *DeviceSlice, stream cr.CudaStream, shouldAllocate bool) *DeviceSlice {
|
|
size := h.Len() * h.SizeOfElement()
|
|
if shouldAllocate {
|
|
dst.MallocAsync(size, h.SizeOfElement(), stream)
|
|
}
|
|
dst.CheckDevice()
|
|
if size > dst.Cap() {
|
|
panic("Number of bytes to copy is too large for destination")
|
|
}
|
|
|
|
cr.CopyToDeviceAsync(dst.inner, h.AsUnsafePointer(), uint(size), stream)
|
|
dst.length = h.Len()
|
|
return dst
|
|
}
|
|
|
|
func (h HostSlice[T]) CopyFromDevice(src *DeviceSlice) {
|
|
src.CheckDevice()
|
|
if h.Len() != src.Len() {
|
|
panic("destination and source slices have different lengths")
|
|
}
|
|
bytesSize := src.Len() * h.SizeOfElement()
|
|
cr.CopyFromDevice(h.AsUnsafePointer(), src.inner, uint(bytesSize))
|
|
}
|
|
|
|
func (h HostSlice[T]) CopyFromDeviceAsync(src *DeviceSlice, stream cr.Stream) {
|
|
src.CheckDevice()
|
|
if h.Len() != src.Len() {
|
|
panic("destination and source slices have different lengths")
|
|
}
|
|
bytesSize := src.Len() * h.SizeOfElement()
|
|
cr.CopyFromDeviceAsync(h.AsUnsafePointer(), src.inner, uint(bytesSize), stream)
|
|
}
|