最近C语言老师布置了一个作业,大致是分别用C语言编写归并排序和快速排序,然后用time命令来比较二者的执行效率。操作的数组是一个用rand()随机生成的长度为2000的一维数组。
这两个算法网上已经写烂了,我就不再说了。下面总结一下我学习在Linux下测试程序执行时间的过程。
首先最简单的方式是使用 time 命令,下面大致介绍一下这个命令的功能和用法。
time 命令可以执行目标程序/命令并计时,使用时的格式是:
time [-p] command [arguments...]
执行这个命令后,系统会执行相应的程序。执行结束后,打印程序的执行时间。可以先执行一下 date 命令来看一下它的输出情况:
arcane@ubuntu:~$ time date
2014年 03月 25日 星期二 18:47:23 CST
real 0m0.044s
user 0m0.000s
sys 0m0.000s
arcane@ubuntu:~$
可以看到,运行 time 命令后,系统先执行了 date ,然后输出了其执行的时间。其中执行时间分为3个部分,它们的意义如下:
real:实际执行时间。
user:用户CPU时间。
sys:系统CPU时间。
我们知道Linux是多任务的系统,所以实际执行时间一般大于用户CPU时间和系统CPU时间之和,因为期间系统会去执行其他任务。
知道 time 命令的基本用法之后,我测试了我写的两个排序程序(归并和快排),如下:
arcane@ubuntu:~/C_learning/lab2$ time ./lab2_3_1
1 9 14 17 18 21 26 26 27 36 36 37 39 41 44 50 51 52 53 59 60 61 67 69 76 77 81 8
3 87 89 90 91 98 99 103 107 112 115 122 132 145 146 150 151 153 154 155 159 1
…………
9857 9865 9869 9880 9880 9888 9909 9913 9914 9915 9916 9922 9928 9935 9939
9947 9948 9951 9955 9960 9976 9977 9983 9986 9987 9994 9999
real 0m0.004s
user 0m0.000s
sys 0m0.000s
--------------------------------------------------------------------------------------------------------------------------------
arcane@ubuntu:~/C_learning/lab2$ time ./lab2_3_2
0 0 2 9 16 19 29 31 34 46 51 52 60 69 83 85 87 89 90 91 94 100 108 108 113 119
129 130 139 150 154 160 176 178 178 181 184 201 204 207 210 221 223 224 232
…………
1 9891 9903 9910 9929 9933 9940 9949 9951 9952 9958 9959 9962 9963 9970 9
981 9986 9996
real 0m0.003s
user 0m0.000s
sys 0m0.000s
我们看到,由于程序本身很小,而且计算机的运算能力较强,完成一个长度为2000的数组的排序似乎太快了,根本很难获得太多有用的信息。重复测试的结果也不太一样。要知道用 time 进行计时本身也是耗时的,这时程序的执行时间越短那么误差便会越大,而且受到计算机当前状况的影响也会更大。
怎么办呢?我修改了两个程序,在程序的主体之外加了一个大循环,让排序算法连续运行3000次。测量累加了多次的排序时间可以有效地减小误差。如下(新代码还取消了输出结果部分的代码,以使运行时间更接近排序的时间):
arcane@ubuntu:~/C_learning/lab2$ time ./test1
real 0m1.659s
user 0m1.636s
sys 0m0.004s
-----------------------------------------------------------------------------------------------
arcane@ubuntu:~/C_learning/lab2$ time ./test2
real 0m0.892s
user 0m0.884s
sys 0m0.008s
多次测试,结果是接近的。可以相信快速排序具有比归并排序更高的排序效率。
上面的方法虽然可以很方便地测试程序的执行时间,但它也有一个短板,就是无法测试某个程序片段的执行时间。比如上面的例子中,3000次的循环中其实还包含了每一次初始化新的随机数组的时间。如果我们想要更细致地考察排序算法部分的运行时间该怎么办呢?
这里提供一种利用 clock() 函数来计算程序片段执行时间的同样简单的方法。
clock() 函数就是一个计时函数,它的功能是返回从程序启动到调用函数中占用的CPU时钟数,也就是说每过一个CPU时钟,调用 clock() 所返回的值就加1。其返回的数据类型是 clock_t,这是一个用于保存时间的数据类型 。
注意使用这个函数需要包含 time.h 。在 time.h 中还定义了一个常量:CLOCKS_PER_SEC,表示1秒钟有几个CPU时钟计时周期。不同的环境下可能不同,可以打印出来查看一下。
掌握了这些信息,我们就可以很方便地为程序段的执行时间计时了!
首先,我们声明两个clock_t类型的变量,如sta和fin,然后在需要计时的程序段始末分别调用clock()函数为它们赋值,然后就可以利用如下公式来计算程序段的运行时间了:
duration = (double)(finish - start) / CLOCKS_PER_SEC;
是不是很简单?看看最新的测试结果:
arcane@ubuntu:~/C_learning/lab2$ ./test1
1.540000 s
---------------------------------------------------------------------------
arcane@ubuntu:~/C_learning/lab2$ ./test2
0.770000 s
可以看出这样的计时结果比用 time 命令得到的时间要短,而少掉的部分就是与排序部分无关的时间。注意在标准c中,计时的最小单位是1毫秒,所以用这种方法得到的时间精度最高也是1毫秒。
以上就是我们测试程序运行的两种方法了。相信随着学习的深入,还可以学到更多更加精确的测试方法。