Nvidia Profiling NVPROF的CPU启动和GPU启动的开始和结束的边界在哪里?

时间:2019-05-14 22:54:21

标签: cuda gpu profiling nvprof nvvp

CPU和GPU(黄色块)中内核启动的开始和结束的定义是什么?它们之间的边界在哪里?

请注意,CPU和GPU中这些黄色块的开始,结束和持续时间是不同的。为什么vecAdd<<<gridSize, blockSize>>>(d_a, d_b, d_c, n);的CPU调用需要这么长时间?

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

// CUDA kernel. Each thread takes care of one element of c
__global__ void vecAdd(double *a, double *b, double *c, int n)
{
    // Get our global thread ID
    int id = blockIdx.x*blockDim.x+threadIdx.x;
    //printf("id = %d \n", id);

    // Make sure we do not go out of bounds
    if (id < n)
        c[id] = a[id] + b[id];
}

int main( int argc, char* argv[] )
{
    // Size of vectors
    int n = 1000000;

    // Host input vectors
    double *h_a;
    double *h_b;
    //Host output vector
    double *h_c;

    // Device input vectors
    double *d_a;
    double *d_b;
    //Device output vector
    double *d_c;

    // Size, in bytes, of each vector
    size_t bytes = n*sizeof(double);

    // Allocate memory for each vector on host
    h_a = (double*)malloc(bytes);
    h_b = (double*)malloc(bytes);
    h_c = (double*)malloc(bytes);

    // Allocate memory for each vector on GPU
    cudaMalloc(&d_a, bytes);
    cudaMalloc(&d_b, bytes);
    cudaMalloc(&d_c, bytes);

    int i;
    // Initialize vectors on host
    for( i = 0; i < n; i++ ) {
        h_a[i] = sin(i)*sin(i);
        h_b[i] = cos(i)*cos(i);
    }

    // Copy host vectors to device
    cudaMemcpy( d_a, h_a, bytes, cudaMemcpyHostToDevice);
    cudaMemcpy( d_b, h_b, bytes, cudaMemcpyHostToDevice);

    int blockSize, gridSize;

    // Number of threads in each thread block
    blockSize = 1024;

    // Number of thread blocks in grid
    gridSize = (int)ceil((float)n/blockSize);

    // Execute the kernel
    vecAdd<<<gridSize, blockSize>>>(d_a, d_b, d_c, n);

    // Copy array back to host
    cudaMemcpy( h_c, d_c, bytes, cudaMemcpyDeviceToHost );

    // Sum up vector c and print result divided by n, this should equal 1 within error
    double sum = 0;
    for(i=0; i<n; i++)
        sum += h_c[i];
    printf("final result: %f\n", sum/n);

    // Release device memory
    cudaFree(d_a);
    cudaFree(d_b);
    cudaFree(d_c);

    // Release host memory
    free(h_a);
    free(h_b);
    free(h_c);

    return 0;
}

CPU黄色块:

enter image description here

GPU黄色块:

enter image description here

1 个答案:

答案 0 :(得分:2)

请注意,您提到的是NVPROF,但是显示的图片来自nvvp-可视分析器。 nvprof是命令行分析器

GPU内核启动是异步的。这意味着CPU线程启动内核,但不等待内核完成。实际上,CPU活动实际上是将内核置于启动队列中-如果GPU上发生了其他任何事情,则内核的实际执行可能会延迟。

因此,就时间而言,CPU(API)活动与GPU活动之间没有定义的关系,只是CPU内核启动显然必须(至少稍微)在GPU内核执行之前。

CPU(API)黄色块表示CPU线程花费在对CUDA运行时库进行库调用中以启动内核的时间(即,将其放置在启动队列中)。此库调用活动通常具有与之相关的一些时间开销,范围为5-50微秒。该时间段的开始以到库中的调用开始为标志。该阶段的结束由库将控制权返回给您的代码(即内核启动后的下一行代码)的时间标记。

GPU黄色框代表内核在GPU上执行的实际时间段。黄色框的开始和结束以GPU上内核活动的开始和结束标记。这里的持续时间取决于内核中的代码在做什么以及需要多长时间。

我不认为以权威的方式在任何地方记录或解释GPU内核启动需要大约5-50微秒的CPU时间的确切原因,并且它是一个封闭的源库,因此您需要承认开销,因为您几乎无法控制。如果您设计运行时间很长的内核并进行大量工作,则这些开销可能会变得微不足道。