概述
Linux内核中有两种不同的clock设备,一种是clock source设备,另一种是clock event设备。Clock source设备一般是一个根据固定频率不停增加的计数器,如STC,内核利用该设备可以计算出从系统启动到当前所经过的时间,再加上RTC所提供的初始时间就能得到当前时间(墙上时间)。Clock event设备则用来提供中断,Clock event设备可以配置为按固定周期发生中断(periodic)或者产生一个特定时间间隔后的中断(onshot)
————————————————
版权声明:本文为CSDN博主「colddown」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/colddown/article/details/38878909
RaymondSQ
让数据动起来
gettimeofday、clockgettime 以及不同时钟源的影响
我们写程序的时候经常会使用计时函数,比如RPC中计算超时时间,日志中打印当前时间,性能profile中计算某个函数的执行时间等。在使用时间函数的时候,我们一般默认认为时间函数本身的性能是很高的,对主逻辑的影响可以忽略不计。虽然绝大部分情况下这个假设都没问题,但是了解更多细节能够增加我们对问题的把控力,利于系统的设计和问题的调查。
首先来比较gettimeofday/clock_gettime的性能。
程序代码见后
Glibc版本:
$rpm -qa|grep glibc-comm
glibc-common-2.5-81
内核版本:
$uname -a
2.6.32-220.23.2
$./a.out -help
[gettimeofday/clock_gettime] thread_number loop_count
$./a.out gettimeofday 1 100000000
gettimeofday(50035480681901) , times : 100000000
thread 1105828160 consume 4000225 us
单线程gettimeofday大概每次40ns
图1看出,gettimeofday走的是vsyscall[1](虚拟系统粗糙的描述就是不经过内核进程的切换就可以调用一段预定好的内核代码),没有线程切换的开销。
图1 gettimeofday 走vsyscall
图2 gettimeofday能将usr态cpu消耗压到100%
因为走vsyscall,没有线程切换,所以多线程运行性能跟单线程是类似的。
$./a.out gettimeofday 12 100000000
gettimeofday(51127820371298) , times : 100000000
thread 1201568064 consume 4111854 us
$./a.out clock_gettime 1 100000000
clock_gettime(50265567600696623) , times : 100000000
thread 1107867968 consume 10242448 us
单线程clock_gettime大概每次100ns
图3 clock_gettime 走真正的系统调用
图4 clock_gettime 70%的cpu花在sys态,确实进入了系统调用流程
因为开销集中在系统调用本身,而不是花在进程切换上,所以多线程结果跟单线程类似。
$./a.out clock_gettime 12 100000000
clock_gettime(50369061997211567) , times : 100000000
thread 1122031936 consume 10226828 us
这里说“开销集中在系统调用本身”意思是说clock_gettime本身的执行就非常耗费时间,其大概的调用路径是
clock_gettime -> sys_call -> sys_clock_gettime -> getnstimeofday -> read_tsc -> native_read_tsc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
上面说到时钟源是可以替换的,
$cat /sys/devices/system/clocksource/clocksource0/available_clocksource
tsc hpet acpi_pm
这是所有可用的时钟源。硬件出问题或者内核bug有时候会使得tsc不可用,于是时钟源默认会切换到hpet,使用hpet后gettimeofday和clock_gettime性能如何?测试一下。
$sudo bash -c "echo hpet > /sys/devices/system/clocksource/clocksource0/current_clocksource"
$cat /sys/devices/system/clocksource/clocksource0/current_clocksource
hpet
$./a.out gettimeofday 1 100000000
gettimeofday(50067118117357) , times : 100000000
thread 1091926336 consume 71748597 us
延时是原来的17倍,大概700ns一次;clock_gettime 与此类似,因为此时瓶颈已经不是系统调用,而是hpet_read很慢。
此时大概的调用路径是
clock_gettime -> sys_call -> sys_clock_gettime -> getnstimeofday -> read_hpet -> hpet_readl –> readl
实现非常直白,但是readl是读时钟设备的内存映射,慢是肯定的了。
总结来说,上文制定的内核和glibc版本下,tsc时钟源,gettimeofday 比 clock_gettime快1倍多,适合做计时用(clock_gettime使用CLOCK_REALTIME_COARSE也是很快的);如果因为tsc不稳定(硬件或者内核bug都可能导致,碰到过),hpet一般不会同时出问题,这时hpet成为了新的时钟源,整体性能下降数十倍,两者没啥区别了。
[1]. On vsyscalls and the vDSO : http://lwn.net/Articles/446528/
[2]. Linux内核的时钟中断机制 : http://wenku.baidu.com/view/4a9f37f24693daef5ef73d32.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
|
最后
以上就是柔弱冥王星为你收集整理的linux系统 时钟源 起始值与步长增加两种类型RaymondSQ的全部内容,希望文章能够帮你解决linux系统 时钟源 起始值与步长增加两种类型RaymondSQ所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复