在我的CUDA运行时间计划中,CPU和GPU可以异步计算,但不能合作地计算

In my cuda program of runtime ,the cpu and gpu can compute Asynchronously,but not cooperatively,why?

本文关键字:计算 异步 但不能 运行时间 CUDA 我的 计划 CPU GPU      更新时间:2023-10-16

在我的CUDA程序程序中,CPU和GPU可以异步计算,但不能合作计算,为什么?

i测量程序的时间,总时间是CPU计算时间和GPU计算时间的总和时间。通过视觉轮廓,我发现GPU在CPU完成之前不计算。我的目的是CPU计算为GPU计算的同一时间。

平台:窗口10
CUDA 7.5
VS2013

以调试模式编译的代码(无优化)

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include<time.h>
__global__ void addKernel()
{
    int a ;
    for (int i = 0; i < 10000;i++)
    for (int j = 0; j < 10000;j++)
        a = i;
}
void comput()
{
    int a = 1;
    for (int i = 0; i < 10000;i++)
        for (int j = 0; j < 10000; j++)
        {
            for (int k = 0; k < 100;k++)
                a = j;
        }
}
int main()
{
    cudaSetDevice(0);
    cudaEvent_t start, stop1;
    cudaEventCreate(&start);
    cudaEventCreate(&stop1);
    clock_t ss = clock();
    cudaEventRecord(start,0);   
    addKernel<<<1,64>>>();
    cudaEventRecord(stop1,0);   
    clock_t ct = clock();
    comput();
    clock_t ctt = clock();
    cudaEventSynchronize(stop1);
    cudaDeviceSynchronize();
    clock_t sss = clock();
    float t1;
    cudaEventElapsedTime(&t1, start, stop1);
    printf("clock GPU :%.4f sn", t1/1000);
    printf("clock cpu:%f sn",(float) (ctt - ct)/CLOCKS_PER_SEC);
    printf("clock total time: %f sn", (float)(sss - ss) / CLOCKS_PER_SEC);
    cudaEventDestroy(start);
    cudaEventDestroy(stop1);
    cudaDeviceReset();
}

在这里有几个问题(可能):

  • 如果您使用的是WDDM驱动程序(与TCC驱动程序相反),则将划分内核,以减少WDDM驱动程序更高的启动开销的效果。这意味着驾驶员将推迟addKernel()的发布等待更多工作,直到遇到cudaEventSynchronize() CALL.TARCE.T。但是,到此时comput()已经完成。
    因此,在您的示例中,CPU和GPU的工作确实不同行,但是GPU上的addKernel()实际上在CPU上 comput()之后运行
    您可以通过在致电comput()之前插入cudaStreamQuery(0)的呼叫来防止(进一步)批处理并强制施加addKernel()

  • addKernel()compute()没有外部可见效果(它们仅设置局部变量a),并且可以由编译器完全优化。在调试模式下编译可能不会阻止所有这些优化。这将使您只能测量内核启动和正时开销,因此很难证明异步执行。
    因此,将它们替换为执行真实工作的代码,例如求和向量,并将结果存储到全局变量中。

  • 正如Halfelf在他的答案中指出的那样,Profiler可以在某些条件下同步启动内核。


⁾如果在一段时间内没有进一步的工作,等待也可能超时,并且addKernel()可能会在cudaEventSynchronize()呼叫之前启动。

来自CUDA编程指南:

程序员可以通过设置cuda_launch_blocking_blocking环境变量可变量为1的所有CUDA应用程序的内核启动的异步性启动的异步性。。

内核启动是同步的,如果通过Profiler(Nsight,Visual Profiler)收集硬件计数器,除非启用并发的内核分析。如果异步内存副本涉及未锁定的主机存储器,则它们也将是同步的。

同样,如果没有优化,主机功能将运行很长时间,也许是百万次内核。如果有优化,它实际上不会运行并立即返回。

我建议尝试分别使用CUDA_LAUNCH_BLOCKING=1CUDA_LAUNCH_BLOCKING=0运行二进制,以测试运行时间。还将内核和主机功能修改为有意义的功能。