嗯,看起来是错误的假设。用户代码并不会启动从进程到进程的切换。那么切换本身可能是到一个在系统调用中被阻塞的进程,即已经在内核模式下运行。 - Nikolai Fetissov
1个回答
10
10
在进程之间切换(前提是你实际上进行了切换,而不是并行运行)时,顺序会变得非常慢。 从用户空间到内核空间的陷入以前是通过处理器中断完成的。大约在2005年(我记不清内核版本了),在邮件列表上进行讨论后,有人发现在一款高端 Xeon 处理器上陷入比早期的 Pentium II 或 III 还要慢(绝对指标上!)。于是他们使用了一个新的 CPU 指令 sysenter(实际上从 Pentium Pro 开始就已经存在了)。这是在每个进程的虚拟动态共享对象(vdso)页面中完成的(在每个进程中 cat /proc/pid/maps 查找)。 因此,现在,内核陷入基本上只是几个 CPU 指令,因此循环次数很少,与使用中断时的十分之一或百分之一相比,中断在现代 CPU 上真的很慢。 进程之间的上下文切换是很重的。它意味着将所有处理器状态(寄存器等)存储到 RAM 中(实际上是在用户进程空间中的一个魔术内存位置,猜猜在哪里!),在 CPU 中实际上污染了所有缓存的内存,并读回新进程的进程状态。它(可能)没有仍然在 CPU 缓存中上次运行的任何内容,因此每个内存读取都将是缓存未命中,并需要从 RAM 中读取。这相当慢。当我在大学时,我“发明”了一个无限大小的缓存(虽然在未使用时不加电源,只用于上下文切换),并在 Simics 中实现了这个想法。我在 Linux 中实现了对这个神奇缓存的支持,我称之为 CARD(Context-switch Active, Run-time Drowsy),并进行了相当大量的基准测试。我发现它可以使具有许多重型进程且共享同一核心的 Linux 机器加速约5%。尽管如此,这是在相对较短(低延迟)的进程时间片段中。 无论如何,上下文切换仍然很重,而内核陷入基本上是免费的。 答案是用户空间中的哪个内存位置,对于每个进程: 在地址零处。没错,就是空指针!无论如何,你都不能从用户空间读取整个页面 :) 这是在2005年,但除非 CPU 状态信息已经增长到一页大小,否则现在可能仍然是相同的实现。
- gustaf r
1
如果你想在内核中完成任何事情,仍然需要保存用户进程的状态。我记得,通常设置虚拟内存,使得内核页表可以从每个进程的页表访问,这样当从进程切换到内核再返回同一进程时就不会使TLB失效。由于使TLB失效几乎会清除缓存中的任何虚拟标记条目,所以我认为这就是为什么在进程之间切换比在内核和进程之间切换要昂贵得多的真正原因。 - Kevin
sysenter/exit
指令。进程之间的上下文切换还意味着切换页表并清除缓存和TLB。 - Nikolai Fetissov