如何进行代码运行效率实测?

icbm 2006-11-13 05:26:50


我写了一段代码,想知道它的运行效率。因为一段代码的执行时间非差短,我想通过多次执行,最后求平均值的办法来得到代码的执行时间,从而得知代码的运行效率。

伪码是这样:

BeginTime = Now; // 记录起始时间

for (i=0; i< 100000; ++i) // 执行100000次
{
// 要测试运行效率的代码
Test;
}

EndTime = Now; // 记录结束时间

RunTime = (EndTime - BeginTime) / 100000; // 代码的执行时间



可是这样会有几个问题:
1、最后记录的总时间中,既包括了Test运行的时间,也包括了for循环运行的时间。而实际上,我只是想知道Test运行的时间。特别是当Test与for循环运行时间相差不大的时候,误差会比较大。
2、CPU的流水操作会预测指令的执行,for循环过多的跳转会导致CPU预测不准确,从而增加了运行总时间误差。


我修改了伪码,使它变成这样:

BeginTime = Now; // 记录起始时间

for (i=0; i< 10000; ++i) // 执行10000次
{
// 要测试运行效率的代码,运行10次
Test;
Test;
Test;
Test;
Test;
Test;
Test;
Test;
Test;
Test;
}

EndTime = Now; // 记录结束时间

RunTime = (EndTime - BeginTime) / 100000; // 代码的执行时间

我的结论:

1、这样减少了for循环运行的次数,从而减小了for循环执行时间带来的误差。
2、减少了for循环执行的跳转,从而减少for循环的跳转会导致CPU预测不准确的增加的负担。

我得出个结论,尽量减少for的执行次数,会使得到的实测结果更准确。于是最后的伪码成了这样:


BeginTime = Now; // 记录起始时间

// 要测试运行效率的代码,运行100000次
Test;
Test;
Test;
Test;
Test;
Test;
Test;
Test;
Test;
Test;
... ... // Test;共100000行。余下省略

EndTime = Now; // 记录结束时间

RunTime = (EndTime - BeginTime) / 100000; // 代码的执行时间

结果最后的源代码和编译后的可执行程序非常大。不知各位有什么好的办法、建议。欢迎大家指点、讨论。

...全文
382 8 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
LiChenYue 2006-11-24
  • 打赏
  • 举报
回复
你的办法其实很好了!
顶一下!
蹭点分!
creamymami 2006-11-13
  • 打赏
  • 举报
回复
用个频率为1的CPU做试验
icbm 2006-11-13
  • 打赏
  • 举报
回复
谢谢 jixingzhong(瞌睡虫·星辰) !:) 不知还有没有其它的办法,集思广义啊。
icbm 2006-11-13
  • 打赏
  • 举报
回复
我只想知道如何准确测试代码的执行时间。

因为理论上的代码执行效率可以通过算法复杂度来估算,但代码的实际执行受到不同种类的CPU的指令、缓存命中率、指令分支预测准确性等等,有的时候差别会很大。这些都很难估计。

这时,只能通过实测来比较相同功能的不同代码,来判定代码的执行效率。希望尽量避免代码执行环境的影响,尽量准确的测试代码的执行时间。

这种实测办法是我自己想出来的。我没有查到相关的资料,所以很想和大家交流一下。看看大家的意见。
jixingzhong 2006-11-13
  • 打赏
  • 举报
回复
方式七:对于精确度要求更高的定时操作,则应该使用QueryPerformanceFrequency()和 QueryPerformanceCounter()函数。这两个函数是VC提供的仅供Windows 95及其后续版本使用的精确时间函数,并要求计算机从硬件上支持精确定时器。如示例工程中的Timer7、Timer7_1、Timer7_2、Timer7_3。
QueryPerformanceFrequency()函数和QueryPerformanceCounter()函数的原型如下:
BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
BOOL QueryPerformanceCounter(LARGE_INTEGER *lpCount);
  数据类型ARGE_INTEGER既可以是一个8字节长的整型数,也可以是两个4字节长的整型数的联合结构, 其具体用法根据编译器是否支持64位而定。该类型的定义如下:
