我正在使用OpenCL从事C ++项目。我将CPU用作intel OpenCL runtime
的OpenCL设备我注意到调用OpenCL函数时有一个奇怪的副作用。这是一个简单的测试:
#include <iostream>
#include <cstdio>
#include <vector>
#include <CL/cl.hpp>
int main(int argc, char* argv[])
{
/*
cl_int status;
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
std::vector<cl::Device> devices;
platforms[1].getDevices(CL_DEVICE_TYPE_CPU, &devices);
cl::Context context(devices);
cl::CommandQueue queue = cl::CommandQueue(context, devices[0]);
status = queue.finish();
printf("Status: %d\n", status);
*/
int ch;
int b = 0;
int sum = 0;
FILE* f1;
f1 = fopen(argv[1], "r");
while((ch = fgetc(f1)) != EOF)
{
sum += ch;
b++;
if(b % 1000000 == 0)
printf("Char %d read\n", b);
}
printf("Sum: %d\n", sum);
}
它是一个简单的循环,它通过char读取文件char并添加它们,因此编译器不会尝试优化它。
我的系统是运行Ubuntu 14.10的Core i7-4770K,2TB HDD 16GB DDR3。上面的程序以100MB文件作为输入,大约需要770ms。这与我的硬盘速度一致。到目前为止一切都很好。
如果您现在反转注释并仅运行OpenCL调用区域,则需要大约200毫秒。再一次,到目前为止,这么好。
如果您取消注释,则该程序需要超过2000毫秒。我期望770ms + 200ms,但它是2000ms。您甚至可以注意到for循环中输出消息之间的延迟增加。这两个区域(OpenCL调用和读取字符)应该是独立的。
我不明白为什么使用OpenCL会干扰简单的C ++ for loop性能。它不是一个简单的OpenCL初始化延迟。
我用以下代码编译此示例:
g++ weird.cpp -O2 -lOpenCL -o weird
我也尝试过使用Clang ++,但它也是一样的。
答案 0 :(得分:3)
这是一个有趣的。这是因为在实例化队列时getc是线程安全版本,因此时间增加是锁定的释放周期 - 我不知道为什么/如何发生这种情况但这是AMD OpenCL的决定性因素带有intel CPU的SDK。我非常惊讶我与OP的时间基本相同。
https://software.intel.com/en-us/forums/topic/337984
您可以通过将getc更改为getc_unlocked来尝试解决此特定问题。
它让我恢复到930毫秒 - 超过750毫秒的时间增加主要用于平台和上下文创建行。
答案 1 :(得分:1)
我认为效果是由OpenCL对象仍在范围内引起的,因此在for循环之前不会被删除。由于需要考虑,它们可能正在影响其他计算。例如,运行您给出的示例会在我的系统上产生以下时间(在Mac OSX上使用O2的g ++ 4.2.1):
CL: 0.012s
Loop: 14.447s
Both: 14.874s
但是将OpenCL代码放入其自己的匿名范围中,因此在循环之前自动调用析构函数似乎可以解决问题。使用代码:
#include <iostream>
#include <cstdio>
#include <vector>
#include "cl.hpp"
int main(int argc, char* argv[])
{
{
cl_int status;
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
std::vector<cl::Device> devices;
platforms[1].getDevices(CL_DEVICE_TYPE_CPU, &devices);
cl::Context context(devices);
cl::CommandQueue queue = cl::CommandQueue(context, devices[0]);
status = queue.finish();
printf("Status: %d\n", status);
}
int ch;
int b = 0;
int sum = 0;
FILE* f1;
f1 = fopen(argv[1], "r");
while((ch = fgetc(f1)) != EOF)
{
sum += ch;
b++;
if(b % 1000000 == 0)
printf("Char %d read\n", b);
}
printf("Sum: %d\n", sum);
}
我得到了时间:
CL: 0.012s
Loop: 14.635s
Both: 14.648s
这似乎是线性增加的。与系统上的其他影响相比,效果非常小,例如来自其他进程的CPU负载,但在添加匿名范围时似乎已经消失。我将进行一些分析,并将其添加为编辑,如果它产生任何感兴趣的东西。