cgoutils/memory.go (122 lines of code) (raw):
// Copyright (c) 2017-2018 Uber Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cgoutils
// #cgo LDFLAGS: -L${SRCDIR}/../lib -lmem
// #include "string.h"
// #include "memory.h"
import "C"
import (
"reflect"
"unsafe"
)
// GetFlags return flags about the memory management.
func GetFlags() C.DeviceMemoryFlags {
return C.GetFlags()
}
func IsDeviceMemoryImplementation() bool {
return (GetFlags() & C.DEVICE_MEMORY_IMPLEMENTATION_FLAG) != 0
}
func IsPooledMemory() bool {
return (GetFlags() & C.POOLED_MEMORY_FLAG) != 0
}
func SupportHashReduction() bool {
return (GetFlags() & C.HASH_REDUCTION_SUPPORT) != 0
}
// HostAlloc allocates memory in C.
func HostAlloc(bytes int) unsafe.Pointer {
return unsafe.Pointer(doCGoCall(func() C.CGoCallResHandle {
return C.HostAlloc(C.size_t(bytes))
}))
}
// HostFree frees memory allocated in C.
func HostFree(p unsafe.Pointer) {
doCGoCall(func() C.CGoCallResHandle {
return C.HostFree(p)
})
}
// HostMemCpy copies memory between two host addresses
func HostMemCpy(dst unsafe.Pointer, src unsafe.Pointer, bytes int) {
doCGoCall(func() C.CGoCallResHandle {
return C.HostMemCpy(dst, src, C.size_t(bytes))
})
}
// MakeSliceFromCPtr make a slice that points to data that cptr points to.
// cptr must be a c-allocated pointer as the garbage collector will not update
// that uintptr's value if the golang object movee.
func MakeSliceFromCPtr(cptr uintptr, length int) []byte {
h := reflect.SliceHeader{
Data: cptr,
Len: length,
Cap: length,
}
return *(*[]byte)(unsafe.Pointer(&h))
}
// CreateCudaStream creates a Cuda stream.
func CreateCudaStream(device int) unsafe.Pointer {
return unsafe.Pointer(doCGoCall(func() C.CGoCallResHandle {
return C.CreateCudaStream(C.int(device))
}))
}
// WaitForCudaStream block waits until all pending operations are finished on
// the specified Cuda stream.
func WaitForCudaStream(stream unsafe.Pointer, device int) {
if stream != nil {
doCGoCall(func() C.CGoCallResHandle {
return C.WaitForCudaStream(stream, C.int(device))
})
}
}
// DestroyCudaStream destroys the specified Cuda stream.
func DestroyCudaStream(stream unsafe.Pointer, device int) {
if stream != nil {
doCGoCall(func() C.CGoCallResHandle {
return C.DestroyCudaStream(stream, C.int(device))
})
}
}
// DeviceAllocate allocates the specified amount of memory on the device.
func DeviceAllocate(bytes, device int) unsafe.Pointer {
return unsafe.Pointer(doCGoCall(func() C.CGoCallResHandle {
return C.DeviceAllocate(C.size_t(bytes), C.int(device))
}))
}
// DeviceFree frees the specified memory from the device.
func DeviceFree(ptr unsafe.Pointer, device int) {
doCGoCall(func() C.CGoCallResHandle {
return C.DeviceFree(ptr, C.int(device))
})
}
// AsyncMemCopyFunc is a abstraction of DeviceToDevice, DeviceToHost, HostToDevice memcopy functions
type AsyncMemCopyFunc func(dst, src unsafe.Pointer, bytes int, stream unsafe.Pointer, device int)
// AsyncCopyHostToDevice asynchronously copies the host buffer to the device
// buffer on the specified stream.
func AsyncCopyHostToDevice(
dst, src unsafe.Pointer, bytes int, stream unsafe.Pointer, device int) {
doCGoCall(func() C.CGoCallResHandle {
return C.AsyncCopyHostToDevice(dst, src, C.size_t(bytes), stream, C.int(device))
})
}
// AsyncCopyDeviceToDevice asynchronously copies the src device buffer to the
// dst device buffer buffer on the specified stream.
func AsyncCopyDeviceToDevice(
dst, src unsafe.Pointer, bytes int, stream unsafe.Pointer, device int) {
doCGoCall(func() C.CGoCallResHandle {
return C.AsyncCopyDeviceToDevice(dst, src, C.size_t(bytes), stream, C.int(device))
})
}
// AsyncCopyDeviceToHost asynchronously copies the device buffer to the host
// buffer on the specified stream.
func AsyncCopyDeviceToHost(
dst, src unsafe.Pointer, bytes int, stream unsafe.Pointer, device int) {
doCGoCall(func() C.CGoCallResHandle {
return C.AsyncCopyDeviceToHost(dst, src, C.size_t(bytes), stream, C.int(device))
})
}
// GetDeviceCount returns the number of GPU devices
func GetDeviceCount() int {
return int(doCGoCall(func() C.CGoCallResHandle {
return C.GetDeviceCount()
}))
}
// GetDeviceGlobalMemoryInMB returns the total global memory(MB) for a given device
func GetDeviceGlobalMemoryInMB(device int) int {
return int(doCGoCall(func() C.CGoCallResHandle {
return C.GetDeviceGlobalMemoryInMB(C.int(device))
}))
}
// CudaProfilerStart starts/resumes the profiler.
func CudaProfilerStart() {
doCGoCall(func() C.CGoCallResHandle {
return C.CudaProfilerStart()
})
}
// CudaProfilerStop stops/pauses the profiler.
func CudaProfilerStop() {
doCGoCall(func() C.CGoCallResHandle {
return C.CudaProfilerStop()
})
}
// GetDeviceMemoryInfo returns information about total size and free size of device memory in bytes for a specfic
// device.
func GetDeviceMemoryInfo(device int) (int, int) {
var freeSize, totalSize C.size_t
doCGoCall(func() C.CGoCallResHandle {
return C.GetDeviceMemoryInfo(&freeSize, &totalSize, C.int(device))
})
return int(freeSize), int(totalSize)
}
// doCGoCall does the cgo call by converting CGoCallResHandle to C.int and *C.char and calls doCGoCall.
// The reason to have this wrapper is because CGo types are bound to package name, thereby even C.int are different types
// under different packages.
func doCGoCall(f func() C.CGoCallResHandle) uintptr {
return DoCGoCall(func() (uintptr, unsafe.Pointer) {
ret := f()
return uintptr(ret.res), unsafe.Pointer(ret.pStrErr)
})
}