为什么数据迁移(D 到 H)在内核启动之前开始?

Why data migration (D to H) started before kernel launch?

以下是 nvvp 基于 CUDA 托管内存的代码的分析结果:

问题: 如上面的屏幕截图所示,数据迁移(D 到 H)甚至在内核启动之前就开始了。尽管与需要传输的总数据(约 4 MB)相比,第一个数据迁移块(在内核启动之前开始)的大小非常小(约 450kb)。那么,这个数据到底是什么?如何在发布前进行数据迁移(D 到 H)?

我的代码:

#include <iostream>
#include <math.h>

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

// CUDA kernel to add elements of two arrays
__global__
void add(int n, float* x, float* y)
{
    int index = blockIdx.x * blockDim.x + threadIdx.x;
    int stride = blockDim.x * gridDim.x;
    for (int i = index; i < n; i += stride)
        y[i] = x[i] + y[i];
}


int RunManagedVersion()
{
    int N = 1 << 20;
    float* x, * y;

    // Allocate Unified Memory -- accessible from CPU or GPU
    cudaMallocManaged(&x, N * sizeof(float));
    cudaMallocManaged(&y, N * sizeof(float));

    // initialize x and y arrays on the host
    for (int i = 0; i < N; i++) {
        x[i] = 1.0f;
        y[i] = 2.0f;
    }

    // Launch kernel on 1M elements on the GPU
    int blockSize = 256;
    int numBlocks = (N + blockSize - 1) / blockSize;
    add << <numBlocks, blockSize >> > (N, x, y);

    // Wait for GPU to finish before accessing on host
    cudaDeviceSynchronize();

    // Check for errors (all values should be 3.0f)
    float maxError = 0.0f;
    for (int i = 0; i < N; i++)
        maxError = fmax(maxError, fabs(y[i] - 3.0f));

    std::cout << "Max error: " << maxError << std::endl;

    // Free memory
    cudaFree(x);
    cudaFree(y);

    return 0;
}

int main()
{
    //RunUnmanagedVersion();

    RunManagedVersion();

    return 0;
}

探查器不会将此类 D->H 传输定位到特定时间点。

相反,它将时间线分成大致固定的时间段,并确定在该段期间是否发生了任何 D->H 传输。如果是这样,该段将被报告为“其中”有 D->H 传输,并且该段将用颜色编码以指示该段内传输的相对“密度”。

因此,您所指的绿色条的开始不一定是 D->H 转移发生的时刻,而是测量段的开始,在此期间一些 D->H 转移activity 发生了。

由于绿色条段在内核完成后延伸得很好,它显然在内核完成后解释了 D->H 传输 activity,这是预期的。

(关于内核启动之前、期间和之后的 H->D 线和蓝色条可能会提出类似的问题。显然不需要 H->D activity 内核启动后。同样,activity是根据固定时间段测量和报告的。)

顺便说一下(对于未来的读者),解释了内核启动之前的数据迁移 (D->H) here