gettimeofday和clock_gettime是不是系统调用?
在《Linux多线程服务端编程》一书5.1节中提到过,在x86-64的Linux上,gettimeofday
不是系统调用,不会陷入内核。其实这种说法有点小问题,因为gettimeofday
确实是个系统调用,但是linux的vdso(virtual dynamic shared object)机制帮我们做到了在调用这些系统调用时不陷入内核,从而提高了性能。
vdso机制说白了就是在用户空间帮我们实现了一些特定的系统调用,用户进程启动时这些代码会被自动映射到进程地址空间的用户空间中。这样的话,当我们利用vdso调用到这些系统调用时,就不会陷入内核了。如何调用到这些代码呢?直接调用这些系统调用对应的glibc包装函数就可以,因为这些glibc包装函数默认会使用vdso。如果你执意通过syscall
函数/syscall
指令/int 0x80
来调用这些系统调用,vdso是无法生效的,还是会陷入内核。
当然vdso也不保证一定不会陷入内核,有些情况下是会fallback的,以clock_gettime
为例,下面是linux 4.16版本中该系统调用在vdso中的实现:
notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
{
switch (clock) {
case CLOCK_REALTIME:
if (do_realtime(ts) == VCLOCK_NONE)
goto fallback;
break;
case CLOCK_MONOTONIC:
if (do_monotonic(ts) == VCLOCK_NONE)
goto fallback;
break;
case CLOCK_REALTIME_COARSE:
do_realtime_coarse(ts);
break;
case CLOCK_MONOTONIC_COARSE:
do_monotonic_coarse(ts);
break;
default:
goto fallback;
}
return 0;
fallback:
return vdso_fallback_gettime(clock, ts);
}
其中do_realtime
和do_monotonic
如果返回值为VCLOCK_NONE
的话,就会调用vdso_fallback_gettime
,而这个函数是会陷入内核的。另外,clock_gettime
的clock
参数可不止上面代码中switch里面的4个case,如果我们传入的是CLOCK_BOOTTIME
/CLOCK_PROCESS_CPUTIME_ID
/CLOCK_THREAD_CPUTIME_ID
的话,就会走到default分支,还是会调用vdso_fallback_gettime
陷入内核。
综上所诉,gettimeofday
和clock_gettime
实际上都是系统调用,但是调用得当的话,可以避免陷入内核,从而提高性能。是否陷入了内核,可以利用strace来判断。
(为什么我会写这篇文章呢?因为我之前一直顾虑clock_gettime
是个系统调用,虽然精度比gettimeofday
高,但性能差不敢多用。为什么我会觉得clock_gettime
性能差呢?因为之前用strace排查公司代码性能问题的时候总是能看到一大堆一大堆的clock_gettime
,总耗时加起来占所有系统调用总耗时比例不低。那看了今天的文章,clock_gettime
不是在vdso中有实现么,为什么性能差?那是因为既然在strace中有输出,就说明这些clock_gettime
还是陷入了内核。为什么陷入了内核中呢?猜测这些clock_gettime
是英伟达显卡驱动通过syscall
函数调用或者直接使用汇编调用的。)
更多推荐
所有评论(0)