系统调用开销

use*_*978 7 operating-system process system-calls context-switch os161

我刚开始研究系统调用.我想知道在进行系统调用时导致开销的原因.

例如,如果我们考虑getpid(),当对getpid()进行系统调用时,我的猜测是如果控件当前在子进程中,则必须进行上下文切换以进入父进程以获取pid .这会导致开销吗?

此外,当调用getpid()时,将在用户空间边界上进行一些元数据传输并进入和退出内核.那么用户空间和内核之间的常量切换是否也会导致一些开销?

PSk*_*cik 9

我在x86-64 Linux(用-O3编译)上做了一些更精确的基准测试:

ns    relative(rounded) function
4.89  1      regular_function  //just a value return
6.05  1      getpid   //glibc caches this one (forks invalidate the cached value)
17.7  4      sysconf(_SC_PAGESIZE)
22.6  5      getauxval(AT_EUID)
25.4  5      sysconf(_SC_NPROCESSORS_ONLN)
27.1  6      getauxval(AT_UID)
54.1  11     gettimeofday
235   48     geteuid
261   53     getuid
264   54     getppid
314   64     sysconf(_SC_OPEN_MAX)
622   127    pread@0 // IO funcs benchmarked with 1 bytes quantities
638   130    read    // through a 1 Gigabyte file
1690  346    write
1710  350    pwrite@0
Run Code Online (Sandbox Code Playgroud)

最便宜的"系统调用"是通过辅助矢量(~20-30ns)的那些.中间的调用(~250-310ns)应该最准确地反映平均开销,因为在内核中应该没有太多的工作要做.

为了比较,具有小尺寸请求(<64字节=>无系统调用)的malloc + free对成本约为70-80ns(参见我在静态内存分配成本与C中动态内存分配的答案).

https://softwareengineering.stackexchange.com/questions/311165/why-isnt-there-generic-batching-syscall-in-linux-bsd/350173对于如何最小化系统调用开销有一些有趣的想法.

  • 从glibc 2.25开始,`getpid()`[不再被缓存](https://sourceware.org/glibc/wiki/Release/2.25#pid_cache_removal),在提交此答案后不久便发布了它。[`getpid(2)`](http://man7.org/linux/man-pages/man2/getppid.2.html)的手册页提供了有关此主题的一些附加上下文,并指出从版本开始存在缓存2.3.4至2.24。 (4认同)

小智 6

例如,如果我们考虑 getpid(),当对 getpid() 进行系统调用时,我的猜测是,如果控件当前在子进程中,则必须进行上下文切换以进入父进程以获取 pid .

这里不需要切换到子进程——内核应该拥有所有可用的必要数据。在大多数情况下,内核只会在调度程序中或从系统调用返回时将上下文切换到用户空间进程。

同样,当 getpid() 被调用时,将有一些元数据跨用户空间边界传输并进入和退出内核。那么用户空间和内核的不断切换是否也会造成一些开销呢?

是的,如果getpid()经常被调用,开销肯定会增加。有一些方法可以避免这种简单的“getter”系统调用的开销,比如getpid()gettimeofday();曾经在 Linux 下使用过的一种方法是将系统调用的(已知)结果存储在一个特殊的内存页面中。(这种机制被称为vsyscall。)