Page 468 - 《软件学报》2025年第5期
P. 468
2368 软件学报 2025 年第 36 卷第 5 期
程. 在自研微内核 ChCore 上, 如果 IPC 服务端线程此时没有运行在其他处理器核心上, 那么内核就会将服务端线
程调度到当前客户端线程的核心上运行. IPC 服务端线程处理完请求后, 也需要再立即切换回原来的客户端线程.
这样整个 IPC 流程就涉及 2 次上下文切换, 每次上下文切换操作都需要保存和恢复一个完整的线程上下文. 而
SPARC 架构上寄存器众多, 如果一个线程使用了全部的寄存器窗口, 那么它需要保存和恢复的寄存器可达
136 个, 而保存和恢复这些寄存器则会为 IPC 带来不可忽视的性能开销. 本工作设计实现了 BankedIPC, 通过重新
设计内核管理分配寄存器窗口的策略, 减少了每次上下文切换的耗时, 优化了 IPC 性能. 下面将首先介绍内核管理
寄存器窗口的 Register bank 策略, 这是 BankedIPC 的基础, 之后将进一步说明 BankedIPC 如何利用 Register bank
策略实现快速上下文切换以及寄存器 IPC.
3.1.1 寄存器组
在第 2.1 节中提到, 现代 SPARC 处理器上, 与使用全部寄存器窗口相比, 仅使用一个单独的寄存器窗口并不
会对应用程序的性能产生较大影响. 因此, 我们可以限制每个应用程序能够使用的寄存器窗口数量, 使其仅能够使
用一部分寄存器窗口. 我们为每个线程能够使用的寄存器分配一个寄存器组 (Register bank), 当该线程正在运行
时, 它的寄存器组与处理器中真实的通用寄存器相对应, 一般为一个寄存器窗口 (出于性能考虑也可增加其寄存器
窗口的数量); 而当该线程因为被抢占等种种原因换出到内存中后, 其寄存器组与内存中的“虚拟寄存器”相对应,
即该线程曾经使用的寄存器的值按照其寄存器组的结构被保存在内存中, 这与普通的上下文保存/恢复相似. 寄存
器组的整体设计如图 4 所示.
寄存器组元数据
Bank 0 Bank 1 Bank 2
active: true active: true active: false …
start_window: 0 start_window: 3 address:
end_window: 2 end_window: 4 0xc00506320
当前线程上下文
线程恢复执行时, 根据其寄存器组元
数据, 将上下文恢复至空闲寄存器中 被挂起线程上下文
内核
Bank 2 Bank 0
CWP
…
内存 寄存器 Bank 1
如果空闲寄存器不足, 寄存器中的上
下文将换出至内存并更新元数据
图 4 寄存器组设计概览
当操作系统内核需要将某个之前被换出到内存的线程恢复运行时, 会首先检查目前处理器上是否有足够多的
满足该线程寄存器组要求的空闲寄存器. 如果有足够的空闲寄存器, 内核会将该线程保存在内存中的上下文恢复
到这些空闲寄存器中, 并记录该线程的寄存器组和这些真实寄存器的映射关系, 之后该线程就可以在这些寄存器
上恢复执行. 如果没有足够多空闲的寄存器, 则需要将一些正在运行的线程的上下文换出到内存中, 以获取足够的
空闲空间. 以图 4 为例, 当需要将图中 Bank 2 对应的线程恢复执行时, 发现已经没有可用寄存器, 此时需要将某个
寄存器组 (比如 Bank 1) 换出到内存. 在这种设计方案下, 将一个线程的寄存器组换出到内存的过程是懒惰的, 即
只有在处理器可用的空闲寄存器数量不足时才会发生上下文的保存和恢复, 而不会在某个线程被挂起时立即发
生. 这种设计方案的优势在于, 当被暂时挂起的线程短时间内将要恢复执行时, 不必重新切换上下文, 因为它的上
下文之前就已经位于寄存器中了, 并且没有被立即换出到内存. 自研微内核 ChCore 上的 IPC 实现与这种场景一