当前位置: 技术问答>linux和unix
如何利用time命令对程序进行全面统计——原创
来源: 互联网 发布时间:2017-01-24
本文导语: 简单说一下起因,前两天做ACM的时候总是超时,所以就想自己测试一下程序的执行效率,就想到了time命令,然后又无意间发现fedora的time命令和freebsd的time命令不太一样,freebsd的time命令有更全面的内容,比如驻留集大...
简单说一下起因,前两天做ACM的时候总是超时,所以就想自己测试一下程序的执行效率,就想到了time命令,然后又无意间发现fedora的time命令和freebsd的time命令不太一样,freebsd的time命令有更全面的内容,比如驻留集大小,IO次数等等,于是我就想fedora能不能也做到这一点,就来csdn上问,竟没人回答,最终还是自己解决了这个问题,有个朋友发帖让我详细分享一下,于是乎我就把详细过程以及一些必要的资料分享一下:
1、linux原始的time命令是这样的:
real 0m0.000s(实际运行时间)
user 0m0.000s(用户态时间——相当于level3时间)
sys 0m0.000s(核心态时间——相当于level0时间)
它只显示了3个时间,但实际上它隐藏了cpu使用率这么一个数据没有显示,如果你想显示这个数据,可以通过建立TIMEFORMAT变量来指定time的显示格式,以下是我定义的格式:
export TIMEFORMAT=$'nRealTime=%3lR UserTime=%3lU SysTime=%3lS CPU=%P%%'
显示:
RealTime=0m0.019s UserTime=0m0.006s SysTime=0m0.014s CPU=103.35%
(顺便说一下,cpu使用率就是UserTime+SysTime/RealTime的比值,如果你的电脑是多核心的话,这个值有可能超过100%)
(如果你对系统自带time的需求已经满足的话,那么下面的内容可以忽略)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2、如何让time统计更多的数据?
这4项内容已经是fedora自带的time命令的全部功能了,如果想统计更多的数据,就需要新的工具,叫做GNU time 1.7,是gun自己开发的time命令,反正fedora不自带这个命令,其他linux系统有没有我不知道,它的下载地址是:
http://ftp.gnu.org/gnu/time/
拿到源码,编译安装就可以了,不过问题时fedora自带的time命令是/usr/bin/time,自己安装的time1.7是/usr/local/bin/time(默认),两个time重名,而且奇怪的是/usr/bin/time无法删除,删除完以后又自动生成,也没法替换,替换完还是原来的time命令,表示非常不解,请高手指点……
没办法,只能给自己装的time改名成time1.7,然后用alias直接屏蔽掉系统自带的time,当然你也可以不屏蔽,换一个其他的名字,让两个命令共用……
具体的设置参考:http://linux.about.com/library/cmd/blcmdl1_time.htm
或者中文版:http://www.360doc.com/content/11/1108/08/1671317_162679287.shtml
其实网上资料很多的,我当时参考的是上面的两个……
然后大家可以time -v ps 查看一下功能:
Command being timed: "ps"
User time (seconds): 0.00
System time (seconds): 0.02
Percent of CPU this job got: 92%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.02
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 3616
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 272
Voluntary context switches: 1
Involuntary context switches: 4
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
相当给力哈,基本上你想知道的内容都统计在这里了,具体的含义,可以参照上面给的两个网址,里面有详细的介绍,其实安装完以后,有一个info文件,还有什么比官方的info更全面的呢?
但是由于系统提供的-v参数是纵向打印,会把程序自身的打印结果刷掉,所以我自定义了一下新time的格式:
export TIME=$'nRealTime=%EstUserTime=%UstSysTime=%SstCPU=%PnMemeryAvg=% KkbtDataAvg=%DkbtStackAvg=%kbtSharedAvg=%XkbnResidentSetMax=%MkbtReside ntSetAvg=%tkbtPageSize=%ZbnMajorPageFault=%FtimstMinorPageFault=%Rtimest Swapped=%WtimesnContext-SwitchedInvoluntarily=%ctimestContext-SwitchedVolu ntarily=%wtimesnFileSystemInput:%ItimestFileSystemOutput=%OtimesnSocketMs gReceived=%rtimestSocketMsgSent=%stimesnSignalsDelevered=%ktimesttExitSt atusOfCommand=%x'
懒得自己写格式的同学,可以cp下去直接用……
注意,新的time命令默认使用的变量时TIME而不再是TIMEFORMAT了,这其实为我们同时使用两个time命令提供了便利,看一下格式化后的结果:
RealTime=0:00.01s UserTime=0.00s SysTime=0.01s CPU=89%
MemeryAvg=0kb DataAvg=0kb StackAvg=0b SharedAvg=0kb
ResidentSetMax=3616kb ResidentSetAvg=0kb PageSize=4096b
MajorPageFault=0tims MinorPageFault=270times Swapped=0times
Context-SwitchedInvoluntarily=3times Context-SwitchedVoluntarily=1times
FileSystemInput:0times FileSystemOutput=0times
SocketMsgReceived=0times SocketMsgSent=0times
SignalsDelevered=0times ExitStatusOfCommand=0
短了很多,对吧,目的达到了……
(至此,time的替换工作基本完成,不过这个time的提供的时间只能精确到10ms,不想系统自带的time可以精确到1ms,如果你已经满足于这个结果,那么下面的内容可以忽略,因为下面我们要去修改源代码)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3、让time的时间更精确
其实修改源代码的过程极度简单,所以如果你有兴趣,可以尝试修改一下,毕竟精度少一位总让人感觉非常的难受……
打开time-1.7目录(也就是刚才编译时的那个目录),打开time.c文件:
376行:fprintf (fp, "%ld:%02ld.%02ld", /* -> m:s. */
改为:fprintf (fp, "%ld:%02ld.%03ld", /* -> m:s. */(把最后一个2变成3即可)
379行:resp->elapsed.tv_usec / 10000);
改为:resp->elapsed.tv_usec / 1000);(删除一个0即可)
411行:fprintf (fp, "%ld.%02ld",
改为:fprintf (fp, "%ld.%03ld",(同样,把最后一个2变成3即可)
413行:resp->ru.ru_stime.TV_MSEC / 10);
改为:resp->ru.ru_stime.TV_MSEC);(把“/10”删掉)
416行:fprintf (fp, "%ld.%02ld",
改为:fprintf (fp, "%ld.%03ld",(还是一样,把最后一个2变成3即可)
418行:resp->ru.ru_utime.TV_MSEC / 10);
改为:resp->ru.ru_utime.TV_MSEC);(和413行的方法完全一样,删掉“/10”)
OK~
然后重新编译,重复一遍上面的工作,新的time命令就完成了,非常简单是吧,其实有编程经验的人一眼就能看出来,我只不过是在打印的时候,提高了1位精度而已,因为计时已经达到了微秒级的精度,但只显示10ms级的精度,所以其实精度的提升空间还很大的,有兴趣的同学可以进一步修改,时间完全可以达到us级别,只是我觉得ms对我就够用了,所以就没再去改……
再来看看新的命令吧:
Command being timed: "ps"
User time (seconds): 0.002
System time (seconds): 0.026
Percent of CPU this job got: 93%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.030
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 3632
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 273
Voluntary context switches: 1
Involuntary context switches: 8
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
看到没?精度已经提升为ms级别了……
(没啦,没啦,下面就是结束语啦!)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
至此,time的更新换代工作就全部完成了,我们可以得到的统计数据变得好多哈……
这为我们调试和测试程序提供了很大的便利……
谁说linux下没有好的测试软件,gdb+time+script就是相当NB的测试三件套,你完全可以通过驻留集的大小来判断是否有内存泄漏,通过IO次数的统计判断外排序的效率如何,总之,time只是提供了工具,怎么用这些工具,就全凭大家的想象力了……
不过值得强调的一点就是,time并不是专业的测试工具,它只是进行简单的整体统计,而且这个统计的过程会对程序的执行产生一些微小的影响,所以这个数据只能作为一种参考,协助你完善你的程序,最终的结果还是需要专业的测试环境以及实际投入使用时的运行结果来衡量……
1、linux原始的time命令是这样的:
real 0m0.000s(实际运行时间)
user 0m0.000s(用户态时间——相当于level3时间)
sys 0m0.000s(核心态时间——相当于level0时间)
它只显示了3个时间,但实际上它隐藏了cpu使用率这么一个数据没有显示,如果你想显示这个数据,可以通过建立TIMEFORMAT变量来指定time的显示格式,以下是我定义的格式:
export TIMEFORMAT=$'nRealTime=%3lR UserTime=%3lU SysTime=%3lS CPU=%P%%'
显示:
RealTime=0m0.019s UserTime=0m0.006s SysTime=0m0.014s CPU=103.35%
(顺便说一下,cpu使用率就是UserTime+SysTime/RealTime的比值,如果你的电脑是多核心的话,这个值有可能超过100%)
(如果你对系统自带time的需求已经满足的话,那么下面的内容可以忽略)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2、如何让time统计更多的数据?
这4项内容已经是fedora自带的time命令的全部功能了,如果想统计更多的数据,就需要新的工具,叫做GNU time 1.7,是gun自己开发的time命令,反正fedora不自带这个命令,其他linux系统有没有我不知道,它的下载地址是:
http://ftp.gnu.org/gnu/time/
拿到源码,编译安装就可以了,不过问题时fedora自带的time命令是/usr/bin/time,自己安装的time1.7是/usr/local/bin/time(默认),两个time重名,而且奇怪的是/usr/bin/time无法删除,删除完以后又自动生成,也没法替换,替换完还是原来的time命令,表示非常不解,请高手指点……
没办法,只能给自己装的time改名成time1.7,然后用alias直接屏蔽掉系统自带的time,当然你也可以不屏蔽,换一个其他的名字,让两个命令共用……
具体的设置参考:http://linux.about.com/library/cmd/blcmdl1_time.htm
或者中文版:http://www.360doc.com/content/11/1108/08/1671317_162679287.shtml
其实网上资料很多的,我当时参考的是上面的两个……
然后大家可以time -v ps 查看一下功能:
Command being timed: "ps"
User time (seconds): 0.00
System time (seconds): 0.02
Percent of CPU this job got: 92%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.02
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 3616
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 272
Voluntary context switches: 1
Involuntary context switches: 4
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
相当给力哈,基本上你想知道的内容都统计在这里了,具体的含义,可以参照上面给的两个网址,里面有详细的介绍,其实安装完以后,有一个info文件,还有什么比官方的info更全面的呢?
但是由于系统提供的-v参数是纵向打印,会把程序自身的打印结果刷掉,所以我自定义了一下新time的格式:
export TIME=$'nRealTime=%EstUserTime=%UstSysTime=%SstCPU=%PnMemeryAvg=% KkbtDataAvg=%DkbtStackAvg=%kbtSharedAvg=%XkbnResidentSetMax=%MkbtReside ntSetAvg=%tkbtPageSize=%ZbnMajorPageFault=%FtimstMinorPageFault=%Rtimest Swapped=%WtimesnContext-SwitchedInvoluntarily=%ctimestContext-SwitchedVolu ntarily=%wtimesnFileSystemInput:%ItimestFileSystemOutput=%OtimesnSocketMs gReceived=%rtimestSocketMsgSent=%stimesnSignalsDelevered=%ktimesttExitSt atusOfCommand=%x'
懒得自己写格式的同学,可以cp下去直接用……
注意,新的time命令默认使用的变量时TIME而不再是TIMEFORMAT了,这其实为我们同时使用两个time命令提供了便利,看一下格式化后的结果:
RealTime=0:00.01s UserTime=0.00s SysTime=0.01s CPU=89%
MemeryAvg=0kb DataAvg=0kb StackAvg=0b SharedAvg=0kb
ResidentSetMax=3616kb ResidentSetAvg=0kb PageSize=4096b
MajorPageFault=0tims MinorPageFault=270times Swapped=0times
Context-SwitchedInvoluntarily=3times Context-SwitchedVoluntarily=1times
FileSystemInput:0times FileSystemOutput=0times
SocketMsgReceived=0times SocketMsgSent=0times
SignalsDelevered=0times ExitStatusOfCommand=0
短了很多,对吧,目的达到了……
(至此,time的替换工作基本完成,不过这个time的提供的时间只能精确到10ms,不想系统自带的time可以精确到1ms,如果你已经满足于这个结果,那么下面的内容可以忽略,因为下面我们要去修改源代码)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3、让time的时间更精确
其实修改源代码的过程极度简单,所以如果你有兴趣,可以尝试修改一下,毕竟精度少一位总让人感觉非常的难受……
打开time-1.7目录(也就是刚才编译时的那个目录),打开time.c文件:
376行:fprintf (fp, "%ld:%02ld.%02ld", /* -> m:s. */
改为:fprintf (fp, "%ld:%02ld.%03ld", /* -> m:s. */(把最后一个2变成3即可)
379行:resp->elapsed.tv_usec / 10000);
改为:resp->elapsed.tv_usec / 1000);(删除一个0即可)
411行:fprintf (fp, "%ld.%02ld",
改为:fprintf (fp, "%ld.%03ld",(同样,把最后一个2变成3即可)
413行:resp->ru.ru_stime.TV_MSEC / 10);
改为:resp->ru.ru_stime.TV_MSEC);(把“/10”删掉)
416行:fprintf (fp, "%ld.%02ld",
改为:fprintf (fp, "%ld.%03ld",(还是一样,把最后一个2变成3即可)
418行:resp->ru.ru_utime.TV_MSEC / 10);
改为:resp->ru.ru_utime.TV_MSEC);(和413行的方法完全一样,删掉“/10”)
OK~
然后重新编译,重复一遍上面的工作,新的time命令就完成了,非常简单是吧,其实有编程经验的人一眼就能看出来,我只不过是在打印的时候,提高了1位精度而已,因为计时已经达到了微秒级的精度,但只显示10ms级的精度,所以其实精度的提升空间还很大的,有兴趣的同学可以进一步修改,时间完全可以达到us级别,只是我觉得ms对我就够用了,所以就没再去改……
再来看看新的命令吧:
Command being timed: "ps"
User time (seconds): 0.002
System time (seconds): 0.026
Percent of CPU this job got: 93%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.030
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 3632
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 273
Voluntary context switches: 1
Involuntary context switches: 8
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
看到没?精度已经提升为ms级别了……
(没啦,没啦,下面就是结束语啦!)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
至此,time的更新换代工作就全部完成了,我们可以得到的统计数据变得好多哈……
这为我们调试和测试程序提供了很大的便利……
谁说linux下没有好的测试软件,gdb+time+script就是相当NB的测试三件套,你完全可以通过驻留集的大小来判断是否有内存泄漏,通过IO次数的统计判断外排序的效率如何,总之,time只是提供了工具,怎么用这些工具,就全凭大家的想象力了……
不过值得强调的一点就是,time并不是专业的测试工具,它只是进行简单的整体统计,而且这个统计的过程会对程序的执行产生一些微小的影响,所以这个数据只能作为一种参考,协助你完善你的程序,最终的结果还是需要专业的测试环境以及实际投入使用时的运行结果来衡量……
|
故障,散花!
gdb+time已经很利器了!
gdb+time已经很利器了!
|
再加上gprof+strace,功德圆满。