CUDA 内核第二次快 运行 秒 运行 - 为什么?
CUDA kernel runs faster the second time it is run - why?
我正在用 CUDA 编写我的第一个真正的应用程序,我已经到了需要知道内核执行需要多长时间的地步。但是,正如标题所说,我不明白为什么在多次 运行 一个内核的应用程序中, second 启动内核所花费的时间很多比第一次用的时间短很多。
例如,在下面的代码中:
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <chrono>
#include <iostream>
#include <stdio.h>
void runCuda(unsigned int size);
__global__ void addKernel(const int arraySize)
{
1 + 1;
}
void doStuff(int arraySize)
{
auto t1 = std::chrono::high_resolution_clock::now();
addKernel <<<(arraySize + 31) / 32, 32 >>> (arraySize);
cudaDeviceSynchronize();
auto t2 = std::chrono::high_resolution_clock::now();
std::cout << "Duration: " << std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count() << '\n';
cudaDeviceReset();
}
int main()
{
doStuff(1e6);
doStuff(1e6);
return 0;
}
内核只做了一些基本的加法,调用了一百万次。上面程序的输出通常是这样的:
Duration: 1072
Duration: 97
这两个数字发生变化,但始终保持在 1000 和 100 左右。事实上,同一个内核 运行 第二次快得多对我来说毫无意义。
可能是因为您的 GPU/CPU 正在提高时钟速度,因为它有工作要做。 OS 日程安排也可能会干扰,但这不是您在这里遇到的主要问题。
像这样计时代码执行时间通常意味着至少对多次运行进行平均,如果你想做得更好,排除异常值。
我敢肯定,如果您再添加几行 doStuff(1e6);
行,它们将比第一个更接近第二个结果。
我没有在这个设置中工作,但很可能在第一个 运行 内核需要编译。 GPU 的着色器必须在 运行 时间内编译,因为每个设备编译它的方式略有不同。否则,您必须制作与设计一样多的可执行文件,再加上每个 OS 和任何其他有助于代码编译(驱动程序版本)的不同变体。
程序启动第一个 Cuda 内核时会产生开销。
当你检查内核
的运行时间时,你应该首先启动一个空白内核
您会发现,在您的第一个 运行 中,几乎所有额外的时间都花在了您的第一个 cudaMalloc() 上。这是一个初始化,它确定只能部分缓解的设备和交换和内存条件。
内核更好的计时方法可以参考《CUDA C++最佳实践指南》,如下代码:
cudaEvent_t start, stop;
float time;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord( start, 0 );
kernel<<<grid,threads>>> ( d_odata, d_idata, size_x, size_y,
NUM_REPS);
cudaEventRecord( stop, 0 );
cudaEventSynchronize( stop );
cudaEventElapsedTime( &time, start, stop );
cudaEventDestroy( start );
我正在用 CUDA 编写我的第一个真正的应用程序,我已经到了需要知道内核执行需要多长时间的地步。但是,正如标题所说,我不明白为什么在多次 运行 一个内核的应用程序中, second 启动内核所花费的时间很多比第一次用的时间短很多。
例如,在下面的代码中:
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <chrono>
#include <iostream>
#include <stdio.h>
void runCuda(unsigned int size);
__global__ void addKernel(const int arraySize)
{
1 + 1;
}
void doStuff(int arraySize)
{
auto t1 = std::chrono::high_resolution_clock::now();
addKernel <<<(arraySize + 31) / 32, 32 >>> (arraySize);
cudaDeviceSynchronize();
auto t2 = std::chrono::high_resolution_clock::now();
std::cout << "Duration: " << std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count() << '\n';
cudaDeviceReset();
}
int main()
{
doStuff(1e6);
doStuff(1e6);
return 0;
}
内核只做了一些基本的加法,调用了一百万次。上面程序的输出通常是这样的:
Duration: 1072
Duration: 97
这两个数字发生变化,但始终保持在 1000 和 100 左右。事实上,同一个内核 运行 第二次快得多对我来说毫无意义。
可能是因为您的 GPU/CPU 正在提高时钟速度,因为它有工作要做。 OS 日程安排也可能会干扰,但这不是您在这里遇到的主要问题。
像这样计时代码执行时间通常意味着至少对多次运行进行平均,如果你想做得更好,排除异常值。
我敢肯定,如果您再添加几行 doStuff(1e6);
行,它们将比第一个更接近第二个结果。
我没有在这个设置中工作,但很可能在第一个 运行 内核需要编译。 GPU 的着色器必须在 运行 时间内编译,因为每个设备编译它的方式略有不同。否则,您必须制作与设计一样多的可执行文件,再加上每个 OS 和任何其他有助于代码编译(驱动程序版本)的不同变体。
程序启动第一个 Cuda 内核时会产生开销。 当你检查内核
的运行时间时,你应该首先启动一个空白内核您会发现,在您的第一个 运行 中,几乎所有额外的时间都花在了您的第一个 cudaMalloc() 上。这是一个初始化,它确定只能部分缓解的设备和交换和内存条件。
内核更好的计时方法可以参考《CUDA C++最佳实践指南》,如下代码:
cudaEvent_t start, stop;
float time;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord( start, 0 );
kernel<<<grid,threads>>> ( d_odata, d_idata, size_x, size_y,
NUM_REPS);
cudaEventRecord( stop, 0 );
cudaEventSynchronize( stop );
cudaEventElapsedTime( &time, start, stop );
cudaEventDestroy( start );