我比较了运行在CPU上的OpenCL代码的性能,它简单地将数据从一个2D数组复制到另一个2D数组中,而纯C++代码则做了同样的事情。我在OpenCL代码中使用了一个工作组来进行公平的比较。我使用了英特尔的OpenCL驱动程序和英特尔编译器。OpenCL代码比CPU代码慢5倍。编译器为copy循环提供以下消息:
loop was transformed to memset or memcpy.对于如何使OpenCL代码与C++代码同步,有什么建议吗?
谢谢
OpenCL主机代码:
#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 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++代码:
#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);
}发布于 2013-11-20 13:42:11
Intel OpenCL编译器能够跨工作组进行矢量化。基本上,一个函数在不同的SSE寄存器中同时运行8个线程。
您的特定内核不会这样做。但这并不重要。我使用Visual 2010和最新的Intel OpenCL测试了您的应用程序。我被迫将N从8192减少到4096,因为集成的GPU将最大OpenCL缓冲区大小减少到128 is,即使只使用CPU。
我的结果是:您的OpenCL内核给了我6956 My /s的带宽。一个变化很小的内核(调用它时使用N*N作为全局大小,NULL作为本地大小,因为如果我们根本不关心本地内存,那么对于CPU来说,我们应该不定义它)。
__kernel void vector_copy2(__global const double* restrict in,
__global double* restrict out)
{
int i = get_global_id(0);
out[i] = in[i];
}给出了相同的结果(7006MB/s)。这个内核实际上是跨线程向量化的,可以使用Intel OpenCL内核编译器进行验证。它为多个线程(如4)生成一个内核,为单个线程生成一个内核。然后,它只运行向量化的内核,直到必须运行最后几个工作项的单线程内核。
C++代码提供了6494 in /s,因此它非常符合要求。我认为国际刑事法院甚至不可能将其速度提高5倍。
我注意到在您的代码中有platforms.at(1),您的计算机中的0平台是什么?
请记住,如果您根本不关心本地内存(内核中没有调用get_local_id ),那么应该将enqueueNDRange的本地大小作为一个简单的神奇参数来处理。要么将其保留为NULL,要么尝试找到一个生成最快结果的值。
发布于 2013-11-20 10:14:05
即使优化了OpenCL代码,它仍将执行1x1(工作项按工作项)的复制。因为只允许OpenCL编译器在每个工作项的基础上进行优化。虽然编译器可能会将C++情况优化为一个memcpy()调用(正如编译器告诉您的那样)。
如果禁用编译器优化,它将在GPU中执行得更快。
那么这有什么原因吗?为此,您有memcpy() in C++和OpenCL中的OpenCL。我认为后一种是你应该使用的。
https://stackoverflow.com/questions/20089963
复制相似问题