提交 8fdaae31 编写于 作者: L LKKlein

update more efficent way to get slice from cgo

上级 d6b7d8b9
...@@ -7,8 +7,6 @@ package paddle ...@@ -7,8 +7,6 @@ package paddle
import "C" import "C"
import ( import (
"bytes"
"encoding/binary"
"reflect" "reflect"
"runtime" "runtime"
"unsafe" "unsafe"
...@@ -34,23 +32,46 @@ var types = []struct { ...@@ -34,23 +32,46 @@ 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
} }
} }
return ret
}
if ret == nil { func sizeofDataType(dtype PaddleDType) int32 {
panic(bug("Data %v type is not support", dtype)) 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
}
for range shape { func shapeAndTypeOf(val reflect.Value) (shape []int32, dt PaddleDType) {
ret = reflect.SliceOf(ret) 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)
} }
return ret 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 {
...@@ -82,8 +103,6 @@ func (tensor *ZeroCopyTensor) 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 { ...@@ -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,112 +155,96 @@ func (tensor *ZeroCopyTensor) SetValue(value interface{}) { ...@@ -136,112 +155,96 @@ 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) Lod() []uint { func (tensor *ZeroCopyTensor) Value() interface{} {
var val []uint t := typeOfDataType(PaddleDType(tensor.c.dtype))
valHdr := (*reflect.SliceHeader)(unsafe.Pointer(&val)) data := tensor.tensorData()
valHdr.Data = uintptr(unsafe.Pointer(tensor.c.lod.data)) return decodeTensor(data, tensor.Shape(), t).Interface()
valHdr.Len = int(tensor.c.lod.length / C.sizeof_size_t)
valHdr.Cap = int(tensor.c.lod.length / C.sizeof_size_t)
return val
} }
func Endian() binary.ByteOrder { // It isn't safe to use reflect.SliceHeader as it uses a uintptr for Data and
buf := [2]byte{} // this is not inspected by the garbage collector
*(*uint16)(unsafe.Pointer(&buf[0])) = uint16(0xABCD) type sliceHeader struct {
Data unsafe.Pointer
Len int
Cap int
}
var endian binary.ByteOrder 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))
switch buf { l := n * int(t.Size())
case [2]byte{0xCD, 0xAB}: typ := reflect.SliceOf(t)
endian = binary.LittleEndian slice := reflect.MakeSlice(typ, n, n)
case [2]byte{0xAB, 0xCD}: baseBytes := *(*[]byte)(unsafe.Pointer(&sliceHeader{
endian = binary.BigEndian Data: unsafe.Pointer(slice.Pointer()),
default: Len: l,
panic("Could not determine native endianness.") Cap: l,
} }))
return endian copy(baseBytes, raw)
}
func DecodeTensor(r *bytes.Reader, shape []int32, t reflect.Type, ptr reflect.Value) { if len(shape) == 0 {
switch t.Kind() { // for n
case reflect.Uint8, reflect.Int32, reflect.Int64, reflect.Float32: return slice.Index(0)
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
} }
if len(shape) == 1 {
// for {}
return slice
} }
// for {{} {}} {{} {}} {{} {}}
for i := 0; i < value.Len(); i++ { if n == 0 {
DecodeTensor(r, shape[1:], t.Elem(), value.Index(i).Addr()) 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)
func SizeofDataType(dtype PaddleDType) int32 { for j := 0; j < n; j++ {
switch dtype { // This is equivalent to nSlice[j] = slice[j*subsliceLen: (j+1)*subsliceLen]
case UINT8: setSliceInSlice(nextSlice, j, sliceHeader{
return int32(C.sizeof_uchar) Data: unsafe.Pointer(uintptr(data) + (uintptr(j*subsliceLen) * underlyingSize)),
case INT32: Len: subsliceLen,
return int32(C.sizeof_int) Cap: subsliceLen,
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) { slice = nextSlice
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()
} }
return slice
}
for _, t := range types { // setSliceInSlice sets slice[index] = content.
if gotype.Kind() == t.gotype.Kind() { func setSliceInSlice(slice reflect.Value, index int, content sliceHeader) {
return shape, PaddleDType(t.dtype) 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
return shape, dt *(*sliceHeader)(unsafe.Pointer(uintptr(unsafe.Pointer(slice.Pointer())) + (uintptr(index) * sliceSize))) = content
}
func (tensor *ZeroCopyTensor) Lod() []uint {
var val []uint
valHdr := (*reflect.SliceHeader)(unsafe.Pointer(&val))
valHdr.Data = uintptr(unsafe.Pointer(tensor.c.lod.data))
valHdr.Len = int(tensor.c.lod.length / C.sizeof_size_t)
valHdr.Cap = int(tensor.c.lod.length / C.sizeof_size_t)
return val
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册