Skip to content

Commit

Permalink
Improve device support
Browse files Browse the repository at this point in the history
  • Loading branch information
MasterOfBinary committed Dec 17, 2016
1 parent 6f38df9 commit 9f90cb0
Show file tree
Hide file tree
Showing 11 changed files with 187 additions and 97 deletions.
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,19 @@ To run it, make sure you have an SDK from Intel, NVIDIA, or AMD and a compatible
device. Then run with `go run main.go`:

```
Platform name: NVIDIA CUDA, number of devices: 1, version: 1.2
Platform name: AMD Accelerated Parallel Processing, number of devices: 1, version: 2.0
Platform name: Intel(R) OpenCL, number of devices: 1, version: 1.2
Platform name: Experimental OpenCL 2.1 CPU Only Platform, number of devices: 1, version: 2.1
PLATFORMS
=========
Name: NVIDIA CUDA, devices: 1, version: 1.2
Name: AMD Accelerated Parallel Processing, devices: 1, version: 2.0
Name: Intel(R) OpenCL, devices: 1, version: 1.2
Name: Experimental OpenCL 2.1 CPU Only Platform, devices: 1, version: 2.1
Output
USING
=====
Platform: NVIDIA CUDA
Vendor: NVIDIA Corporation
OUTPUT
======
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
```
77 changes: 59 additions & 18 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ package main
import (
"fmt"

"strings"

"github.com/MasterOfBinary/go-opencl/opencl"
)

const (
deviceType = opencl.DeviceTypeAll

dataSize = 128

programCode = `
Expand All @@ -18,50 +22,88 @@ kernel void kern(global float* out)
`
)

func printHeader(name string) {
fmt.Println(strings.ToUpper(name))
for _ = range name {
fmt.Print("=")
}
fmt.Println()
}

func printInfo(platform opencl.Platform, device opencl.Device) {
var platformName string
err := platform.GetInfo(opencl.PlatformName, &platformName)
if err != nil {
panic(err)
}

var vendor string
err = device.GetInfo(opencl.DeviceVendor, &vendor)
if err != nil {
panic(err)
}

fmt.Println()
printHeader("Using")
fmt.Println("Platform:", platformName)
fmt.Println("Vendor: ", vendor)
}

func main() {
platforms, err := opencl.GetPlatforms()
if err != nil {
panic(err)
}

var cpuDevice *opencl.Device
printHeader("Platforms")

foundDevice := false

var platform opencl.Platform
var device opencl.Device
var name string
for _, platform := range platforms {
err = platform.GetInfo(opencl.PlatformName, &name)
for _, curPlatform := range platforms {
err = curPlatform.GetInfo(opencl.PlatformName, &name)
if err != nil {
panic(err)
}

var devices []opencl.Device
devices, err = platform.GetDevices(opencl.DeviceTypeAll)
devices, err = curPlatform.GetDevices(deviceType)
if err != nil {
panic(err)
}

version := platform.GetVersion()

fmt.Printf("Platform name: %v, number of devices: %v, version: %v\n", name, len(devices), version)

// Use the first device
if len(devices) > 0 && cpuDevice == nil {
cpuDevice = &devices[0]
// Use the first available device
if len(devices) > 0 && !foundDevice {
var available bool
err = devices[0].GetInfo(opencl.DeviceAvailable, &available)
if err == nil && available {
platform = curPlatform
device = devices[0]
foundDevice = true
}
}

version := curPlatform.GetVersion()
fmt.Printf("Name: %v, devices: %v, version: %v\n", name, len(devices), version)
}

if cpuDevice == nil {
if !foundDevice {
panic("No device found")
}

var context *opencl.Context
context, err = cpuDevice.CreateContext()
printInfo(platform, device)

var context opencl.Context
context, err = device.CreateContext()
if err != nil {
panic(err)
}
defer context.Release()

var commandQueue *opencl.CommandQueue
commandQueue, err = context.CreateCommandQueue()
commandQueue, err = context.CreateCommandQueue(device)
if err != nil {
panic(err)
}
Expand All @@ -75,7 +117,7 @@ func main() {
defer program.Release()

var log string
err = program.Build(&log)
err = program.Build(device, &log)
if err != nil {
fmt.Println(log)
panic(err)
Expand Down Expand Up @@ -114,8 +156,7 @@ func main() {
}

fmt.Println()
fmt.Println("Output")
fmt.Println("======")
printHeader("Output")
for _, item := range data {
fmt.Printf("%v ", item)
}
Expand Down
2 changes: 1 addition & 1 deletion opencl/buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type Buffer struct {
buffer C.cl_mem
}

func createBuffer(context *Context, flags []MemFlags, size uint64) (*Buffer, error) {
func createBuffer(context Context, flags []MemFlags, size uint64) (*Buffer, error) {
// AND together all flags
flagBitField := uint64(0)
for _, flag := range flags {
Expand Down
7 changes: 3 additions & 4 deletions opencl/command_queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,21 @@ import (

type CommandQueue struct {
commandQueue C.cl_command_queue
context *Context
}

func createCommandQueue(context *Context) (*CommandQueue, error) {
func createCommandQueue(context Context, device Device) (*CommandQueue, error) {
var errInt clError
queue := C.clCreateCommandQueue(
context.context,
context.device.deviceID,
device.deviceID,
0,
(*C.cl_int)(&errInt),
)
if errInt != clSuccess {
return nil, clErrorToError(errInt)
}

return &CommandQueue{queue, context}, nil
return &CommandQueue{queue}, nil
}

func (c CommandQueue) EnqueueNDRangeKernel(kernel *Kernel, workDim uint32, globalWorkSize []uint64) error {
Expand Down
25 changes: 11 additions & 14 deletions opencl/context.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
package opencl

// #if __APPLE__
// #include <OpenCL/opencl.h>
// #else
// #include <CL/cl.h>
// #endif
// #include "opencl.h"
import "C"

type Context struct {
context C.cl_context
device Device
}

func createContext(device Device) (*Context, error) {
func createContext(device Device) (Context, error) {
var emptyContext Context

// TODO add more functionality. Super simple context creation right now
var errInt clError
ctx := C.clCreateContext(
Expand All @@ -24,24 +21,24 @@ func createContext(device Device) (*Context, error) {
(*C.cl_int)(&errInt),
)
if errInt != clSuccess {
return nil, clErrorToError(errInt)
return emptyContext, clErrorToError(errInt)
}

return &Context{ctx, device}, nil
return Context{ctx}, nil
}

func (c *Context) CreateCommandQueue() (*CommandQueue, error) {
return createCommandQueue(c)
func (c Context) CreateCommandQueue(device Device) (*CommandQueue, error) {
return createCommandQueue(c, device)
}

func (c *Context) CreateProgramWithSource(programCode string) (*Program, error) {
func (c Context) CreateProgramWithSource(programCode string) (*Program, error) {
return createProgramWithSource(c, programCode)
}

func (c *Context) CreateBuffer(memFlags []MemFlags, size uint64) (*Buffer, error) {
func (c Context) CreateBuffer(memFlags []MemFlags, size uint64) (*Buffer, error) {
return createBuffer(c, memFlags, size)
}

func (c *Context) Release() {
func (c Context) Release() {
C.clReleaseContext(c.context)
}
50 changes: 44 additions & 6 deletions opencl/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ const (
DeviceAvailable = DeviceInfo(C.CL_DEVICE_AVAILABLE)
DeviceBuiltInKernels = DeviceInfo(C.CL_DEVICE_BUILT_IN_KERNELS)
DeviceCompilerAvailable = DeviceInfo(C.CL_DEVICE_COMPILER_AVAILABLE)
DeviceInfoType = DeviceInfo(C.CL_DEVICE_TYPE)
DeviceVendor = DeviceInfo(C.CL_DEVICE_VENDOR)
DriverVersion = DeviceInfo(C.CL_DRIVER_VERSION)
)

var (
Expand All @@ -38,6 +41,9 @@ var (
DeviceAvailable: {false},
DeviceBuiltInKernels: {"", []string{}},
DeviceCompilerAvailable: {false},
DeviceInfoType: {DeviceTypeDefault},
DeviceVendor: {""},
DriverVersion: {"", MajorMinor{}},
}
)

Expand All @@ -49,7 +55,13 @@ type Device struct {
// getDevices returns a slice of devices of type deviceType for platform.
func getDevices(platform Platform, deviceType DeviceType) ([]Device, error) {
var deviceCount C.cl_uint = C.cl_uint(0)
errInt := clError(C.clGetDeviceIDs(platform.platformID, C.cl_device_type(deviceType), 0, nil, &deviceCount))
errInt := clError(C.clGetDeviceIDs(
platform.platformID,
C.cl_device_type(deviceType),
0,
nil,
&deviceCount,
))
if errInt != clSuccess {
if errInt == clDeviceNotFound {
return []Device{}, nil
Expand Down Expand Up @@ -82,17 +94,19 @@ func getDevices(platform Platform, deviceType DeviceType) ([]Device, error) {

// CreateContext creates and returns an OpenCL context for a device. After use the
// context must be released.
func (d Device) CreateContext() (*Context, error) {
func (d Device) CreateContext() (Context, error) {
return createContext(d)
}

// GetInfo retrieves the information specified by name and stores it in output.
// The output must correspond to the return type for that type of info:
//
// DeviceAddressBits *bool
// DeviceAvailable *bool
// DeviceBuiltInKernels *string or *[]string
// DeviceAddressBits *bool
// DeviceAvailable *bool
// DeviceBuiltInKernels *string or *[]string
// DeviceCompilerAvailable *bool
// DeviceInfoType *DeviceType
// DriverVersion *string or *MajorMinor
//
// Note that if DeviceBuiltInKernels is retrieved with output being a *string,
// the extensions will be a semicolon-separated list as specified by the OpenCL
Expand Down Expand Up @@ -136,8 +150,21 @@ func (d Device) GetInfo(name DeviceInfo, output interface{}) error {
*t = elems
}

case *uint32, *bool:
case *uint32, *bool, *DeviceType:
return d.getInfoNum(name, output)

case *MajorMinor:
if err := d.getInfoStr(name, &outputString); err != nil {
return err
}
if name == DriverVersion {
ver, err := ParseMajorMinor(outputString)
if err != nil {
return err
}

*t = ver
}
}

return nil
Expand Down Expand Up @@ -170,6 +197,17 @@ func (d Device) getInfoNum(name DeviceInfo, output interface{}) error {
))
*t = u == C.CL_TRUE

case *DeviceType:
var u C.cl_device_type
errInt = clError(C.clGetDeviceInfo(
d.deviceID,
C.cl_device_info(name),
C.sizeof_cl_device_type,
unsafe.Pointer(&u),
nil,
))
*t = DeviceType(u)

}

if errInt != clSuccess {
Expand Down
2 changes: 1 addition & 1 deletion opencl/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ var (
OutOfHostMemory = errors.New("Out of host memory")

UnexpectedType = errors.New("Unexpected type")
ErrorParsingVersion = errors.New("Error parsing OpenCL version")
ErrorParsingVersion = errors.New("Error parsing version")
UnknownError = errors.New("Unknown error")
)

Expand Down
Loading

0 comments on commit 9f90cb0

Please sign in to comment.