update more efficent way to get slice from cgo
This commit is contained in:
parent
d6b7d8b9df
commit
8fdaae31c6
|
@ -7,8 +7,6 @@ package paddle
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
@ -34,25 +32,48 @@ var types = []struct {
|
||||||
{reflect.TypeOf(uint8(0)), UINT8},
|
{reflect.TypeOf(uint8(0)), UINT8},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TypeOfShape(dtype PaddleDType, shape []int32) reflect.Type {
|
func typeOfDataType(dtype PaddleDType) reflect.Type {
|
||||||
var ret reflect.Type
|
var ret reflect.Type
|
||||||
for _, t := range types {
|
for _, t := range types {
|
||||||
if dtype == PaddleDType(t.dtype) {
|
if t.dtype == dtype {
|
||||||
ret = t.gotype
|
ret = t.gotype
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ret == nil {
|
|
||||||
panic(bug("Data %v type is not support", dtype))
|
|
||||||
}
|
|
||||||
|
|
||||||
for range shape {
|
|
||||||
ret = reflect.SliceOf(ret)
|
|
||||||
}
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sizeofDataType(dtype PaddleDType) int32 {
|
||||||
|
switch dtype {
|
||||||
|
case UINT8:
|
||||||
|
return int32(C.sizeof_uchar)
|
||||||
|
case INT32:
|
||||||
|
return int32(C.sizeof_int)
|
||||||
|
case INT64:
|
||||||
|
return int32(C.sizeof_longlong)
|
||||||
|
case FLOAT32:
|
||||||
|
return int32(C.sizeof_float)
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func shapeAndTypeOf(val reflect.Value) (shape []int32, dt PaddleDType) {
|
||||||
|
gotype := val.Type()
|
||||||
|
for gotype.Kind() == reflect.Array || gotype.Kind() == reflect.Slice {
|
||||||
|
shape = append(shape, int32(val.Len()))
|
||||||
|
if val.Len() > 0 {
|
||||||
|
val = val.Index(0)
|
||||||
|
}
|
||||||
|
gotype = gotype.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, t := range types {
|
||||||
|
if gotype.Kind() == t.gotype.Kind() {
|
||||||
|
return shape, PaddleDType(t.dtype)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return shape, dt
|
||||||
|
}
|
||||||
|
|
||||||
type ZeroCopyTensor struct {
|
type ZeroCopyTensor struct {
|
||||||
c *C.PD_ZeroCopyTensor
|
c *C.PD_ZeroCopyTensor
|
||||||
name string
|
name string
|
||||||
|
@ -82,8 +103,6 @@ func (tensor *ZeroCopyTensor) Name() string {
|
||||||
func (tensor *ZeroCopyTensor) Rename(name string) {
|
func (tensor *ZeroCopyTensor) Rename(name string) {
|
||||||
tensor.name = name
|
tensor.name = name
|
||||||
tensor.c.name = (*C.char)(unsafe.Pointer(tensor.c.name))
|
tensor.c.name = (*C.char)(unsafe.Pointer(tensor.c.name))
|
||||||
//tensor.c.name = C.CString(tensor.name)
|
|
||||||
//defer C.free(unsafe.Pointer(tensor.c.name))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tensor *ZeroCopyTensor) Reshape(shape []int32) {
|
func (tensor *ZeroCopyTensor) Reshape(shape []int32) {
|
||||||
|
@ -107,9 +126,9 @@ func (tensor *ZeroCopyTensor) DataType() PaddleDType {
|
||||||
|
|
||||||
func (tensor *ZeroCopyTensor) SetValue(value interface{}) {
|
func (tensor *ZeroCopyTensor) SetValue(value interface{}) {
|
||||||
val := reflect.ValueOf(value)
|
val := reflect.ValueOf(value)
|
||||||
shape, dtype := ShapeAndTypeOf(val)
|
shape, dtype := shapeAndTypeOf(val)
|
||||||
num := numel(shape)
|
num := numel(shape)
|
||||||
length := C.size_t(SizeofDataType(dtype) * num)
|
length := C.size_t(sizeofDataType(dtype) * num)
|
||||||
if tensor.c.data.capacity < length {
|
if tensor.c.data.capacity < length {
|
||||||
if tensor.c.data.capacity != C.size_t(0) {
|
if tensor.c.data.capacity != C.size_t(0) {
|
||||||
C.free(tensor.c.data.data)
|
C.free(tensor.c.data.data)
|
||||||
|
@ -136,35 +155,89 @@ func (tensor *ZeroCopyTensor) SetValue(value interface{}) {
|
||||||
tensor.c.dtype = C.PD_DataType(dtype)
|
tensor.c.dtype = C.PD_DataType(dtype)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TypeOf(dtype PaddleDType, shape []int32) reflect.Type {
|
func (tensor *ZeroCopyTensor) tensorData() []byte {
|
||||||
var ret reflect.Type
|
cbytes := tensor.c.data.data
|
||||||
for _, t := range types {
|
|
||||||
if t.dtype == dtype {
|
|
||||||
ret = t.gotype
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for range shape {
|
|
||||||
ret = reflect.SliceOf(ret)
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tensor *ZeroCopyTensor) Value() interface{} {
|
|
||||||
t := TypeOf(PaddleDType(tensor.c.dtype), tensor.shape)
|
|
||||||
value := reflect.New(t)
|
|
||||||
c_bytes := tensor.c.data.data
|
|
||||||
length := tensor.c.data.length
|
length := tensor.c.data.length
|
||||||
var slice []byte
|
var slice []byte
|
||||||
if unsafe.Sizeof(unsafe.Pointer(nil)) == 8 {
|
if unsafe.Sizeof(unsafe.Pointer(nil)) == 8 {
|
||||||
slice = (*[1<<50 - 1]byte)(unsafe.Pointer(c_bytes))[:length:length]
|
slice = (*[1<<50 - 1]byte)(unsafe.Pointer(cbytes))[:length:length]
|
||||||
} else {
|
} else {
|
||||||
slice = (*[1 << 30]byte)(unsafe.Pointer(c_bytes))[:length:length]
|
slice = (*[1 << 30]byte)(unsafe.Pointer(cbytes))[:length:length]
|
||||||
}
|
}
|
||||||
r := bytes.NewReader(slice)
|
return slice
|
||||||
DecodeTensor(r, tensor.Shape(), t, value)
|
}
|
||||||
return reflect.Indirect(value).Interface()
|
|
||||||
|
func (tensor *ZeroCopyTensor) Value() interface{} {
|
||||||
|
t := typeOfDataType(PaddleDType(tensor.c.dtype))
|
||||||
|
data := tensor.tensorData()
|
||||||
|
return decodeTensor(data, tensor.Shape(), t).Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// It isn't safe to use reflect.SliceHeader as it uses a uintptr for Data and
|
||||||
|
// this is not inspected by the garbage collector
|
||||||
|
type sliceHeader struct {
|
||||||
|
Data unsafe.Pointer
|
||||||
|
Len int
|
||||||
|
Cap int
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeTensor(raw []byte, shape []int32, t reflect.Type) reflect.Value {
|
||||||
|
// Create a 1-dimensional slice of the base large enough for the data and
|
||||||
|
// copy the data in.
|
||||||
|
n := int(numel(shape))
|
||||||
|
|
||||||
|
l := n * int(t.Size())
|
||||||
|
typ := reflect.SliceOf(t)
|
||||||
|
slice := reflect.MakeSlice(typ, n, n)
|
||||||
|
baseBytes := *(*[]byte)(unsafe.Pointer(&sliceHeader{
|
||||||
|
Data: unsafe.Pointer(slice.Pointer()),
|
||||||
|
Len: l,
|
||||||
|
Cap: l,
|
||||||
|
}))
|
||||||
|
copy(baseBytes, raw)
|
||||||
|
|
||||||
|
if len(shape) == 0 {
|
||||||
|
// for n
|
||||||
|
return slice.Index(0)
|
||||||
|
}
|
||||||
|
if len(shape) == 1 {
|
||||||
|
// for {}
|
||||||
|
return slice
|
||||||
|
}
|
||||||
|
// for {{} {}} {{} {}} {{} {}}
|
||||||
|
if n == 0 {
|
||||||
|
n = int(numel(shape[:len(shape)-1]))
|
||||||
|
}
|
||||||
|
for i := len(shape) - 2; i >= 0; i-- {
|
||||||
|
underlyingSize := typ.Elem().Size()
|
||||||
|
typ = reflect.SliceOf(typ)
|
||||||
|
subsliceLen := int(shape[i+1])
|
||||||
|
if subsliceLen != 0 {
|
||||||
|
n = n / subsliceLen
|
||||||
|
}
|
||||||
|
data := unsafe.Pointer(slice.Pointer())
|
||||||
|
nextSlice := reflect.MakeSlice(typ, n, n)
|
||||||
|
|
||||||
|
for j := 0; j < n; j++ {
|
||||||
|
// This is equivalent to nSlice[j] = slice[j*subsliceLen: (j+1)*subsliceLen]
|
||||||
|
setSliceInSlice(nextSlice, j, sliceHeader{
|
||||||
|
Data: unsafe.Pointer(uintptr(data) + (uintptr(j*subsliceLen) * underlyingSize)),
|
||||||
|
Len: subsliceLen,
|
||||||
|
Cap: subsliceLen,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
slice = nextSlice
|
||||||
|
}
|
||||||
|
return slice
|
||||||
|
}
|
||||||
|
|
||||||
|
// setSliceInSlice sets slice[index] = content.
|
||||||
|
func setSliceInSlice(slice reflect.Value, index int, content sliceHeader) {
|
||||||
|
const sliceSize = unsafe.Sizeof(sliceHeader{})
|
||||||
|
// We must cast slice.Pointer to uninptr & back again to avoid GC issues.
|
||||||
|
// See https://github.com/google/go-cmp/issues/167#issuecomment-546093202
|
||||||
|
*(*sliceHeader)(unsafe.Pointer(uintptr(unsafe.Pointer(slice.Pointer())) + (uintptr(index) * sliceSize))) = content
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tensor *ZeroCopyTensor) Lod() []uint {
|
func (tensor *ZeroCopyTensor) Lod() []uint {
|
||||||
|
@ -175,73 +248,3 @@ func (tensor *ZeroCopyTensor) Lod() []uint {
|
||||||
valHdr.Cap = int(tensor.c.lod.length / C.sizeof_size_t)
|
valHdr.Cap = int(tensor.c.lod.length / C.sizeof_size_t)
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
func Endian() binary.ByteOrder {
|
|
||||||
buf := [2]byte{}
|
|
||||||
*(*uint16)(unsafe.Pointer(&buf[0])) = uint16(0xABCD)
|
|
||||||
|
|
||||||
var endian binary.ByteOrder
|
|
||||||
|
|
||||||
switch buf {
|
|
||||||
case [2]byte{0xCD, 0xAB}:
|
|
||||||
endian = binary.LittleEndian
|
|
||||||
case [2]byte{0xAB, 0xCD}:
|
|
||||||
endian = binary.BigEndian
|
|
||||||
default:
|
|
||||||
panic("Could not determine native endianness.")
|
|
||||||
}
|
|
||||||
return endian
|
|
||||||
}
|
|
||||||
|
|
||||||
func DecodeTensor(r *bytes.Reader, shape []int32, t reflect.Type, ptr reflect.Value) {
|
|
||||||
switch t.Kind() {
|
|
||||||
case reflect.Uint8, reflect.Int32, reflect.Int64, reflect.Float32:
|
|
||||||
binary.Read(r, Endian(), ptr.Interface())
|
|
||||||
case reflect.Slice:
|
|
||||||
value := reflect.Indirect(ptr)
|
|
||||||
value.Set(reflect.MakeSlice(t, int(shape[0]), int(shape[0])))
|
|
||||||
if len(shape) == 1 && value.Len() > 0 {
|
|
||||||
switch value.Index(0).Kind() {
|
|
||||||
case reflect.Uint8, reflect.Int32, reflect.Int64, reflect.Float32:
|
|
||||||
binary.Read(r, Endian(), value.Interface())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < value.Len(); i++ {
|
|
||||||
DecodeTensor(r, shape[1:], t.Elem(), value.Index(i).Addr())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func SizeofDataType(dtype PaddleDType) int32 {
|
|
||||||
switch dtype {
|
|
||||||
case UINT8:
|
|
||||||
return int32(C.sizeof_uchar)
|
|
||||||
case INT32:
|
|
||||||
return int32(C.sizeof_int)
|
|
||||||
case INT64:
|
|
||||||
return int32(C.sizeof_longlong)
|
|
||||||
case FLOAT32:
|
|
||||||
return int32(C.sizeof_float)
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
func ShapeAndTypeOf(val reflect.Value) (shape []int32, dt PaddleDType) {
|
|
||||||
gotype := val.Type()
|
|
||||||
for gotype.Kind() == reflect.Array || gotype.Kind() == reflect.Slice {
|
|
||||||
shape = append(shape, int32(val.Len()))
|
|
||||||
if val.Len() > 0 {
|
|
||||||
val = val.Index(0)
|
|
||||||
}
|
|
||||||
gotype = gotype.Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, t := range types {
|
|
||||||
if gotype.Kind() == t.gotype.Kind() {
|
|
||||||
return shape, PaddleDType(t.dtype)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return shape, dt
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue