I compared the performance of an OpenCL code, running on the CPU, which simply copies data from one 2D array into another to a pure C++ code which does the same thing. I used a single workgroup in the OpenCL code to make a fair comparison. I used Intel's OpenCL drivers and the Intel compiler. The OpenCL code is about 5 times slower than the CPU code. The compiler gives the following message for the copy loop:
loop was transformed to memset or memcpy.
Any suggestions on how to get the OpenCL code upto speed with the C++ code?
Thanks
OpenCL host code:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <cmath>
#include <ctime>
#include <CL/cl.hpp>
int main(int argc, char **argv)
{
// Create the two input vectors
const int N = 8192;
double *in = new double[N*N];
double *out = new double[N*N];
for(int i = 0; i < N; i++)
for (int j=0; j < N; j++) {
in[i*N + j] = i + j;
out[i*N + j] = 0.;
}
double time;
std::clock_t start;
int niter = 100;
cl_int cl_err;
std::vector<cl::Platform> platforms;
cl_err = cl::Platform::get(&platforms);
std::vector<cl::Device> devices;
cl_err = platforms.at(1).getDevices(CL_DEVICE_TYPE_CPU,
&devices);
cl_context_properties context_properties[3] = {CL_CONTEXT_PLATFORM,
(cl_context_properties)(platforms.at(1)()),
0};
cl::Context context = cl::Context(devices,
context_properties,
NULL, NULL, &cl_err);
cl::Buffer buffer_in = cl::Buffer(context,
CL_MEM_USE_HOST_PTR | CL_MEM_READ_ONLY,
N*N*sizeof(double),
in, &cl_err);
cl::Buffer buffer_out = cl::Buffer(context,
CL_MEM_USE_HOST_PTR | CL_MEM_WRITE_ONLY,
N*N*sizeof(double),
out, &cl_err);
cl::CommandQueue queue = cl::CommandQueue(context, devices.at(0), 0, &cl_err);
std::ifstream sourceFile("vector_copy.cl");
std::string sourceCode((std::istreambuf_iterator<char>(sourceFile)),
std::istreambuf_iterator<char>());
cl::Program::Sources source(1, std::make_pair(sourceCode.c_str(),
sourceCode.length()+1));
cl::Program program(context, source, &cl_err);
cl_err = program.build(devices, NULL, NULL, NULL);
cl::Kernel kernel(program, "vector_copy", &cl_err);
cl_err = kernel.setArg(0, buffer_in);
cl_err = kernel.setArg(1, buffer_out);
cl_err = kernel.setArg(2, N);
cl::NDRange global(N);
cl::NDRange local(N);
start = std::clock();
for (int n=0; n < niter; n++) {
cl_err = queue.enqueueNDRangeKernel(kernel,
cl::NullRange,
global,
local,
NULL, NULL);
cl_err = queue.finish();
}
time = (std::clock() - start)/(double)CLOCKS_PER_SEC;
std::cout << "Time/iteration OpenCL (s) = " << time/(double)niter << std::endl;
return(0);
}
OpenCL kernel code:
__kernel void vector_copy(__global const double* restrict in,
__global double* restrict out,
const int N)
{
int i = get_global_id(0);
int j;
for (j=0; j<N; j++) {
out[j + N*i] = in[j + N*i];
}
}
C++ code:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <cmath>
#include <ctime>
const int N = 8192;
int main(int argc, char **argv)
{
double *in = new double[N*N];
double *out = new double[N*N];
// Create the two input vectors
for(int i = 0; i < N; i++)
for (int j=0; j < N; j++) {
in[j + N*i] = i + j;
out[j + N*i] = 0.;
}
std::clock_t start;
int niter = 100;
start = std::clock();
for (int n=0; n < niter; n++) {
for (int i=0; i<N; i++)
for (int j=0; j<N; j++) {
out[j + N*i] = in[j + N*i];
}
}
double time = (std::clock() - start)/(double)CLOCKS_PER_SEC;
std::cout << "Time/iteration C = " << time/(double)niter << std::endl;
return(0);
}