想要用cuda Kernel执行一个循环,直到用户取消

时间:2016-04-29 13:16:35

标签: c++ cuda infinite-loop

我想并行计算GPU上的一些东西,并在每次内核调用之间显示结果。代码看起来像这样:

void execute(){
    runthread = true;
    float erg[128 * 2] = {};
    float *d_a, *d_b, *d_c, *d_erg;
    size_t sizeErg = sizeof(float) * 2 * N;
    size_t sizeAB = sizeof(float)*N;
    float c[2] = { 1, 2 };
    gpuErrchk(cudaMalloc((void**)&d_a, sizeAB));
    gpuErrchk(cudaMalloc((void**)&d_b, sizeAB));
    gpuErrchk(cudaMalloc((void**)&d_c, sizeof(float) * 2));
    gpuErrchk(cudaMalloc((void**)&d_erg, sizeErg));

    gpuErrchk(cudaMemcpy(d_a, anode, sizeAB, cudaMemcpyHostToDevice));
    gpuErrchk(cudaMemcpy(d_b, kathode, sizeAB, cudaMemcpyHostToDevice));
    gpuErrchk(cudaMemcpy(d_c, c, 2 * sizeof(float), cudaMemcpyHostToDevice));


    float time = 0;
    int i = 0;
    while (runthread){
        kernel<<<(N * 2) / 64, 64 >>>(d_a, d_b, d_c, d_erg, N);
        cudaDeviceSynchronize();
        gpuErrchk(cudaMemcpy(erg, d_erg, sizeErg, cudaMemcpyDeviceToHost));

        float acc = 0;
        for (int j = 0; j < N * 2; j++){
            acc += erg[j];
        }
        std::cout << "Erg" << i << "=" << acc << std::endl;
        std::cout << "Kernel Execution took" << time << "ms" << std::endl;
        i++;
    }
    cudaFree(d_a);
    cudaFree(d_b);
    cudaFree(d_c);
    cudaFree(d_erg);
}

此函数是bool变量runthread的类的一部分。我的想法是调用另一个成员函数,它将使用执行函数启动一个新的CPU线程并在main函数中等待,直到用户输入一些东西来调用另一个设置runthreads = false的成员函数。因此线程将在下一个内核完成后完成。 我总是从Visual Studio收到错误消息。现在我想知道这是否可能,或者CPU是否忙于控制GPU执行?有关GPU和CPU上的并行执行的多线程有没有人参与?或者我应该在while循环中查找userinput吗?

1 个答案:

答案 0 :(得分:3)

GPU上的执行与CPU上的执行是异步的。除了等待操作,您可以继续在CPU上进行处理。另外,根据配置标志,请参阅cudaSetDeviceFlags,等待操作将使用或不使用CPU周期。

  

cudaDeviceScheduleSpin:指示CUDA在等待设备结果时主动旋转。这可以减少等待设备时的延迟,但如果它们与CUDA线程并行执行工作,则可能会降低CPU线程的性能。

您想要实现的目标是完全可行的(这是Windows上的一个示例):

#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <stdio.h>

volatile int runthread ;

__global__ void kernel() { }

#include <Windows.h>


int execute(void* p)
{
    int count = 0 ;
    while (runthread)
    {
        kernel<<<1,1>>>();
        cudaDeviceSynchronize();
        ++count;
    }
    printf ("Executed kernel %d times\n", count);
    ::ExitThread(count);
    return count ;
}

int main()
{
    runthread = 1 ;

    HANDLE hThread = ::CreateThread (0, 0, (LPTHREAD_START_ROUTINE)execute, 0, 0, 0) ;

    printf ("Press key\n") ;
    int c = getc(stdin);

    printf ("Stopping\n") ;

    runthread = 0 ;

    ::WaitForSingleObject (hThread, INFINITE) ;

    printf ("DONE\n");
    return 0 ;
}

但是,您要小心执行cuda调用的线程,因为每个线程存储了一些cuda配置和状态元素。如果你想从不同的线程使用cuda,我推荐this帖子。实质上,您希望使用cuCtxSetCurrent API调用将cuda环境附加到线程。最简单的方法是让所有的cuda代码都由一个线程执行。