CUDA文档不清楚CUDA应用程序抛出异常后内存数据如何变化。
例如,内核启动(动态)遇到异常(例如Warp超出范围的地址),将停止当前的内核启动。在此之后,设备上的数据(例如__device__变量)是否仍会保留,或者它们是否会被删除?
一个具体的例子是这样的:
有人能说明这背后的理由吗?
答案 0 :(得分:5)
如果发生CUDA错误会破坏CUDA上下文,则行为未定义。
这种类型的错误是显而易见的,因为它是" sticky",这意味着一旦发生,每个CUDA API调用都将返回该错误,直到上下文被销毁。
非粘性错误在cuda API调用返回后自动清除(cudaPeekAtLastError
除外)。任何"崩溃的内核"类型错误(无效访问,未指定的启动失败等)将是一个棘手的错误。在您的示例中,步骤3将(始终)对cudaMemcpy
调用的结果返回API错误,以便将variableA从设备传输到主机,因此cudaMemcpy
操作的结果未定义且不可靠 - 就好像cudaMemcpy
操作也以某种未指定的方式失败了。
由于未定义损坏的CUDA上下文的行为,因此没有任何分配内容的定义,或者通常是在发生此类错误后的机器状态。
非粘性错误的一个示例可能是尝试cudaMalloc
多于设备内存中可用的数据。此类操作将返回内存不足错误,但该错误将在返回后被清除,并且后续(有效)cuda API调用可以成功完成,而不会返回错误。非粘性错误不会破坏CUDA上下文,并且cuda上下文的行为与从未请求过无效操作的行为完全相同。
许多记录错误代码descriptions中都会出现粘性和非粘性错误之间的区别,例如:
非粘性,非cuda-context-corrupting:
粘性,cuda-context-corrupting:cudaErrorMemoryAllocation = 2 API调用失败,因为它无法分配足够的内存来执行请求的操作。
cudaErrorMisalignedAddress = 74 设备在未对齐的内存地址上遇到加载或存储指令。不能使用上下文,因此必须销毁它(并且应该创建一个新的上下文)。此上下文中的所有现有设备内存分配均无效,如果程序要继续使用CUDA,则必须重新构建。
请注意,cudaDeviceReset()
本身不足以将GPU恢复到正常的功能行为。为了实现这一点,"拥有"进程也必须终止。见here。