【发布时间】:2014-06-18 20:42:21
【问题描述】:
我正在编写一个基于 cuda 的程序,该程序需要定期将一组项目从 GPU 传输到主机内存。为了保持进程异步,我希望使用 cuda 的 UMA 在主机内存中有一个内存缓冲区和标志(因此 GPU 和 CPU 都可以访问它)。 GPU 将确保标志被清除,将其项目添加到缓冲区,并设置标志。 CPU 等待标志被设置,将内容从缓冲区中复制出来,然后清除标志。据我所知,这不会产生任何竞争条件,因为它会强制 GPU 和 CPU 轮流,始终对彼此相对的标志进行读写。
到目前为止,我还不能让它工作,因为似乎确实存在某种竞争条件。我想出了一个有类似问题的更简单的例子:
#include <stdio.h>
__global__
void uva_counting_test(int n, int *h_i);
int main() {
int *h_i;
int n;
cudaMallocHost(&h_i, sizeof(int));
*h_i = 0;
n = 2;
uva_counting_test<<<1, 1>>>(n, h_i);
//even numbers
for(int i = 1; i <= n; ++i) {
//wait for a change to odd from gpu
while(*h_i == (2*(i - 1)));
printf("host h_i: %d\n", *h_i);
*h_i = 2*i;
}
return 0;
}
__global__
void uva_counting_test(int n, int *h_i) {
//odd numbers
for(int i = 0; i < n; ++i) {
//wait for a change to even from host
while(*h_i == (2*(i - 1) + 1));
*h_i = 2*i + 1;
}
}
对我来说,这种情况总是在 CPU 的第一条打印语句之后挂起 (host h_i: 1)。真正不寻常的事情(可能是一个线索)是我可以让它在 cuda-gdb 中工作。如果我在 cuda-gdb 中运行它,它会像以前一样挂起。如果我按 ctrl+C,它会将我带到内核中的 while() 循环行。从那里,令人惊讶的是,我可以告诉它继续,它会完成。对于 n > 2,它会在每个内核之后再次冻结内核中的 while() 循环,但我可以使用 ctrl+C 继续推动它并继续。
如果有更好的方法来完成我正在尝试做的事情,那也会有所帮助。
【问题讨论】:
-
代码中的任何内容都不能保证缓存的一致性。如果没有某种内存栅栏,这种方法就行不通。而是考虑每次都启动一个内核,无论如何与统一内存访问相比,这相当便宜。
-
您的示例代码不起作用,因为在内核执行期间无法保证跨 PCI-e 总线的内存一致性。这个游戏的基本规则是不要尝试设计任何依赖于 GPU 和主机设备之间显式主机驱动程序级别同步以外的任何东西的执行模型。
-
您没有使用Unified Memory.。您正在使用零拷贝主机内存。如果您只想查看有效的计数测试,请查看here。除了关于您的方法的所有其他 cmets,今天的统一内存实现并非旨在为主机和当前执行的内核提供对内存区域的同时一致访问。