Skip to content

Commit

Permalink
Auto merge of #58 - ReconfigureIO:feature/reader-writer-for-memory, r…
Browse files Browse the repository at this point in the history
…=patrickt

Add Reader & Writer objects for Memory.

None
  • Loading branch information
reconfig-bot authored Mar 9, 2017
2 parents 6511d3e + b49c135 commit 1302b4d
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 21 deletions.
6 changes: 1 addition & 5 deletions examples/addition/cmd/test-addition/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"bytes"
"encoding/binary"
"fmt"
"os"
Expand All @@ -24,11 +23,8 @@ func main() {

krnl.Run(1, 1, 1)

resp := make([]byte, 4)
buff.Read(resp)

var ret uint32
err := binary.Read(bytes.NewReader(resp), binary.LittleEndian, &ret)
err := binary.Read(buff.Reader(), binary.LittleEndian, &ret)
if err != nil {
fmt.Println("binary.Read failed:", err)
}
Expand Down
15 changes: 4 additions & 11 deletions examples/histogram/cmd/test-histogram/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"bytes"
"encoding/binary"
"fmt"
"log"
Expand Down Expand Up @@ -30,18 +29,14 @@ func main() {
input[i] = uint32(uint16(rand.Uint32()))
}

inputByteLength := uint(4 * len(input))

buff := world.Malloc(xcl.ReadOnly, inputByteLength)
buff := world.Malloc(xcl.ReadOnly, uint(binary.Size(input)))
defer buff.Free()

resp := make([]byte, 4*HISTOGRAM_WIDTH)
outputBuff := world.Malloc(xcl.ReadWrite, uint(len(resp)))
outputBuff := world.Malloc(xcl.ReadWrite, uint(binary.Size(resp)))
defer outputBuff.Free()

inputBuff := new(bytes.Buffer)
binary.Write(inputBuff, binary.LittleEndian, &input)
buff.Write(inputBuff.Bytes())
binary.Write(buff.Writer(), binary.LittleEndian, &input)

outputBuff.Write(resp)

Expand All @@ -51,10 +46,8 @@ func main() {

krnl.Run(1, 1, 1)

outputBuff.Read(resp)

var ret [512]uint32
err := binary.Read(bytes.NewReader(resp), binary.LittleEndian, &ret)
err := binary.Read(outputBuff.Reader(), binary.LittleEndian, &ret)
if err != nil {
log.Fatal("binary.Read failed:", err)
}
Expand Down
117 changes: 112 additions & 5 deletions go/src/xcl/xcl.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ package xcl
import "C"

import (
"errors"
"fmt"
"io"
"log"
"unsafe"
)

Expand All @@ -29,9 +33,22 @@ type Kernel struct {

type Memory struct {
world *World
size uint
mem C.cl_mem
}

type MemoryWriter struct {
left uint
offset uint
memory *Memory
}

type MemoryReader struct {
left uint
offset uint
memory *Memory
}

const (
ReadOnly = iota
WriteOnly
Expand Down Expand Up @@ -71,21 +88,111 @@ func (world *World) Malloc(flags uint, size uint) *Memory {
f = C.CL_MEM_READ_WRITE
}
m := C.xcl_malloc(C.xcl_world(*world), f, C.size_t(size))
return &Memory{world, m}
return &Memory{world, size, m}
}

func (mem *Memory) Free() {
C.clReleaseMemObject(mem.mem)
}

func (mem *Memory) Write(bytes []byte) {
p := C.CBytes(bytes)
C.xcl_memcpy_to_device(C.xcl_world(*mem.world), mem.mem, p, C.size_t(len(bytes)))
func (mem *Memory) Writer() *MemoryWriter {
return &MemoryWriter{mem.size, 0, mem}
}

func ErrorCode(code C.cl_int) error {
switch code {
case C.CL_SUCCESS:
return nil
case C.CL_INVALID_COMMAND_QUEUE:
return errors.New("CL_INVALID_COMMAND_QUEUE")
case C.CL_INVALID_CONTEXT:
return errors.New("CL_INVALID_CONTEXT")
case C.CL_INVALID_MEM_OBJECT:
return errors.New("CL_INVALID_MEM_OBJECT")
case C.CL_INVALID_VALUE:
return errors.New("CL_INVALID_VALUE")
case C.CL_INVALID_EVENT_WAIT_LIST:
return errors.New("CL_INVALID_EVENT_WAIT_LIST")
case C.CL_MISALIGNED_SUB_BUFFER_OFFSET:
return errors.New("CL_MISALIGNED_SUB_BUFFER_OFFSET")
case C.CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST:
return errors.New("CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST")
case C.CL_MEM_OBJECT_ALLOCATION_FAILURE:
return errors.New("CL_MEM_OBJECT_ALLOCATION_FAILURE")
case C.CL_INVALID_OPERATION:
return errors.New("CL_INVALID_OPERATION")
case C.CL_OUT_OF_RESOURCES:
return errors.New("CL_OUT_OF_RESOURCES")
case C.CL_OUT_OF_HOST_MEMORY:
return errors.New("CL_OUT_OF_HOST_MEMORY")
default:
return fmt.Errorf("Unknown error code %d", code)
}
}

func (writer *MemoryWriter) Write(bytes []byte) (n int, err error) {
if writer.left == 0 {
return 0, io.ErrShortWrite
}
toWrite := uint(len(bytes))
if toWrite > writer.left {
toWrite = writer.left
}
// I think we can make this zero copy like in Read
p := C.CBytes(bytes[0:toWrite])

ret := C.clEnqueueWriteBuffer(
C.xcl_world(*writer.memory.world).command_queue,
writer.memory.mem,
C.CL_TRUE,
C.size_t(writer.offset), C.size_t(toWrite), p, C.cl_uint(0), nil, nil)

err = ErrorCode(ret)
C.free(p)
writer.left -= toWrite
writer.offset += toWrite
return int(toWrite), err
}

func (mem *Memory) Write(bytes []byte) {
_, err := mem.Writer().Write(bytes)
if err != nil {
log.Fatalf("Unhandled error in Write %v. Use the Writer interface to handle this\n", err)
}
}

func (mem *Memory) Reader() *MemoryReader {
return &MemoryReader{mem.size, 0, mem}
}

func (reader *MemoryReader) Read(bytes []byte) (n int, err error) {
if reader.left == 0 {
return 0, io.EOF
}
toRead := uint(len(bytes))
if toRead > reader.left {
toRead = reader.left
}

p := unsafe.Pointer(&bytes[0])

ret := C.clEnqueueReadBuffer(
C.xcl_world(*reader.memory.world).command_queue,
reader.memory.mem,
C.CL_TRUE,
C.size_t(reader.offset), C.size_t(toRead), p, C.cl_uint(0), nil, nil)

err = ErrorCode(ret)
reader.left -= toRead
reader.offset += toRead
return int(toRead), err
}

func (mem *Memory) Read(bytes []byte) {
C.xcl_memcpy_from_device(C.xcl_world(*mem.world), unsafe.Pointer(&bytes[0]), mem.mem, C.size_t(cap(bytes)))
_, err := mem.Reader().Read(bytes)
if err != nil && err != io.EOF {
log.Fatalf("Unhandled error in Read %v. Use the Reader interface to handle this\n", err)
}
}

func (kernel *Kernel) SetMemoryArg(index uint, mem *Memory) {
Expand Down

0 comments on commit 1302b4d

Please sign in to comment.