18

很多时候,我读到/听到这样的论点,即进行大量系统调用等会效率低下,因为应用程序进行了模式切换,即从用户模式切换到内核模式,并且在执行系统调用后开始在用户模式下执行再次切换模式。

我的问题是模式切换的开销是多少?cpu 缓存是否失效或 tlb 条目被刷新或发生什么导致开销?

请注意,我问的是模式切换而不是上下文切换所涉及的开销。我知道模式切换和上下文切换是两个不同的东西,我完全了解与上下文切换相关的开销,但我不明白模式切换会导致什么开销?

如果可能,请提供一些关于特定 *nix 平台的信息,如 Linux、FreeBSD、Solaris 等。

问候

拉里

4

2 回答 2

13

简单模式切换上不应有 CPU 缓存或 TLB 刷新。

一个快速测试告诉我,在我的 Linux 笔记本电脑上,用户空间进程完成一个简单的系统调用大约需要 0.11 微秒,除了切换到内核模式并返回之外,该系统调用的工作量微不足道。我正在使用 getuid(),它只从内存结构中复制一个整数。 strace确认系统调用重复了 MAX 次。

#include <unistd.h>
#define MAX 100000000
int main() {
  int ii;
  for (ii=0; ii<MAX; ii++) getuid();
  return 0;
}

这在我的笔记本电脑上大约需要 11 秒,使用 测量time ./testover,11 秒除以 1 亿得到 0.11 微秒。

从技术上讲,这是两个模式切换,所以我想您可以声称单个模式切换需要 0.055 微秒,但是单向切换不是很有用,所以我认为往返数字更多相关的。

于 2009-12-07T18:26:20.900 回答
2

有很多方法可以在 x86 CPU 上进行模式切换(我在这里假设)。对于用户调用的函数,通常的方式是做一个Task jump或Call(简称Task Gates和Call Gates)。这两个都涉及任务切换(相当于上下文切换)。在调用之前添加一些处理,调用之后的标准验证和返回。这会将最低要求四舍五入为安全模式开关。

至于 Eric 的时间安排,我不是 Linux 专家,但是在我处理过的大多数操作系统中,简单的系统调用会在用户空间中缓存数据(如果可以安全地完成)以避免这种开销。在我看来, getuid() 将是此类数据缓存的主要候选者。因此,Eric 的时间可能更多地反映了用户空间中预切换处理的开销,而不是其他任何东西。

于 2009-12-07T18:56:55.043 回答