cuda 异常后的内存数据状态

Posted

技术标签:

【中文标题】cuda 异常后的内存数据状态【英文标题】:States of memory data after cuda exceptions 【发布时间】:2018-10-08 12:28:47 【问题描述】:

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

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

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

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

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

【问题讨论】:

【参考方案1】:

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

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

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

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

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

在许多记录的错误代码descriptions 中都提到了粘性和非粘性错误之间的区别,例如:

非粘性、非 cuda-context-corrupting:

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

粘性,cuda-context-corrupting:

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

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

【讨论】:

你能告诉我哪个 cuda api 调用清除这些非粘性错误吗? cudaGetLastError() 报告最后一个错误,如果是非粘性错误,则将其清除。 cudaPeekAtLastError() 将报告错误(粘性或非粘性)但不会清除它。如果没有错误,或者之前唯一的错误是非粘性的并且之前已清除,则这些调用中的任何一个都可以报告cudaSuccess 好的,谢谢!所以只是为了说明这一点:如果我两次调用 cudaGetLastError() 而第二次调用没有返回 cudaSuccess 那么我知道发生了一个粘性错误。 是的,假设这两个对cudaGetLastError()的调用之间没有干预活动 您能否详细说明cudaDeviceReset() 在地址未对齐错误后如何无法恢复GPU?

以上是关于cuda 异常后的内存数据状态的主要内容,如果未能解决你的问题,请参考以下文章

cuda 共享内存和块执行调度

android笔记--保存和恢复activity的状态数据

转android笔记--保存和恢复activity的状态数据

Linux下做破坏性测试,模拟内存完全满后的状态怎么做到

释放 LPDIRECT3D9 和 LPDIRECT3DDEVICE9 后的内存状态

Windows系统CPU和内存状态实时查询(Java)