想要使用 cuda 内核执行循环直到用户取消

Want to execute a loop with cuda Kernel till user cancels

我想在 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 的 class 的一部分。我的想法是调用另一个成员函数,该函数将使用执行函数启动一个新的 CPU 线程,并在主函数中等待,直到用户输入一些内容以调用另一个设置 runthreads =false 的成员函数。因此线程将在下一个内核完成后完成。 我总是从 Visual Studio 收到错误消息。现在我想知道这是否可能,或者 CPU 是否忙于控制 GPU 执行?有人在 GPU 和 CPU 上有关于并行执行的多线程经验吗?或者我应该只在 while 循环中寻找用户输入?

GPU 上的执行与 CPU 上的执行是异步的。除了等待操作,您可以继续处理 CPU。同样取决于配置标志,请参阅 cudaSetDeviceFlags ,等待操作将使用或不使用 CPU 周期。

cudaDeviceScheduleSpin: Instruct CUDA to actively spin when waiting for results from the device. This can decrease latency when waiting for the device, but may lower the performance of CPU threads if they are performing work in parallel with the CUDA thread.

你想实现的是完全可行的(这里是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 post。本质上,您想使用 cuCtxSetCurrent API 调用将 cuda 环境附加到线程。最简单的方法是让您的所有 cuda 代码都由一个线程执行。