为什么数据迁移(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。
以下是 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。