typedef union _LARGE_INTEGER
{
struct
{
DWORD LowPart ;// 4字节整型数
LONG HighPart;// 4字节整型数
};
LONGLONG QuadPart ;// 8字节整型数

}LARGE_INTEGER ;
  在进行定时之前,先调用QueryPerformanceFrequency()函数获得机器内部定时器的时钟频率, 然后在需要严格定时的事件发生之前和发生之后分别调用QueryPerformanceCounter()函数,利用两次获得的计数之差及时钟频率,计算出事件经 历的精确时间。下列代码实现1ms的精确定时:
LARGE_INTEGER litmp;
LONGLONG QPart1,QPart2;
double dfMinus, dfFreq, dfTim;
QueryPerformanceFrequency(&litmp);
dfFreq = (double)litmp.QuadPart;// 获得计数器的时钟频率
QueryPerformanceCounter(&litmp);
QPart1 = litmp.QuadPart;// 获得初始值
do
{
QueryPerformanceCounter(&litmp);
QPart2 = litmp.QuadPart;//获得中止值
dfMinus = (double)(QPart2-QPart1);
dfTim = dfMinus / dfFreq;// 获得对应的时间值,单位为秒
}while(dfTim<0.001);
  其定时误差不超过1微秒,精度与CPU等机器配置有关。 下面的程序用来测试函数Sleep(100)的精确持续时间:
LARGE_INTEGER litmp;
LONGLONG QPart1,QPart2;
double dfMinus, dfFreq, dfTim;
QueryPerformanceFrequency(&litmp);
dfFreq = (double)litmp.QuadPart;// 获得计数器的时钟频率
QueryPerformanceCounter(&litmp);
QPart1 = litmp.QuadPart;// 获得初始值
Sleep(100);
QueryPerformanceCounter(&litmp);
QPart2 = litmp.QuadPart;//获得中止值
dfMinus = (double)(QPart2-QPart1);
dfTim = dfMinus / dfFreq;// 获得对应的时间值,单位为秒
  由于Sleep()函数自身的误差,上述程序每次执行的结果都会有微小误差。下列代码实现1微秒的精确定时:
LARGE_INTEGER litmp;
LONGLONG QPart1,QPart2;
double dfMinus, dfFreq, dfTim;
QueryPerformanceFrequency(&litmp);
dfFreq = (double)litmp.QuadPart;// 获得计数器的时钟频率
QueryPerformanceCounter(&litmp);
QPart1 = litmp.QuadPart;// 获得初始值
do
{
QueryPerformanceCounter(&litmp);
QPart2 = litmp.QuadPart;//获得中止值
dfMinus = (double)(QPart2-QPart1);
dfTim = dfMinus / dfFreq;// 获得对应的时间值,单位为秒
}while(dfTim<0.000001);
其定时误差一般不超过0.5微秒,精度与CPU等机器配置有关。
jixingzhong 2006-11-13
  • 打赏
  • 举报
回复
否则可以这样,
记录一个 空的 for (i=0; i< 10000; ++i) // 执行10000次
运行时间,
然后把你的 for 减去这个纯粹的for,
结果就是了 ~~

不过空的for可能时间很少,
需要比较精确,
如果是在 Win 下,
使用 QueryPerformanceFrequency()和 QueryPerformanceCounter()函数 ...
jixingzhong 2006-11-13
  • 打赏
  • 举报
回复
一般上来说,
你要测试的代码如果说运行时间都接近这个 for 本身了,
那么这个效率是相当的高了 ....

相比而言,
需要测试的时候,
程序可能是在 效率要求门槛上的,
如果结果显然符合要求, 那还做什么呢 ?
jixingzhong 2006-11-13
  • 打赏
  • 举报
回复
for 循环本身基本不需要什么时间 ....

它不就是一个条件判断 加 一个++操作么 ...

70,023

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