我在基于 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 调用的错误代码,所有 return CL_SUCCESS
,只是在上面的代码中删除了它们以获得更好的概览。我标记了我粗略假设发生错误的行,这是基于在发布版本中插入打印语句并观察代码的哪些点在故障发生之前完成的。此外,在语句上方插入打印语句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
问题:
- 谁能在我的代码中发现一个明显的错误?
- 如果没有,Apple OpenCL 实施中是否有任何已知错误可能导致此类错误?