在基于OpenCL的应用程序中,我在MacOS上遇到了难以追踪的错误。在一个发行版本中,我的代码有时会因SIGABRT而崩溃,在一个发行版本中,我在线程上得到一个EXC_BAD_INSTRUCTION
显然是在管理某些lib派发/ GCD内容(com.apple.libdispatch-manager
)。请注意,我自己没有调用任何与GCD相关的东西,因此我认为这是由Apple OpenCL运行时在后台完成的。
上下文是一个基准测试应用程序,用于测量CL命令排队和接收CL_COMPLETE
回调以各种方式访问CL缓冲区之间的延迟。您将在下面找到代码。仅对我的MacBook Pro(AMD Radeon Pro 555计算引擎)中的三个可用CL设备之一发生错误。
代码的相关部分:
nlohmann::json performTestUseHostPtr()
{
nlohmann::json results;
std::vector<cl::Event> inputBufferEvent (1);
std::vector<cl::Event> outputBufferEvent (1);
std::vector<cl::Event> kernelEvent (1);
for (auto size : testSizes)
{
std::vector<float> inputBufferHost (size);
std::vector<float> outputBufferHost (size);
cl::Buffer inputBuffer (context, CL_MEM_USE_HOST_PTR | CL_MEM_READ_ONLY, size * sizeof (float), inputBufferHost.data());
cl::Buffer outputBuffer (context, CL_MEM_USE_HOST_PTR | CL_MEM_WRITE_ONLY, size * sizeof (float), outputBufferHost.data());
void* inputBufferMapped = queue.enqueueMapBuffer (inputBuffer, CL_TRUE, CL_MAP_WRITE_INVALIDATE_REGION, 0, size * sizeof (float));
std::memcpy (inputBufferMapped, testData.data(), size * sizeof (float));
kernel.setArg (0, inputBuffer);
kernel.setArg (1, outputBuffer);
for (int i = 0; i < numTests; ++i)
{
startTimes[i] = my::HighResolutionTimer::now();
queue.enqueueUnmapMemObject (inputBuffer, inputBufferMapped, nullptr, &inputBufferEvent[0]);
inputBufferEvent[0].setCallback (CL_COMPLETE, setTimestampCallback, &unmapCompletedTimes[i]);
queue.enqueueNDRangeKernel (kernel, cl::NullRange, cl::NDRange (size), cl::NullRange, &inputBufferEvent, &kernelEvent[0]);
kernelEvent[0].setCallback (CL_COMPLETE, setTimestampCallback, &kernelCompletedTimes[i]);
void* outputBufferMapped = queue.enqueueMapBuffer (outputBuffer, CL_FALSE, CL_MAP_READ, 0, size * sizeof (float), &kernelEvent, &outputBufferEvent[0]);
outputBufferEvent[0].setCallback (CL_COMPLETE, setTimestampCallback, &mapCompletedTimes[i]);
inputBufferMapped = queue.enqueueMapBuffer (inputBuffer, CL_TRUE, CL_MAP_WRITE_INVALIDATE_REGION, 0, size * sizeof (float), &kernelEvent, nullptr);
// --- Release build error seems to happen somewhere here ---
queue.finish();
std::memcpy (inputBufferMapped, outputBufferMapped, size * sizeof (float));
queue.enqueueUnmapMemObject (outputBuffer, outputBufferMapped);
queue.finish();
}
queue.enqueueUnmapMemObject (inputBuffer, inputBufferMapped);
results["vecSize=" + std::to_string (size)] = calculateTimes();
queue.finish();
}
return results;
}
注释:
我检查了所有CL调用的错误代码,所有错误代码都返回CL_SUCCESS
,只是在上面的代码中将它们删除了,以便进行更好的概述。
我标记了我大致假定会发生错误的行,这是基于在release版本中插入打印语句并观察错误发生之前代码的哪些点已完成。此外,在queue.finish();
语句上方插入打印语句会使该错误消失,因此这可能与计时有关。
更新:
在我以为发生错误的行中插入短暂睡眠并运行调试版本时,它现在还会触发SIGABRT。另外,我可以在控制台上找到以下打印件:
OpenCLLatencyTests(17903,0x10012a5c0) malloc: tiny_free_list_remove_ptr: Internal invariant broken (next ptr of prev): ptr=0x1003052d0, prev_next=0x0
OpenCLLatencyTests(17903,0x10012a5c0) malloc: *** set a breakpoint in malloc_error_break to debug
Signal: SIGABRT (signal SIGABRT)
E0412 11:55:02.898913 233472000 ProtobufClient.cpp:63] No such process
问题: