Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Cuda 如何通过页面锁定的主机内存共享变量_Cuda_Nvidia_Gpu - Fatal编程技术网

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

我想利用CUDA中的
页面锁定主机内存
在主机和设备之间共享消息,让我通过以下示例来表达我的想法。我不确定这是否合理

我的机器的环境:

 - Ubuntu 14.04.5 LTS
 - gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
 - CUDA 9.1
我将我的计划分为以下四个步骤:

  • 让我们假设有两个块,对于第一个块,它进行一些计算,并在第一个块的末尾生成一个信号 块
  • 当第一块完成功能时,通知CPU终端,然后在CPU中组织相应的数据
  • 然后,将数据复制到gpu,并在数据复制完成时向gpu发送信号
  • gpu中的第二个块根据步骤3中的信号触发
  • 在您知道我想做什么之后,我遇到了一个问题,当我更改页面锁定内存中的数据时(在我的程序中是信号),它们似乎无法被对方设备识别。

    对于这个问题,我尝试了以下方法

    • 我发现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)
    )时,它会给出一个错误
    未指定的启动失败
    ,我在搜索相关信息后不知道这个错误,对这个错误有什么意见吗?我感到无助。