Time 测量CUDA程序和CUDA内核的运行时间时出现问题
目前,我有三种测量运行时间的方法,两种使用CUDA事件,另一种记录开始和结束UNIX。使用CUDA事件的方法测量两件事,一个测量整个外部循环时间,另一个测量所有内核执行时间的总和 代码如下:Time 测量CUDA程序和CUDA内核的运行时间时出现问题,time,cuda,Time,Cuda,目前,我有三种测量运行时间的方法,两种使用CUDA事件,另一种记录开始和结束UNIX。使用CUDA事件的方法测量两件事,一个测量整个外部循环时间,另一个测量所有内核执行时间的总和 代码如下: int64 x1, x2; cudaEvent_t start; cudaEvent_t end; cudaEvent_t s1, s2; float timeValue; #define timer_s cudaEventRecord(start, 0); #define timer_e cud
int64 x1, x2;
cudaEvent_t start;
cudaEvent_t end;
cudaEvent_t s1, s2;
float timeValue;
#define timer_s cudaEventRecord(start, 0);
#define timer_e cudaEventRecord(end, 0); cudaEventSynchronize(end); cudaEventElapsedTime( &timeValue, start, end ); printf("time: %f ms \n", timeValue);
cudaEventCreate( &start );
cudaEventCreate( &end );
cudaEventCreate( &s1 );
cudaEventCreate( &s2 );
cudaEventRecord(s1, 0);
x1 = GetTimeMs64();
for(int r = 0 ; r < 2 ; r++)
{
timer_s
kernel1<<<1, x>>>(gl_devdata_ptr);
cudaThreadSynchronize();
timer_e
sum += timeValue;
for(int j = 0 ; j < 5; j++)
{
timer_s
kernel2<<<1,x>>>(gl_devdata_ptr);
cudaThreadSynchronize();
timer_e
sum += timeValue;
timer_s
kernel3<<<1,x>>>(gl_devdata_ptr);
cudaThreadSynchronize();
timer_e
sum += timeValue;
}
timer_s
kernel4<<<y, x>>> (gl_devdata_ptr);
cudaThreadSynchronize();
timer_e
sum += timeValue;
}
x2 = GetTimeMs64();
cudaEventRecord(s2, 0);
cudaEventSynchronize(s2);
cudaEventElapsedTime( &timeValue, s1, s2 );
printf("elapsed cuda : %f ms \n", timeValue);
printf("elapsed sum : %f ms \n", sum);
printf("elapsed win : %d ms \n", x2-x1);
这些不是真正的变量名,也不是正确的内核名,我只是删除了一些以使代码更小
所以问题是,每种测量方法都给了我不同的总时间
我刚才运行的一些示例:
elapsed cuda : 21.076832
elapsed sum : 4.177984
elapsed win : 27
那么为什么会有如此巨大的差异呢?所有内核调用的总和约为4毫秒,其他18毫秒在哪里?CPU时间?cudaThreadSynchronize是一个开销非常大的操作,因为它必须等待GPU上的所有工作完成 如果按照以下方式构造代码,则应得到正确的结果:
int64 x1, x2;
cudaEvent_t start;
cudaEvent_t end;
const int k_maxEvents = 5 + (2 * 2) + (2 * 5 * 2);
cudaEvent_t events[k_maxEvents];
int eIdx = 0;
float timeValue;
for (int e = 0; e < 5; ++e)
{
cudaEventCreate(&events[e]);
}
x1 = GetTimeMs64();
cudaEventRecord(events[eIdx++], 0);
for(int r = 0 ; r < 2 ; r++)
{
cudaEventRecord(events[eIdx++], 0);
kernel1<<<1, x>>>(gl_devdata_ptr);
for(int j = 0 ; j < 5; j++)
{
cudaEventRecord(events[eIdx++], 0);
kernel2<<<1,x>>>(gl_devdata_ptr);
cudaEventRecord(events[eIdx++], 0);
kernel3<<<1,x>>>(gl_devdata_ptr);
}
cudaEventRecord(events[eIdx++], 0);
kernel4<<<y, x>>> (gl_devdata_ptr);
}
cudaEventRecord(eIdx++, 0);
cudaDeviceSynchronize();
x2 = GetTimeMs64();
cudaEventElapsedTime( &timeValue, events[0], events[k_maxEvents - 1] );
printf("elapsed cuda : %f ms \n", timeValue);
// TODO the time between each events is the time to execute each kernel.
// On WDDM a context switch may occur between any of the kernels leading
// to higher than expected results.
// printf("elapsed sum : %f ms \n", sum);
printf("elapsed win : %d ms \n", x2-x1);
int64-x1,x2;
cudaEvent\u t启动;
cudaEvent_t end;
常量int k_maxEvents=5+(2*2)+(2*5*2);
cudaEvent_t事件[k_maxEvents];
int-eIdx=0;
浮动时间值;
对于(int e=0;e<5;++e)
{
cudaEventCreate(&events[e]);
}
x1=GetTimeMs64();
cudaEventRecord(事件[eIdx++],0);
对于(int r=0;r<2;r++)
{
cudaEventRecord(事件[eIdx++],0);
内核1(gl_devdata_ptr);
对于(int j=0;j<5;j++)
{
cudaEventRecord(事件[eIdx++],0);
内核2(gl_devdata_ptr);
cudaEventRecord(事件[eIdx++],0);
内核3(gl_devdata_ptr);
}
cudaEventRecord(事件[eIdx++],0);
内核4(gl_devdata_ptr);
}
cudaEventRecord(eIdx++,0);
cudaDeviceSynchronize();
x2=GetTimeMs64();
CudaEventReleasedTime(&timeValue,事件[0],事件[k_maxEvents-1]);
printf(“已用cuda:%f ms\n”,时间值);
//TODO每个事件之间的时间是执行每个内核的时间。
//在WDDM上,上下文切换可能发生在任何内核之间
//以高于预期的结果。
//printf(“已用总和:%f ms\n”,总和);
printf(“经过的胜利:%d毫秒\n”,x2-x1);
在Windows上,一种更容易测量时间的方法是使用QueryPerformanceCounter和QueryPerformanceFrequency
如果您编写上述示例时没有将事件作为
#include "NvToolsExt.h"
nvtxRangePushA("CPU Time");
for(int r = 0 ; r < 2 ; r++)
{
kernel1<<<1, x>>>(gl_devdata_ptr);
for(int j = 0 ; j < 5; j++)
{
kernel2<<<1,x>>>(gl_devdata_ptr);
kernel3<<<1,x>>>(gl_devdata_ptr);
}
kernel4<<<y, x>>> (gl_devdata_ptr);
}
cudaDeviceSynchronize();
nvtxRangePop();
#包括“NvToolsExt.h”
nvtxRangePushA(“CPU时间”);
对于(int r=0;r<2;r++)
{
内核1(gl_devdata_ptr);
对于(int j=0;j<5;j++)
{
内核2(gl_devdata_ptr);
内核3(gl_devdata_ptr);
}
内核4(gl_devdata_ptr);
}
cudaDeviceSynchronize();
nvtxRangePop();
并在Nsight Visual Studio Edition 1.5-2.2 CUDA跟踪活动或Visual Profiler 4.0+中运行,所有时间都可用。GPU时间将比使用cudaEvents API收集的时间更精确。使用nvtxRangePush测量CPU时间范围是可选的。这也可以通过测量从示例中的第一个CUDA API到cudaDeviceSynchronize的结尾来实现。阅读您的答案后,我尝试了QueryPerformanceCounter,它工作了,从这里获得了函数:谢谢。
#include "NvToolsExt.h"
nvtxRangePushA("CPU Time");
for(int r = 0 ; r < 2 ; r++)
{
kernel1<<<1, x>>>(gl_devdata_ptr);
for(int j = 0 ; j < 5; j++)
{
kernel2<<<1,x>>>(gl_devdata_ptr);
kernel3<<<1,x>>>(gl_devdata_ptr);
}
kernel4<<<y, x>>> (gl_devdata_ptr);
}
cudaDeviceSynchronize();
nvtxRangePop();