CUDA已从设备锁定内存刷新

CUDA已从设备锁定内存刷新,cuda,Cuda,CUDA 5,设备功能3.5,VS 2012,64位Win 2012服务器 线程之间没有共享内存访问,每个线程都是独立的 我正在使用零拷贝的固定内存。只有在主机上发出cudaDeviceSynchronize时,我才能从主机读取设备写入的固定内存 我希望能够: 设备更新后立即刷新到固定内存中 不阻止设备线程(可能通过异步复制) 每次设备写入后,我都尝试调用\uuuuuuThreadFence\uSystem和\uuuThreadFence,但没有刷新 下面是一个完整的CUDA代码示例,演示了我的

CUDA 5,设备功能3.5,VS 2012,64位Win 2012服务器

线程之间没有共享内存访问,每个线程都是独立的

我正在使用零拷贝的固定内存。只有在主机上发出
cudaDeviceSynchronize
时,我才能从主机读取设备写入的固定内存

我希望能够:

  • 设备更新后立即刷新到固定内存中
  • 不阻止设备线程(可能通过异步复制)
  • 每次设备写入后,我都尝试调用
    \uuuuuuThreadFence\uSystem
    \uuuThreadFence
    ,但没有刷新

    下面是一个完整的CUDA代码示例,演示了我的问题:

    #包括
    #包括
    #包括“cuda.h”
    #包括“cuda_runtime.h”
    #包括“设备启动参数.h”
    __全局无效内核(易失性浮点*hResult)
    {
    int tid=threadIdx.x+blockIdx.x*blockDim.x;
    printf(“内核%u:在写入内核之前,\n”,tid);
    hResult[tid]=tid+1;
    __threadfence_系统();
    //希望数据被刷新到这里的主机!
    printf(“内核%u:在内核中写入\n之后”,tid);
    //循环浪费时间(睡眠)
    对于(int-timeWater=0;timeWater<100000000;timeWater++);
    }
    void main()
    {
    块大小=2;
    挥发性浮点数*hResult;
    cudaHostAlloc((空隙**)和hResult,区块*尺寸(浮动),cudaHostAllocMapped);
    内核(hResult);
    int filledelementscenter=0;
    //NAIVE线程实现,可以使用
    //另一个主机线程
    while(填充元素中心<块)
    {
    //块,直到值更改为止,这将按顺序移动
    //而线程没有顺序(对于此示例可以)。
    而(hResult[Filled元素中心]==0);
    printf(“%f\n”,hResult[Filled元素中心];;
    filledlementsconter++;
    }
    cudaFreeHost((void*)hResult);
    系统(“暂停”);
    }
    
    当前此示例将无限期等待,因为除非我发出
    cudaDeviceSynchronize
    ,否则不会从设备读取任何内容。下面的示例有效,但它不是我想要的,因为它违背了异步复制的目的:

    void main()
    {
    块大小=2;
    挥发性浮点数*hResult;
    cudaHostAlloc((空隙**)和hResult,区块*尺寸(浮动),cudaHostAllocMapped);
    内核(hResult);
    cudaError_t error=cudaDeviceSynchronize();
    if(error!=cudaSuccess){throw;}
    对于(int i=0;i
    不能将主机指针直接传递到内核。如果使用带有
    cudaHostAllocMapped
    标志的
    cudaHostAllocMapped
    分配主机内存,则首先必须检索映射主机内存的设备指针,然后才能在内核中使用它。用于获取映射主机内存的设备指针

    float* hResult, *dResult;
    cudaHostAlloc((void**)&hResult, blocks*sizeof(float), cudaHostAllocMapped);
    cudaHostGetDevicePointer(&dResult,hResult);
    Kernel<<<1,blocks>>>(dResult);
    
    float*hResult,*dResult;
    cudaHostAlloc((空隙**)和hResult,区块*尺寸(浮动),cudaHostAllocMapped);
    cudaHostGetDevicePointer(&dResult,hResult);
    果仁(dResult);
    
    调用
    \uuu threadfence\u system()
    将确保系统在继续之前可以看到写入操作,但CPU将缓存
    h\u result
    变量,因此您只是在无限循环中旋转旧值。尝试将h_结果标记为volatile,我在Centos 6.2上使用CUDA 5.5和特斯拉M2090使用了您的代码,可以得出以下结论:

    它不能在您的系统上工作的问题一定是驱动程序问题,我建议您使用TCC驱动程序

    我附加了我的代码,运行良好,并做你想要的。这些值在内核结束之前出现在主机端。如您所见,我添加了一些计算代码,以防止由于编译器优化而删除for循环。我添加了一个流和一个回调,在流中的所有工作完成后执行。程序输出
    1
    2
    ,并且在很长一段时间内不执行任何操作,直到
    流结束…
    打印到控制台

     #include <iostream>
     #include "cuda.h"
     #include "cuda_runtime.h"
     #include "device_launch_parameters.h"
    
     #define SEC_CUDA_CALL(val)           checkCall  ( (val), #val, __FILE__, __LINE__ )
    
     bool checkCall(cudaError_t result, char const* const func,  const char *const file, int const line)
     {
        if (result != cudaSuccess)
        {
                std::cout << "CUDA (runtime api) error: " << func << " failed! " << cudaGetErrorString(result) << " (" << result << ") " << file << ":" << line << std::endl;
        }
        return result != cudaSuccess;
    }
    
    class Callback
    {
    public:
        static void CUDART_CB dispatch(cudaStream_t stream, cudaError_t status, void *userData);
    
    private:
        void call();
    };
    
    void CUDART_CB Callback::dispatch(cudaStream_t stream, cudaError_t status, void *userData)
    {
        Callback* cb = (Callback*) userData;
        cb->call();
    }
    
    void Callback::call()
    {
         std::cout << "stream finished..." << std::endl;
    }
    
    
    
    __global__ void Kernel(volatile float* hResult)
    {
        int tid = threadIdx.x + blockIdx.x * blockDim.x;
    
        hResult[tid] = tid + 1;
        __threadfence_system();
        float A = 0;
        for (int timeWater = 0; timeWater  < 100000000; timeWater++)
        {
            A = sin(cos(log(hResult[0] * hResult[1]))) + A;
            A = sqrt(A);
        }
    }
    
    int main(int argc, char* argv[])
    {
        size_t blocks = 2;
        volatile float* hResult;
        SEC_CUDA_CALL(cudaHostAlloc((void**)&hResult,blocks*sizeof(float),cudaHostAllocMapped));
    
        cudaStream_t stream;
        SEC_CUDA_CALL(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking));
        Callback obj;
        Kernel<<<1,blocks,NULL,stream>>>(hResult);
        SEC_CUDA_CALL(cudaStreamAddCallback(stream, Callback::dispatch, &obj, 0));
    
        int filledElementsCounter = 0;
    
        while (filledElementsCounter < blocks)
        {
            while(hResult[filledElementsCounter] == 0);
            std::cout << hResult[filledElementsCounter] << std::endl;
            filledElementsCounter++;
        }
    
        SEC_CUDA_CALL(cudaStreamDestroy(stream));
        SEC_CUDA_CALL(cudaFreeHost((void *)hResult));
    }
    
    #包括
    #包括“cuda.h”
    #包括“cuda_runtime.h”
    #包括“设备启动参数.h”
    #定义SEC_CUDA_CALL(val)checkCall((val),#val,u文件,u行)
    bool checkCall(cudaError\u t result、char const*const func、const char*const file、int const行)
    {
    如果(结果!=cudaSuccess)
    {
    
    当你说“你不能通过”时你是想解决我的刷新问题,还是说一般的问题?因为当我用
    cudaDeviceSynchronize
    替换我的while循环时,我可以访问hResult中的数据,而无需执行任何
    cudaMemcpy
    。我仍然看不到你建议的解决方案是如何解决刷新问题的。我是否继续在dR上执行
    cudamemcpysync
    esult直到我找到它里面的东西?实际上我指出了一个会导致未定义行为的一般性错误。刷新问题可能是由于内核中的
    printf
    语句造成的。因为内核中的
    printf
    在内核完成执行后会转储其输出。我在问题中添加了另一个示例,哪一个是有效的,但是是同步的。你是说第二个示例有一个未定义的行为吗?它是有效的,即使我删除了内核
    printf
    ,这只有在你没有统一虚拟寻址的情况下才是正确的。如果你有UVA(即sm_20或更高版本,64位Linux或带有TCC/WinXP的64位Windows)那么你就不需要调用
    cudaHostGetDevicePointer()
    。有关更多信息,请参阅。@Tom,因此我拥有除TCC之外的所有这些,因为我目前正在使用GTX Titan,但是代码仍然可以工作,而没有调用
    cudaHostGetDevicePointer
    ,这是侥幸吗?我已经更新了上面的示例并添加了u threadfence_system()而且不稳定,因为添加volat是个好主意