CUDA文档不清楚在CUDA应用程序抛出异常后内存数据如何变化。
例如,内核启动(动态)遇到异常(例如,Warp out -range Address),当前内核启动将被停止。在此之后,设备上的数据(例如__device__变量)仍然保留还是与异常一起被删除?
一个具体的例子是这样的:
- CPU启动内核
- 内核将__device__变量a的值更新为5,然后崩溃
- CPU内存变量a从设备到主机的值,CPU在这种情况下得到的值是什么,5或其他什么?
谁能说明这背后的原理?
在CUDA错误破坏CUDA上下文的情况下,该行为是未定义的。
这种类型的错误是明显的,因为它是"粘滞的",这意味着一旦发生,每个单独的CUDA API调用都会返回该错误,直到上下文被破坏。
非粘性错误在cuda API调用返回后自动清除(cudaPeekAtLastError
除外)。任何"崩溃的内核";类型错误(无效访问,未指定的启动失败等)将是一个粘性错误。在您的示例中,步骤3将(总是)在cudaMemcpy
调用的结果上返回API错误,以将变量a从设备传输到主机,因此cudaMemcpy
操作的结果是未定义的和不可靠的-就好像cudaMemcpy
操作也以某种未指定的方式失败。
由于损坏的CUDA上下文的行为是未定义的,因此没有任何分配内容的定义,或者在发生此类错误后机器的一般状态。
非粘性错误的一个例子可能是试图cudaMalloc
比设备内存中可用的更多的数据。这样的操作将返回内存不足错误,但该错误将在返回后被清除,并且后续(有效的)cuda API调用可以成功完成,而不会返回错误。非粘性错误不会破坏CUDA上下文,CUDA上下文的行为与从未请求过无效操作完全相同。
粘性错误和非粘性错误的区别在许多文档化的错误代码描述中都有提到,例如:
同步、非粘性、非cuda-context-corrupting:
cudaErrorMemoryAllocation = 2API调用失败,因为它无法分配足够的内存来执行请求的操作。
异步,粘性,cuda-context-corrupting:
cudaErrorMisalignedAddress = 74设备在未对齐的内存地址上遇到加载或存储指令。不能使用上下文,因此必须销毁它(并且应该创建一个新的上下文)。如果程序要继续使用CUDA,则此上下文中所有现有的设备内存分配都是无效的,必须重建。
注意cudaDeviceReset()
本身不足以恢复GPU的正常功能行为。为了实现这一点,"所有权";进程也必须终止。看到这里。