Skip to content

Instantly share code, notes, and snippets.

@IceflowRE
Last active February 2, 2017 16:04
Show Gist options
  • Save IceflowRE/c50a57258a6a6058f0e83e68dc6fcb42 to your computer and use it in GitHub Desktop.
Save IceflowRE/c50a57258a6a6058f0e83e68dc6fcb42 to your computer and use it in GitHub Desktop.
Small OpenCL 2.0 code
# 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/
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)];
}
/*
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