Last active
February 2, 2017 16:04
-
-
Save IceflowRE/c50a57258a6a6058f0e83e68dc6fcb42 to your computer and use it in GitHub Desktop.
Small OpenCL 2.0 code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# just in case you are interested in getting the cl2.hpp | |
# i build it on linux but at least you can use the headers on windows too | |
# https://github.com/KhronosGroup/OpenCL-CLHPP | |
sudo apt-get install wget cmake make gcc doxygen ruby ruby-bundler python | |
#pacman -S wget cmake make gcc doxygen ruby ruby-bundler python | |
git clone https://github.com/KhronosGroup/OpenCL-Headers.git ./OpenCL-Headers | |
cd OpenCL-Headers | |
git pull | |
cd .. | |
git clone https://github.com/KhronosGroup/OpenCL-CLHPP.git ./hppSrc -b opencl21 --single-branch | |
cd hppSrc | |
git pull | |
cd .. | |
git clone --recursive https://github.com/throwtheswitch/cmock.git ./cmock | |
cd cmock | |
git pull | |
cd .. | |
git clone https://github.com/ThrowTheSwitch/Unity.git ./UnityTests | |
cd UnityTests | |
git pull | |
cd .. | |
cd cmock | |
bundle install # Ensures you have all RubyGems needed | |
bundle exec rake # Run all CMock library tests | |
cd .. | |
cd hppSrc | |
mkdir build | |
cd build | |
cmake -DUNITY_DIR=./UnityTests/ -DCMOCK_DIR=./cmock/ -DOPENCL_DIST_DIR=./OpenCL-Headers/ .. | |
make | |
tests/test_clhpp | |
tests/test_clhpp_cxx11 | |
tests/test_clhpp_deprecated_1_1 | |
make docs | |
cd .. | |
cd .. | |
mkdir include | |
cd include | |
mkdir CL | |
cd .. | |
cp hppSrc/build/include/CL/* include/CL/ | |
cp OpenCL-Headers/* include/CL/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void kernel simple_add(global const int* A, global const int* B, global int* C) { | |
C[get_global_id(0)] = A[get_global_id(0)] + B[get_global_id(0)]; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Author: Iceflower S | |
Adapted from: | |
https://github.com/KhronosGroup/OpenCL-CLHPP | |
http://simpleopencl.blogspot.de/2013/06/tutorial-simple-start-with-opencl-and-c.html | |
http://enja.org/2010/07/20/adventures-in-opencl-part-1-5-cpp-bindings/ | |
*/ | |
#define CL_HPP_ENABLE_EXCEPTIONS | |
#define CL_HPP_TARGET_OPENCL_VERSION 200 | |
#include <CL/cl2.hpp> | |
#include <iostream> | |
#include <fstream> | |
#include <exception> | |
#include <string> | |
#include <vector> | |
void printDeviceInfo(cl::Device& device) { | |
std::cout << "----------------DEVICE----------------" << std::endl; | |
std::cout << "Type: "; | |
if (device.getInfo<CL_DEVICE_TYPE>() & CL_DEVICE_TYPE_CPU) std::cout << "CPU"; | |
if (device.getInfo<CL_DEVICE_TYPE>() & CL_DEVICE_TYPE_GPU) std::cout << "GPU"; | |
if (device.getInfo<CL_DEVICE_TYPE>() & CL_DEVICE_TYPE_ACCELERATOR) std::cout << "Acclerator"; | |
if (device.getInfo<CL_DEVICE_TYPE>() & CL_DEVICE_TYPE_DEFAULT) std::cout << "Default"; | |
if (device.getInfo<CL_DEVICE_TYPE>() & CL_DEVICE_TYPE_CUSTOM) std::cout << "Custom"; | |
std::cout << std::endl; | |
std::cout << "Name: " << device.getInfo<CL_DEVICE_NAME>() << std::endl; | |
std::cout << "Vendor: " << device.getInfo<CL_DEVICE_VENDOR>() << std::endl; | |
std::cout << "Driver version: " << device.getInfo<CL_DRIVER_VERSION>() << std::endl; | |
std::cout << "Profile: " << device.getInfo<CL_DEVICE_PROFILE>() << std::endl; | |
std::cout << "Device version: " << device.getInfo<CL_DEVICE_VERSION>() << std::endl; | |
std::cout << "Open CL version: " << device.getInfo<CL_DEVICE_OPENCL_C_VERSION>() << std::endl; | |
std::cout << "Max compute units: " << device.getInfo<CL_DEVICE_MAX_COMPUTE_UNITS>() << std::endl; | |
std::cout << "--------------------------------------" << std::endl; | |
} | |
void printOpenClInfo() { | |
try { | |
std::vector<cl::Platform> platforms; | |
(void) cl::Platform::get(&platforms); | |
std::cout << "Number of platforms: " << platforms.size() << "\n"; | |
// dump platform information | |
for (auto platform : platforms) { | |
std::cout << "================PLATFORM===============" << std::endl; | |
std::cout << "Version: " << platform.getInfo<CL_PLATFORM_VERSION>() << "\n"; | |
std::cout << "Name: " << platform.getInfo<CL_PLATFORM_NAME>() << "\n"; | |
std::cout << "Vendor: " << platform.getInfo<CL_PLATFORM_VENDOR>() << "\n"; | |
std::vector<cl::Device> devices; | |
(void) platform.getDevices(CL_DEVICE_TYPE_ALL, &devices); | |
std::cout << "--------------------------------------" << std::endl; | |
std::cout << "Number of devices: " << devices.size() << "\n"; | |
// dump device information | |
for (cl::Device device : devices) { | |
printDeviceInfo(device); | |
} | |
} | |
std::cout << "======================================" << std::endl; | |
} catch (cl::Error err) { | |
std::cerr << "ERROR: " << err.what() << "("; | |
switch (err.err()) { | |
case CL_INVALID_VALUE: std::cerr << "CL_INVALID_VALUE"; break; | |
case CL_INVALID_DEVICE_TYPE: std::cerr << "CL_INVALID_DEVICE_TYPE"; break; | |
case CL_DEVICE_NOT_FOUND: std::cerr << "CL_DEVICE_NOT_FOUND"; break; | |
default: std::cerr << err.err(); break; | |
} | |
std::cerr << ")\n"; | |
} | |
} | |
// return a pair with platform index, device index | |
std::pair<int, int> getDeviceId() { | |
try { | |
std::vector<cl::Platform> platforms; | |
cl::Platform::get(&platforms); | |
// loop through all platforms and check for a device which supports OpenCl 2.0 or higher | |
for (int i = 0; i < platforms.size(); i++) { | |
cl::Platform platform = platforms[i]; | |
std::vector<cl::Device> curDevices; | |
platform.getDevices(CL_DEVICE_TYPE_ALL, &curDevices); | |
for (int k = 0; k < curDevices.size(); k++) { | |
cl::Device curDevice = curDevices[k]; | |
int majorVer = curDevice.getInfo<CL_DEVICE_OPENCL_C_VERSION>().at(9) - 48; | |
int minorVer = curDevice.getInfo<CL_DEVICE_OPENCL_C_VERSION>().at(11) - 48; | |
if ((majorVer >= 2) && (minorVer >= 0)) { // check for OpenCl version | |
#if _DEBUG | |
printDeviceInfo(curDevice); | |
#endif | |
return std::pair<int, int>(i, k); | |
} | |
} | |
} | |
} catch (cl::Error err) { | |
std::cerr << "ERROR: " << err.what() << "("; | |
switch (err.err()) { | |
case CL_INVALID_VALUE: | |
std::cerr << "CL_INVALID_VALUE"; | |
break; | |
case CL_INVALID_DEVICE_TYPE: | |
std::cerr << "CL_INVALID_DEVICE_TYPE"; | |
break; | |
case CL_DEVICE_NOT_FOUND: | |
std::cerr << "CL_DEVICE_NOT_FOUND"; | |
break; | |
default: | |
std::cerr << err.err(); | |
break; | |
} | |
std::cerr << ")" << std::endl; | |
} | |
throw "No device found"; | |
} | |
int main() { | |
// printOpenClInfo(); | |
// get device which supports a specific OpenCl version | |
std::pair<int, int> clDeviceIndex(0, 0); | |
try { | |
clDeviceIndex = getDeviceId(); | |
} catch (std::exception e) { | |
std::cout << e.what() << std::endl; | |
} | |
// set device for calculating | |
std::cout << "|set OpenCL device| START" << std::endl; | |
std::vector<cl::Platform> platforms; | |
cl::Platform::get(&platforms); | |
std::vector<cl::Device> devices; | |
platforms[clDeviceIndex.first].getDevices(CL_DEVICE_TYPE_ALL, &devices); | |
cl::Device calcDevice = devices[clDeviceIndex.second]; | |
std::cout << "|set OpenCL device| DONE" << std::endl; | |
// load kernel content | |
std::cout << "|load kernel code| START" << std::endl; | |
std::ifstream inputFile; | |
inputFile.open("./kernel.cl", std::ifstream::in); | |
std::string kernelCode(std::istreambuf_iterator<char>(inputFile), {}); | |
inputFile.close(); | |
if (inputFile.good() != true) { | |
std::cout << "|load kernel code| FAILED" << std::endl; | |
return 1; | |
} | |
std::cout << ">> Loaded kernel: " << kernelCode << std::endl; | |
// create program source | |
cl::Program::Sources sources; | |
sources.push_back({kernelCode.c_str(), kernelCode.length()}); | |
std::cout << "|load kernel code| DONE" << std::endl; | |
std::cout << "|build kernel code| START" << std::endl; | |
// create context | |
cl::Context context({calcDevice}); | |
// build kernel | |
cl::Program program(context, sources); | |
if (program.build({calcDevice}) != CL_SUCCESS) { | |
std::cout << "|build kernel code| FAILED - " << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(calcDevice) << std::endl; | |
return 1; | |
} | |
std::cout << "|build kernel code| DONE" << std::endl; | |
//create command queue for the device | |
std::cout << "|create commandQueue| START" << std::endl; | |
cl::CommandQueue commandQueue(context, calcDevice); | |
std::cout << "|create commandQueue| DONE" << std::endl; | |
// create buffers on the device | |
std::cout << "|create buffer| START" << std::endl; | |
cl::Buffer buffer_A(context, CL_MEM_READ_WRITE, sizeof(int) * 10); | |
cl::Buffer buffer_B(context, CL_MEM_READ_WRITE, sizeof(int) * 10); | |
cl::Buffer buffer_C(context, CL_MEM_READ_WRITE, sizeof(int) * 10); | |
std::cout << "|create buffer| DONE" << std::endl; | |
int A[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; | |
int B[] = {0, 1, 2, 0, 1, 2, 0, 1, 2, 0}; | |
//write arrays A and B to the device | |
std::cout << "|write buffer| START" << std::endl; | |
commandQueue.enqueueWriteBuffer(buffer_A, CL_TRUE, 0, sizeof(int) * 10, A); | |
commandQueue.enqueueWriteBuffer(buffer_B, CL_TRUE, 0, sizeof(int) * 10, B); | |
std::cout << "|write buffer| DONE" << std::endl; | |
std::cout << "|create kernel| START" << std::endl; | |
cl::Kernel simple_add(program, "simple_add"); | |
simple_add.setArg(0, buffer_A); | |
simple_add.setArg(1, buffer_B); | |
simple_add.setArg(2, buffer_C); | |
commandQueue.finish(); | |
std::cout << "|create kernel| DONE" << std::endl; | |
std::cout << "|RUN| START" << std::endl; | |
commandQueue.enqueueNDRangeKernel(simple_add, cl::NullRange, cl::NDRange(10), cl::NullRange); // run it | |
std::cout << "|RUN| DONE" << std::endl; | |
std::cout << "|read result|" << std::endl; | |
int C[10]; | |
//read result C from the device to array C | |
commandQueue.enqueueReadBuffer(buffer_C, CL_TRUE, 0, sizeof(int) * 10, C); | |
std::cout << "|sum result|" << std::endl; | |
int sum = 0; | |
for (int i = 0; i < 10; i++) { | |
sum += C[i]; | |
} | |
std::cout << "OpenCL sum: " << sum << std::endl; | |
//normal version | |
sum = 0; | |
for (int i = 0; i < 10; i++) { | |
sum += A[i]; | |
sum += B[i]; | |
} | |
std::cout << "Normal sum: " << sum << std::endl; | |
std::cin.get(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment