Linux clock source problem with Skylake-X processors

0x00

最近将一个在CentOS/RHEL 7.x下开发、运行的程序尝试移植到Ubuntu 16.04下,发现性能骤降,用perf top检查发现__vdso_clock_gettimeread_hpet的时间开销非常巨大。

0x01

Google搜了一圈:Two frequently used system calls are ~77% slower on AWS EC2
感觉是__vdso_clock_gettime没有能按照预期工作,而是每次都进内核读取硬件时钟。
但是我们的环境都是baremetal,并不是VM,理论上不应该是上述文中提到的原因。

0x02

因为代码中不少地方使用了clock_gettimeasiotimer,跟踪下去发现asio的底层使用了HPET,但是每个io_service仅使用了一个timerfd,大量的read_hpet应该是由clock_gettime调用的,一般来说clock_gettime不应该使用HPET这么高精度的时钟源。
顺着这个思路,发现两台机器的时钟源果然不同
$ cat /sys/devices/system/clocksource/clocksource0/current_clocksource
出问题的这台显示是hpet,而正常应该为tsc

再查看当前可用时钟源,发现竟然没有tsc
$ cat /sys/devices/system/clocksource/clocksource0/available_clocksource

离真相已经不远了。

0x03

出问题的是Intel Core i9-7900x(代号Skylake-X),怀疑是内核对新CPU的支持还不完善。
在 Kernel.org 的 Bugzilla 和 git log 里面发现类似的反馈:

Skylake-X的TSC晶振频率应该是25MHz,不是24MHz。内核在检测TSC时发现偏差,从而禁用了TSC,转用了HPET作为默认时钟源。

0x04

解决方案就是换最新的内核,我选用的是4.15.3,再验证可用时钟源和当前时钟源均为tsc无误,程序运行也恢复正常。

PS:至于开头__vdso_clock_gettime为何没有按照预期运行,而是每次都执行read_hpet,暂时未深入研究具体代码,以后有空再补……

Leave a Reply

Your email address will not be published. Required fields are marked *