CUDA和x2B;OpenMP多GPU批处理

CUDA和x2B;OpenMP多GPU批处理,cuda,gpu,openmp,multi-gpu,Cuda,Gpu,Openmp,Multi Gpu,我正在努力做到以下几点: 我假设我有一个具有异构处理单元(PU)的系统,包括CPU、GPU和Intel Xeon Phis。GPU设备也可以具有不同的特性。因此,在这些设备之间拆分工作负载不像N/num_设备那样简单 omp_set_num_threads(system->getPUCount()); #pragma omp parallel { unsigned int cpu_thread_id = omp_get_thread_num(); unsigned int

我正在努力做到以下几点: 我假设我有一个具有异构处理单元(PU)的系统,包括CPU、GPU和Intel Xeon Phis。GPU设备也可以具有不同的特性。因此,在这些设备之间拆分工作负载不像N/num_设备那样简单

omp_set_num_threads(system->getPUCount());
#pragma omp parallel
{
    unsigned int cpu_thread_id = omp_get_thread_num();
    unsigned int num_cpu_threads = omp_get_num_threads();
每个线程在循环中迭代,直到到达数据的末尾

    PU pu = listOfPUs[cpu_thread_id];

    //threads are active until all data is processed
    while (finish_0 < N) {
        //the my_start and my_finish are private to a specific device.
        int my_start = 0;
        int my_finish = 0;
现在我检查PU的类型,并执行相应的内核

if(pu.getType() == GPU) {

            int myN = my_finish-my_start;

            CudaSafeCall(cudaSetDevice(pu.getId()));

            unsigned int nbytes_per_kernel = sizeof(double)*myN;

            //memory allocation
            CudaSafeCall(cudaMalloc((void**)&d_a, nbytes_per_kernel));
            CudaSafeCall(cudaMalloc((void**)&d_c, nbytes_per_kernel));

            CudaSafeCall(cudaMemset(d_a, 0, nbytes_per_kernel));
            CudaSafeCall(cudaMemset(d_c, 0, nbytes_per_kernel));
            //data transfer
            CudaSafeCall(cudaMemcpy(d_a, a+my_start, nbytes_per_kernel, cudaMemcpyHostToDevice));
            CudaSafeCall(cudaMemcpy(d_c, c+my_start, nbytes_per_kernel, cudaMemcpyHostToDevice));


            //block and grid values
            dim3 gpu_threads(128);
            dim3 gpu_blocks(myN/gpu_threads.x);
            if( myN % gpu_threads.x != 0 ) gpu_blocks.x+=1;

            //execute kernel
            kernel_0<<<gpu_blocks,gpu_threads>>>( d_a,  d_c, myN);

            //data transfer device to host
            CudaSafeCall(cudaMemcpy(c+my_start, d_c, nbytes_per_kernel, cudaMemcpyDeviceToHost));

            //sycnhronize devices
            CudaSafeCall(cudaDeviceSynchronize());

            // //free device memory
            CudaSafeCall(cudaFree(d_a));
            CudaSafeCall(cudaFree(d_c));
        }
当分配两个或多个GPU来运行这个类时,我会收到不同的错误消息,有时它只是挂起,什么也不做。当我通过nvidia smi检查GPU状态时,它显示GPU正在执行这个类,但是利用率为0%

一些错误包括:

cudaSafeCall() failed at mini.cu:221 : invalid argument
cudaSafeCall() failed at mini.cu:221 : driver shutting down

我可以想象,
hybrid\u function\u 0
中的设备变量声明应该移动到主OpenMP并行部分中,类似这样:

#pragma omp parallel
{
    unsigned int cpu_thread_id = omp_get_thread_num();
    unsigned int num_cpu_threads = omp_get_num_threads();

    //device variable declarations
    double *d_a;
    double *d_c;
    ...
目前,线程之间存在内存竞争,这可能导致其他线程使用错误设备的分配覆盖设备变量指针值,从而导致在使用设备指针作为参数的API调用中报告的各种无效参数错误


我预计该错误可能发生在
cudaMemset
cudaMemcpy
、或
cudaFree
调用或该函数中的内核启动时,并且根据竞争线程的行为,错误可能会从一个位置移动到另一个位置。

在询问“为什么该代码不工作?”您应提供第1项中所示的。您的MCVE应该是一个完整的代码,其他人可以编译、运行和查看问题,而无需添加任何内容或更改任何内容。@RobertCrovella感谢您指出缺少的内容。现在,我已经提供了完整的示例以及编译说明。“但是,当我用两个GPU测试它时,它不起作用。”如果您定义这意味着什么,这将是一件好事。你对工作和不工作的定义是什么。该计划是否产生了一系列预期结果?在非工作情况下,它是否抛出任何类型的错误?如果我运行了你的代码,我怎么知道它是否正常工作?如果你查看系统类,在构造函数中我创建了两个GPU实例,一个id为0,一个id为1。然后我使用system类来获取PUs的数量,并设置cuda设备id。因此,如果在这个构造函数中我只有一个GPU,无论是0还是1,它工作正常,程序执行到最后。但当我使用多个GPU时,有时程序会挂起,无法继续,有时还会抛出错误。当输出抛出错误时,我已经附加了输出。我们应该猜mini.cu中的221是什么链接吗?嗨@Talonmes。你的答案似乎是正确的。我确实尝试过,现在我没有运行时错误,我可以使用多个GPU。非常感谢。
nvcc mini.cu -o mini -Xcompiler "-fopenmp"
cudaSafeCall() failed at mini.cu:221 : invalid argument
cudaSafeCall() failed at mini.cu:221 : driver shutting down
#pragma omp parallel
{
    unsigned int cpu_thread_id = omp_get_thread_num();
    unsigned int num_cpu_threads = omp_get_num_threads();

    //device variable declarations
    double *d_a;
    double *d_c;
    ...