Cuda 如何通过页面锁定的主机内存共享变量
我想利用CUDA中的Cuda 如何通过页面锁定的主机内存共享变量,cuda,nvidia,gpu,Cuda,Nvidia,Gpu,我想利用CUDA中的页面锁定主机内存在主机和设备之间共享消息,让我通过以下示例来表达我的想法。我不确定这是否合理 我的机器的环境: - Ubuntu 14.04.5 LTS - gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4 - CUDA 9.1 我将我的计划分为以下四个步骤: 让我们假设有两个块,对于第一个块,它进行一些计算,并在第一个块的末尾生成一个信号 块 当第一块完成功能时,通知CPU终端,然后在CPU中组织相应的数据 然后,将数据复制到gpu
页面锁定主机内存
在主机和设备之间共享消息,让我通过以下示例来表达我的想法。我不确定这是否合理
我的机器的环境:
- Ubuntu 14.04.5 LTS
- gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
- CUDA 9.1
我将我的计划分为以下四个步骤:
- 我发现CUDA编译器可能会优化该值并将该值存储在寄存器中,因此我无法在内核中获取该值的最新值,因此我注意到了PTX李>
- 我试图利用PTX阻止编译器优化部分代码,我成功地在内核中获得了信号,但未能将信号从设备传递到主机,这让我非常困惑李>
__global__ void pipeline(int *flag_a, int*flag_b, int*Input, int*Out){
int idx = threadIdx.x;
if (blockIdx.x == 0) {
if (0 == idx) {
flag_a[0] = 1; //to generate signal in the step one
//why the host cannot get the flag_a[0]==1?
}
}
if (blockIdx.x == 1) {
if (0 == idx) {
int value = 0;
do{
asm volatile("ld.global.cg.u32 %0, [%1];" :"=r"(value) : "l"(&flag_b[0]));
//receipt signal form the host generate in step 3
//and the asm volatile to make sure I can get the newest flag_b[0]
} while (value != 1);
}
__syncthreads();
Out[idx] = Input[idx] + idx;
}
}
int main()
{
/*1*/
int *flag_a, *flag_b;
cudaHostAlloc((void**)&flag_a, sizeof(int), cudaHostAllocMapped);
cudaHostAlloc((void**)&flag_b, sizeof(int), cudaHostAllocMapped);
flag_a[0] = 0;
flag_b[0] = 0;
/*2*/
int*Input, *Out;
int *d_Input, *d_Out;
int*d_float_a, *d_float_b;
Input = (int*)malloc(sizeof(int) * 32);
Out = (int*)malloc(sizeof(int) * 32);
for (int i = 0; i<32; i++) {
Input[i] = i;
}
memset(Out, 0, sizeof(int) * 32);
cudaMalloc((void**)&d_Input, sizeof(int) * 32);
cudaMemset(d_Input, 0, sizeof(int) * 32);
cudaMalloc((void**)&d_Out, sizeof(int) * 32);
cudaMemset(d_Out, 0, sizeof(int) * 32);
cudaHostGetDevicePointer((void **)&d_float_a, (void *)flag_a, 0);
cudaHostGetDevicePointer((void **)&d_float_b, (void *)flag_b, 0);
cudaStream_t stream_kernel, stream_datacopy;
cudaStreamCreate(&stream_kernel);
cudaStreamCreate(&stream_datacopy);
pipeline <<< 2, 32, 0, stream_kernel >>> (d_float_a, d_float_b, d_Input, d_Out);
int count = 0;
do{
if (flag_a[0]==1){
cudaMemcpyAsync(d_Input, Input, sizeof(int) * 32, cudaMemcpyHostToDevice, stream_datacopy);
cudaStreamSynchronize(stream_datacopy);
flag_b[0] = 1; //step 3;
break;
}
if (count==10)
break;
} while (1 != flag_a[0]);
cudaStreamSynchronize(stream_kernel);
cudaMemcpy(Out, d_Out, sizeof(int) * 32, cudaMemcpyDeviceToHost);
for (int i = 0; i<32; i++) {
printf("%d:%d\n", i, Out[i]);
}
// free()
return 0;
}
\uuuuu全局\uuuuuu无效管道(int*标志a、int*标志b、int*输入、int*输出){
int idx=threadIdx.x;
if(blockIdx.x==0){
如果(0==idx){
标志_a[0]=1;//在第一步生成信号
//为什么主机无法获取标志_a[0]==1?
}
}
if(blockIdx.x==1){
如果(0==idx){
int值=0;
做{
asm volatile(“ld.global.cg.u32%0,[%1];”:“=r”(值):“l”(&flag_b[0]);
//在步骤3中生成的来自主机的接收信号
//和asm volatile,以确保我可以获得最新的标志\u b[0]
}while(值!=1);
}
__同步线程();
输出[idx]=输入[idx]+idx;
}
}
int main()
{
/*1*/
int*标志a,*标志b;
cudaHostAlloc((无效**)和标志a,尺寸(内部),cudaHostAllocMapped);
cudaHostAlloc((无效**)和flag_b,sizeof(内部),cudaHostAllocMapped);
标志a[0]=0;
标志_b[0]=0;
/*2*/
int*输入,*输出;
int*d_输入,*d_输出;
int*d_float_a,*d_float_b;
输入=(int*)malloc(sizeof(int)*32);
Out=(int*)malloc(sizeof(int)*32);
for(int i=0;i(d_float_a,d_float_b,d_输入,d_输出);
整数计数=0;
做{
如果(标志a[0]==1){
cudaMemcpyAsync(d_输入,输入,sizeof(int)*32,cudamemcpyhostodevice,stream_数据拷贝);
cudaStreamSynchronize(流_数据拷贝);
标志_b[0]=1;//步骤3
打破
}
如果(计数=10)
打破
}而(1!=标志a[0]);
cudaStreamSynchronize(流_内核);
cudaMemcpy(Out,d_Out,sizeof(int)*32,cudaMemcpyDeviceToHost);
对于(int i=0;i最后,我删除了PTX部件的代码,并将代码放入Tesla P100-PCIE
(TCC模式
),它可以正确运行我期望的程序。感谢RobertCrovella在评论中给出的提示
下面是更新的代码和结果
__global__ void pipeline(volatile float *flag_a, volatile float*flag_b, int*Input, int*Out)
{
int idx = threadIdx.x;
if (blockIdx.x == 0) {
if (0 == idx) {
flag_a[idx] = 1;
}
}
if (blockIdx.x == 1) {
if (0 == idx) {
while (!(1 == flag_b[0])) {
}
}
__syncthreads();
Out[idx] = Input[idx] + idx;
}
}
主要功能是从内核获取信号
int main()
{
//Data definition
pipeline << < 2, 32, 0, stream_kernel >> > (flag_a, flag_b, d_Input, d_Out);
while (flag_a[0] == 0);
if (flag_a[0] == 1)
{
std::cout << "get the flag_a[0]==1" << std::endl;
cudaMemcpyAsync(d_Input, Input, sizeof(int) * 32, cudaMemcpyHostToDevice, stream_datacopy);
cudaStreamSynchronize(stream_datacopy);
flag_b[0] = 1;
std::cout << "data transfer has finished" << std::endl;
}
cudaStreamSynchronize(stream_kernel);
cudaMemcpy(Out, d_Out, sizeof(int) * 32, cudaMemcpyDeviceToHost);
for (int i = 0; i < 32; i++)
{
printf("%d:%d\n", i, Out[i]);
}
//free the memory;
return 0;
}
intmain()
{
//数据定义
管道>>(标志a、标志b、d输入、d输出);
while(flag_a[0]==0);
如果(标志a[0]==1)
{
std::cout将通信变量(指针)标记为volatile
asm volatile
与变量上的volatile
装饰没有类似的行为。此外,您可能需要在某些点上使用适当的屏障(如threadfence\u系统)来帮助该过程()
。最后,Windows WDDM不是您的朋友。这里有一些可能有用的信息。不必使用PTX来实现这一点。@RobertCrovella谢谢Robert,我将参考您的建议,并尝试重新考虑如何进行通信。此外,CPU和GPU之间的信号传输似乎不像我想象的那样方便d、 我原本以为锁页主机内存中的数据可以直接在CPU和GPU之间共享,那么,我应该怎么做才能保证通信的稳定性呢?你有没有相关的经验和建议给我?或者,你是否方便对我上面给出的问题给出一个简单的解决方案,这可能对我很有意义?再次感谢!@RobertCrovella另一个问题是,当我想释放一个用volatile修饰的指针(如cudaFreeHost((void*)hptr)
)时,它会给出一个错误未指定的启动失败
,我在搜索相关信息后不知道这个错误,对这个错误有什么意见吗?我感到无助。