[linux][system] gettimeofday的几种实现方法

前言: 有同事讨论到gettimeofday的性能问题。想起来大约四五年前,在linux-2.6.x上的时候,用一种很极端的方法实现过time函数。 下面就简单分析一下几种gettimeofday的实现。当然,实现方法是包括但不限于以下。 分析: 1,int 0x80 在早期阶段,x86上的syscall通过int 0x80实现的。IRQ可以让CPU中断当前的处理,陷入到Ring0中,当触发的IRQ号是0x80的时候,就进入到了对应的handler里面处理。处理完成后,返回Ring3,用户态进程拿到结果。 目前的主流的x86,已经放弃这种使用方式了。因为成本比较高。 2,syscall intel后来提供了新的指令syscall,SDM介绍如下:

目前主流的CPU和Linux都是使用这种方式的。syscall相比于int 0x80,更加快速。 3,vDSO 有一些syscall,例如time、gettimeofday等,这些只是从kernel中请求数据,kernel的实现上,甚至只是把内核变量copy到用户buf上。那么,是不是可以不用陷入到kernel中处理,只要copy内存就行呢。vDSO的man介绍如下:

4,vsyscall LWN上有所介绍,https://lwn.net/Articles/446528/ The vsyscall area is the older of these two mechanisms. It was added as a way to execute specific system calls which do not need any real level of privilege to run. The classic example is gettimeofday(); all it needs to do is to read the kernel's idea of the current time. There are applications out there that call gettimeofday() frequently, to the point that they care about even a little bit of overhead. To address that concern, the kernel allows the page containing the current time to be mapped read-only into user space; that page also contains a fast gettimeofday() implementation. Using this virtual system call, the C library can provide a fast gettimeofday() which never actually has to change into kernel mode. 代码实现在linux/arch/x86/entry/vsyscall/vsyscall_64.c

目前x86上可以通过特定的地址访问到gettimeofday,time,getcpu三个syscall。 5,memory mapping 上文提到了那个非常极端的方法,本质来说和vDSO比较接近,但是更加激进一些。通过kallsymbol计算出来xtime的地址,然后通过/dev/mem做memory mapping,把xtime的地址直接映射到user space。 相比于vDSO,安全检查非常不好,也需要root权限。 这里不做实现。 6,benchmark 作者写了测试工具,https://github.com/pacepi/tool/blob/master/gettimeofday-bench.c 分别对比vDSO vs Vsyscall vs syscall的测试结果。 在笔记本Intel(R) Core(TM) i7-8550U上的测试结果: VDSO gettimeofday test 369098014 cycles, everage 36 cycles SYSCALL gettimeofday test 4813905443 cycles, everage 481 cycles VSYSCALL gettimeofday test 12802716166 cycles, everage 1280 cycles 虽然看起来三者有倍数甚至数量级的差别,但是,都是很小的范围内。 可见,syscall的实现上,已经比vDSO的实现没有太大的差距了。远不似当年相对比于int 0x80的性能提升了。 在skylake上测试,syscall大约只要320 cycles。 对于静态连接场景,可以放心大胆使用syscall了。

原文发布于微信公众号 - AlwaysGeek(gh_d0972b1eeb60)

原文发表时间:2018-12-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券