3

CUDA 文档不清楚 CUDA 应用程序抛出异常后内存数据如何变化。

例如,内核启动(动态)遇到异常(例如 Warp Out-of-range Address),当前内核启动将停止。在此之后,设备上的数据(例如 __device__ 变量)是否仍会保留,还是会与异常一起被删除?

一个具体的例子是这样的:

  1. CPU 启动内核
  2. 内核将 __device__ variableA 的值更新为 5 然后崩溃
  3. CPU memcpy 从设备到主机的 variableA 的值,在这种情况下 CPU 得到的值是 5 还是其他?

有人可以说明这背后的理由吗?

4

1 回答 1

8

如果发生破坏 CUDA 上下文的 CUDA 错误,则行为未定义。

这种类型的错误很明显,因为它是“粘性的”,这意味着一旦发生,每个 CUDA API 调用都会返回该错误,直到上下文被破坏。

非粘性错误在由 cuda API 调用返回后会自动清除(除了cudaPeekAtLastError)。任何“内核崩溃”类型的错误(无效访问、未指定的启动失败等)都将是一个粘性错误。cudaMemcpy在您的示例中,步骤 3 将(总是)在调用将变量 A 从设备传输到主机的结果上返回 API 错误,因此cudaMemcpy操作的结果是未定义且不可靠的 - 就好像cudaMemcpy操作在某些情况下也失败了未指定的方式。

由于损坏的 CUDA 上下文的行为是未定义的,因此没有定义任何分配的内容,或者通常是发生此类错误后的机器状态。

非粘性错误的一个示例可能是尝试cudaMalloc获取比设备内存中可用的更多数据。这样的操作会返回一个内存不足的错误,但是该错误在返回后会被清除,并且后续(有效的)cuda API调用可以成功完成,而不会返回错误。非粘性错误不会破坏 CUDA 上下文,并且 cuda 上下文的行为与从未请求过无效操作完全相同。

粘滞错误和非粘滞错误之间的这种区别在许多记录在案的错误代码描述中都有体现,例如:

非粘性、非 cuda-context-corrupting:

cudaErrorMemoryAllocation = 2 API 调用失败,因为它无法分配足够的内存来执行请求的操作。

粘性,cuda-context-corrupting:

cudaErrorMisalignedAddress = 74 设备在未对齐的内存地址上遇到加载或存储指令。上下文不能被使用,所以它必须被销毁(并且应该创建一个新的)。此上下文中的所有现有设备内存分配都是无效的,如果程序要继续使用 CUDA,则必须重新构建。

请注意,cudaDeviceReset()仅靠其本身不足以将 GPU 恢复到正确的功能行为。为了实现这一点,“拥有”过程也必须终止。见这里

于 2015-07-26T22:27:23.573 回答