cudaHostRegister returns cudaErrorInvalidValue on GPUs with compute capability 1.1
我有一个简单的程序,它分配一个 unsigned __int64(堆栈上的 8 个字节),然后尝试使用 cudaHostRegister 在 GPU 上注册该内存。进行此调用的程序部分如下所示:
1
2 3 4 5 6 7 8 9 10 |
unsigned __int64 mem;
unsigned __int64 *pMem = &mem; cudaError_t result; result = cudaHostRegister(pMem, sizeof(unsigned __int64), cudaHostRegisterMapped); |
我在 Visual Studio 2010 Premium 中使用 nvcc 标志 compute_11 和 sm_11 进行编译,并且在我的笔记本电脑上一切正常,运行带有 cuda 功能版本 3.0 的 Quadro K1000m。
我最近切换到我的台式机,我尝试使用 GeForce 8600 GT 和 GeForce 9500 GT 运行,两者的 cuda 功能版本均为 1.1。
根据 NVIDIA 的 cudaHostRegister 文档,具有 1.1 及以上 cuda 功能的卡应该允许使用 cudaHostRegisterMapped:
cudaHostRegisterMapped: Maps the allocation into the CUDA address space. The device pointer to the memory may be obtained by calling cudaHostGetDevicePointer(). This feature is available only on GPUs with compute capability greater than or equal to 1.1.
经过一番搜索,似乎 cudaHostRegisterMapped 可能需要页面对齐的内存。我认为这可能是我的 3.0 卡和我的 1.1 卡之间的差异,所以我屏蔽了地址以获得页面对齐的地址,并在 size 字段中使用了页面的大小(4096 字节),如下所示:
1
2 3 4 5 6 7 8 9 10 11 12 13 |
unsigned __int64 mem;
unsigned __int64 *pMem = &mem; unsigned __int64 memAddr = (unsigned __int64)pMem; cudaError_t result; pMem = (unsigned __int64 *)(memAddr & 0xFFFFFFFFFFFFF000); result = cudaHostRegister(pMem, 4096, cudaHostRegisterMapped); |
此代码也适用于我的 3.0 卡,但在我的 1.1 卡上失败,结果与之前相同。 cudaHostRegister 函数返回错误cudaErrorInvalidValue,表示:
one or more of the parameters passed to the API call is not within an acceptable range of values
我无法找到更多关于为什么这个函数可能会像这样失败的更多信息。感谢任何人都可以提供的任何帮助。
[编辑]
根据 talonmies 的回复,我验证了我的至少一张卡(9500 GT,我没有在 8600 GT 上运行它)确实支持根据 SDK 附带的 NVIDIA 的 deviceQuery 可执行文件进行内存映射。
- 你的对齐代码对我来说看起来很冒险。确定生成的地址真的总是你的吗?在我看来,您至少需要 mem[128] 以确保安全。
- SM 1.1 及更高版本的硬件可以做映射固定内存,因此映射标志对除原始 G80 (GeForce GTX 8800) 之外的所有 GPU 都有效。如果在您删除该标志时调用通过,请将其作为错误报告给 NVIDIA。两台机器之间的平台差异是什么(如果有的话)?如果内存在堆栈上,则某些平台不支持页面锁定该内存。
- @ArchaeaSoftware:当我将标志更改为 cudaHostRegisterPortable 而不是 cudaHostRegisterMapped 时,调用确实通过了。两个系统(一台装有 Quadro K1000m 的笔记本电脑和一台装有 9500GT 的台式机)都运行 Windows 7 Ultimate x64 SP1。台式机配备 AMD 处理器,而笔记本电脑运行 Intel,如果这很重要的话。我会将此作为错误报告给 NVIDIA;感谢您的帮助!
部分计算能力 1.1 设备支持映射内存,但不是全部。 MCP79 系列集成芯片组(如 Ion 和 9300M/9400M)确实支持映射内存。但是,较旧的计算能力 1.1 设备(如 8600GT 和 9500GT)不支持映射内存。
您可以使用 cudaGetDeviceProperties API 调用以编程方式检查这一点; canMapHostMemory 将告诉您给定设备是否支持映射内存。
- 使用 SDK 提供的 deviceQuery 可执行文件,9500GT 的结果显示: Support host page-locked memory mapping: Yes 这不是 canMapHostMemory 字段吗?
- 我刚刚在 deviceQuery 的源代码中验证了为 Support host page-locked memory mapping 显示的字段是 canHostMemory 设备属性。
- 所以 cudaHostRegister() 在返回 canMapHostMemory = true 的同一个 9500GT 上失败?如果是这样,听起来像是您应该报告的错误。 (1) 转到 nvidia.com/content/cuda/cuda-toolkit.html (2) 如果您已有 NVdeveloper 帐户(例如通过 partners.nvidia.com),请单击绿色的”登录到 nvdeveloper”链接屏幕右半部分(否则单击”加入 nvdeveloper”申请新帐户) (3) 使用您的电子邮件地址和密码登录 (4) 在左侧边栏中,单击标题为””的顶部第三个链接Bug Report” (5) 填写错误报告表并提交
- @talonmies:所有 SM 1.1。以及更高版本的硬件,包括 8600GT 和 9500GT,都支持映射固定内存。唯一不支持映射固定内存的支持 CUDA 的 GPU 是 G80。
- @ArchaeaSoftware:固定映射=”零拷贝”不是吗? Pre Ion/GT200 设备绝对不支持零拷贝。
- @talonmies,在 NVIDIA 时,我编写了规范并为 CUDA 2.2 进行了映射固定内存的初始实现。除了 MCP79(真正没有副本)之外,G86 是我最喜欢的测试平台,因为它非常慢,它在传输受限的工作负载(如 Black-Scholes)上表现出最大的优势。如果驱动程序没有正确报告对 SM 1.1 类硬件上的功能的支持,那就是驱动程序错误。硬件可以做到。
- @ArchaeaSoftware:所以如果真的没有副本,驱动程序是否使用卡本身上的某种寄存器或内存映射来映射内存?所有支持映射内存的版本都是这种情况吗?所以在我的情况下,问题很可能是驱动程序错误地报告它不支持该卡的映射标志。没有映射,它是通过其他方式完成的吗?
- @fortenbt:在所有情况下,固定内存都是为 GPU 映射的,就像任何其他支持 DMA 的设备一样。映射的固定内存恰好以这样的方式映射
来源:https://www.codenong.com/12301772/