THE MOMENT, THE MEMENTO

2008年05月29日

Linux平台多线程程序中使用clock()计算程序执行时间存在问题

标签:, , — 吴德文 @ 17:08

今天在Linux下测试对一个程序使用openmp进行部分优化后的执行时间的比较。

根据之前在Windows下的经验,判断一个代码段执行的时间,是使用clock()函数在代码段的开始和结束分别产生一个clock_t的值,然后后者减去前者再除以CLOCKS_PER_SEC,得到一个秒值。

这次测试的时候发现了很奇怪的问题,使用openmp优化过后的执行时间居然比优化前的执行时间多了两倍,这个是令人百思不得其解的问题。

源程序为hw.c,分别使用icc hw.c -o icc_hw  和 icc hw.c -openmp -o omp_hw命令进行编译。执行后通过clock()方式的计算发现前者的执行时间为9.71秒,后者的为20.67秒。

刚开始对这种问题非常费解,以为是调度以及线程间同步的问题,于是使用sar监控CPU的使用情况,发现前者会100%的使用某个CPU,而后者在两个CPU上的使用率都只达到48%左右。

不知为什么忽然对这个clock()的计时产生了怀疑,用了身边一个秒表计算之后,发现后者的实际实行时间并没有达到20秒这么久,而只是13秒左右。

这就奇怪了,为什么13秒的时间会被计算成20秒呢。

在网络上查询了一些资料后,学会使用time命令来统计程序的执行时间,结果如下:

#time ./icc_hw icc && time ./omp_hw omp

time 9.710000

real    0m9.723s
user    0m8.156s
sys     0m1.566s

time 20.670000

real    0m13.057s
user    0m12.605s
sys     0m8.077s

以上分别为两个程序的执行情况,其中第一行是程序自身的输出,是使用clock()计算出来的时间,而后三行是time命令的结果。real是是实际的执行时间,即从程序开始到程序执行结束时所消耗的时间,包括CPU的用时。CPU用时被划分为user和sys两块:user值表示程序本身,以及它所调用的库中的子例程使用的时间(是否可以理解为usert态消耗的时间?);sys是由程序直接或间接调用的系统调用执行的时间(是否可以理解为系统态消耗的时间?)。可以看出,在单线程情况下通过clock()得到的时间和实际时间是比较相符的,而多线程情况下,就有差异了:clock()得到的时间约等于是user态下的时间与sys态下的执行时间之和,但由于并行的关系,可能有些时间是重叠的,因此最后实际的执行时间其实更短。

在单处理器上,real值和整个CPU用时之差,也就是real - ( user + sys )是所有延迟程序执行的因素的总和。在SMP上,这个值近似为real * number_of_processors - ( user + sys )。这些因素包括:

  • 调入程序文本和数据的IO操作
  • 获取程序实际使用内存的IO操作
  • 由其它程序消耗的CPU用时
  • 由操作系统消耗的CPU用时
  • Shell下处理计时相对来说很简单,它是以牺牲计时精确性为代价的。相比之下,在语言中进行处理就显得要复杂得多,但精度更高。

这段具体怎么回事还没怎么看懂,留待以后再做分析。至少现在明白一个事情,Linux下统计多线程程序的执行时间时,不能使用clock()的方法,再没有其他更好的办法前,可以使用shell 命令time,或者GNU的time命令(/usr/bin/time,精度要低一些)。

参考资料:


Related:

评论暂缺 »

还没有任何评论。

这篇文章上的评论 RSS feed TrackBack URI

留下评论

You must be logged in to post a comment.

Valid XHTML 1.1 Valid CSS! Creative Commons License WordPress 所驱动