C++ CUDA内核在第二次运行时运行得更快-为什么?

C++ CUDA内核在第二次运行时运行得更快-为什么?,c++,parallel-processing,cuda,gpgpu,C++,Parallel Processing,Cuda,Gpgpu,我正在用CUDA编写我的第一个实际应用程序,现在我需要知道内核执行需要多长时间。但是,正如标题中所说,我不明白为什么在多次运行内核的应用程序中,内核第二次启动所花费的时间比第一次启动所花费的时间要短得多 例如,在下面的代码中: #include "cuda_runtime.h" #include "device_launch_parameters.h" #include <chrono> #include <iostream> #include <stdio.h&

我正在用CUDA编写我的第一个实际应用程序,现在我需要知道内核执行需要多长时间。但是,正如标题中所说,我不明白为什么在多次运行内核的应用程序中,内核第二次启动所花费的时间比第一次启动所花费的时间要短得多

例如,在下面的代码中:

#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;
}

这两个数字有所变化,但始终保持在1000和100左右。同一个内核第二次运行速度如此之快,这一事实对我来说毫无意义。

可能是因为您的GPU/CPU正在提高其时钟速度,因为它有工作要做。操作系统调度也可能会产生干扰,但这不是您在这里遇到的主要问题

这样对代码执行时间进行计时通常意味着至少对多次运行进行平均,如果您想做得更好,可以排除异常值


我确信,如果您再添加一些
doStuff(1e6)行,它们将比第一行更接近第二个结果。

我没有在这个设置中工作过,但很可能在第一次运行时内核需要编译。GPU的着色器必须在运行时编译,因为每个设计对它的编译略有不同。否则,您将不得不创建尽可能多的可执行文件,以及每个操作系统的不同变体,以及任何有助于代码编译(驱动程序版本)的其他内容。

当程序启动第一个Cuda内核时,会有开销。
当您检查内核的运行时间时,应该首先启动一个空白内核

您会发现,在第一次运行时,几乎所有额外的时间都花在了第一次cudamaloc()上。这是一个初始化,它决定了设备和交换和内存条件,只能部分减轻。

< P>内核中的更好的计时方法可以在“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 );
cudaEvent\u t启动、停止;
浮动时间;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(开始,0);
内核(d_odata、d_idata、size_x、size_y、,
次数(次);;
cudaEventRecord(停止,0);
CUDAEVENTS同步(停止);
CUDAEVENTERASEDTIME(时间、开始、停止(&T));
cudaEventDestroy(启动);

确实如此,第一次之后的所有结果始终在100毫秒左右。我怀疑您的答案可能是导致差异的原因,但另一方面,我担心会有一些非常低级的优化,在这种情况下,第二个结果实际上信息量会更少。谢谢你的回答!还有其他各种原因,包括驱动程序内核缓存、设备内存缓存等。除了它们可能存在之外,我不知道所有这些都是有用的。如果你从你的问题中删除CUDA,你会发现与普通C++完全相同的事情(如果你设法欺骗优化器而不是优化所有的东西),那么这至少是你需要考虑的一个基线特征。problem@talonmieswrt重新打开:请参阅。关于您的“与问题无关”评论,一个简单的CUDA少演示:。注意:我不是说我的答案包含完整答案,但它肯定是延迟的一部分。这与OP的观察无关。这是第一次调用时的延迟上下文初始化。看到被舔的人了吗duplicate@talonmies非常感谢。然而,我要说的是,我不同意标记此副本。我的问题是问“为什么会发生X?”,而链接的问题是问“X的发生是因为Y,你能告诉我如何避免Y吗?”。对我来说,这是两个不同的问题。就像我一样,另一个有同样问题的用户可能甚至不知道他们实际上在寻找你链接的问题…@Talonmes就像我上面说的,不,这个问题的答案不是“重复问题”的答案。链接问题的答案是“在第一次启动内核之前使用
cudaFree(0)
”。我的问题的答案是“发生这种情况是因为您尚未初始化GPU”。这两个答案虽然相似,但并不相同。如果开放式问题让你如此烦恼,请随意添加一个简短的答案,我会接受的。或者我可以自己做,如果没有其他答案出现,我计划这样做。或者投票关闭,在这种情况下,我想我们同意不同意。这就是为什么需要在计时之前调用预热内核。我同意@Talonmes的说法,这个问题是一个dup。@忘记,我的计划是在有时间写下这个问题后,给它添加一个答案。无法判断内核是否需要编译,因为OP没有提供编译信息,也没有提供关于它们运行的GPU的任何信息。但是,当然可以避免在运行时编译内核,即使在这种情况下,OP的观察仍然会持续,原因在对问题的评论中有所提及。很抱歉,在聚会上迟到了,但是你能添加一个“空白内核”的例子吗?我发现我的没有明显的效果<代码>无效内核预热(int*dummy){*dummy=1;}
<代码>内核预热(/*cuda ptr到int*/)我仍然认为提供一个示例会很有用,但事实证明我的问题与不预取内存有关,而不是冷启动。@EddInglis“blank kernel”也称为预热内核(在大多数情况下)。你可以在谷歌上搜索,或者看看这个
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 );