gettimeofday() 不使用 vDSO?

Roe*_*erg 3 amazon-ec2 linux-kernel vdso

我跟踪了一个 java 进程,该进程触发了大量内核时间来查看正在使用的系统调用,并且惊讶地看到它gettimeofday()clock_gettime()占主导地位(我怀疑这是由于日志记录),考虑到以下man vdso状态,这很奇怪:

使用strace (1)跟踪系统调用时,vDSO 导出的符号(系统调用)不会出现在跟踪输出中。

这些系统调用是怎么发生的?有没有办法避免它们?

该机器在 EC2 上运行 Ubuntu 16.04.1。

为方便起见,我用 C ( testgtod.c)创建了一个最小的测试程序:

#include <stdlib.h>
#include <sys/time.h>

void main(void)
{
    struct timeval tv;
    for(int i = 0; i < 1000; i++) {
        /* glibc wrapped, shouldn't actually syscall */
        gettimeofday(&tv, NULL);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我在strace下编译并运行程序: gcc testgtod.c -o testgtod && sudo strace ./testgtod

输出包括对 gettimeofday() 的一千次调用,尽管我有预料。

我测试过的东西以确保我看不到东西:

  1. 确保二进制文件是一个 64 位精灵使用 file

  2. ldd ./testgtod 确保 vDSO 处于活动状态:

    linux-vdso.so.1 => (0x00007ffcee25d000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6f6e161000) /lib64/ld-linux-x82-64.so.so. (0x0000559ed71f3000)

  3. getauxval(AT_SYSINFO_EHDR) != NULL

  4. gettimeofday(&tv, NULL)调用替换为 ,调用syscall(SYS_gettimeofday, &tv, NULL)次数增加到 1000 万次,运行time时行为在两种情况下都相同:./testgtod 0.16s user 0.83s system 99% cpu 0.998 total.

Roe*_*erg 5

该问题与运行在 Xen 上的 VM 有关,具体而言,Xen 时钟源尚不允许 vDSO 访问时钟:

ubuntu@machine:~% cat /sys/devices/system/clocksource/*/current_clocksource
xen
Run Code Online (Sandbox Code Playgroud)

然后,我将时钟源更改为tsc

ubuntu@machine:~% sudo sh -c "echo tsc >/sys/devices/system/clocksource/clocksource0/current_clocksource"
Run Code Online (Sandbox Code Playgroud)

注意:不建议tsc在生产机器上移动到时钟源,因为它可能导致时钟向后漂移。

请参阅https://blog.packagecloud.io/eng/2017/03/08/system-calls-are-much-slower-on-ec2/有关 vDSO 和时钟源之间交互的详细文章。

注 2tscXen 的支持似乎随着 4.0 版和 Sandy Bridge+ 平台对 CPU 的支持有所改进。现代 EC2 机器应该可以使用tsc. 使用dmesg | grep "Xen version". 亚马逊tsc在 re:Invent 2015 ( https://www.slideshare.net/AmazonWebServices/cmp402-amazon-ec2-instances-deep-dive ) 中推荐了时钟源。我还没有运行到生产中,但情况似乎没有 packagecloud 暗示的那么糟糕。

补充阅读:
为什么rdtsc与虚拟机交互不佳
Xen 的 4.0 rdtsc 更改了
Linux 内核计时文档,讨论了 TSC 的陷阱