
在任何计算机系统中,中央处理器与其众多外围设备之间的高效通信都至关重要。尽管简单的轮询效率低下,但中断机制提供了一种优雅的解决方案,允许设备在需要关注时直接向 CPU 发送信号。然而,这种信号传递并非瞬时完成。在设备请求与 CPU 响应之间存在一个微小但至关重要的延迟,即中断延迟。本文旨在探讨这一延迟的关键性及其常被忽视的本质。首先,在“原理与机制”一节中,我们将剖析中断延迟的构成,探究其硬件和软件层面的根源,从临界区到优先级层次结构。随后,在“应用与跨学科关联”一节中,我们将考察这种延迟对实时控制、虚拟化计算等不同领域的系统性能、安全性和稳定性的深远影响,揭示為何管理這種延遲是現代系統設計的基石。
想象一下,您是中央处理器(CPU),计算机不知疲倦的大脑。您的生活充满了 whirlwind of calculations,以惊人的速度一个接一个地执行指令。但您并不孤单。您的周围是其他设备——键盘、鼠标、网卡、硬盘——每个设备都有自己的需求和节奏。您如何与这个熙熙攘攘的外围设备之城进行通信?您如何知道网卡何时收到了新的数据包,或者用户何时点击了鼠标?
一种最容易想象的方法是轮询。您,CPU,可以每隔一段时间就从主要任务中抽身,逐一询问每个设备:“有我的事吗?你呢?有什么新情况吗?”这就像一个老板在办公室里走来走去,不断地盯着每个人的肩膀。这种方法可行,但效率极低。大多数时候,答案都是“没有”,而您却浪费了宝贵的时钟周期去询问。更糟糕的是,如果一个紧急事件在您刚刚检查完某个设备后发生,您要等到下一轮巡视才能知道。
自然界和计算机工程师们找到了一种更优雅的解决方案:中断。设备不再需要您不断询问,而是在需要您关注时给您“肩上轻轻一拍”。这一拍是发送给您——CPU——的物理电信号。当您感觉到这一拍时,您可以暂停当前的工作,处理设备的请求,然后无缝地恢复您之前正在做的事情。
这看起来很完美!但正如物理学和工程学中的所有事物一样,天下没有免费的午餐。宇宙施加了速度限制。从设备“轻拍”到您实际开始执行处理它的第一行代码之间所经过的时间,称为中断延迟。它是衡量系统响应能力的基本指标。在台式计算机中,高延迟可能意味着鼠标光标跳动。在汽车的防抱死制动系统或战斗机的控制系统中,它可能关系到平稳停车与 catastrophic failure 的区别。
有趣的是,老式的轮询方法并非总是更差。如果一个设备需要非常频繁的关注,而 CPU 又没有太多其他事情可做,那么整个中断机制的开销——暂停、保存工作和处理“轻拍”的过程——可能比简单轮询所需的时间还要大。可以想象这样一种场景:如果两次轮询之间的有效工作量足够小,比如少于几十个简单操作,那么轮询反而可能更快。但对于我们所依赖的复杂多任务系统而言,中断无疑是效率之王。我们的任务就是理解它们所引入的延迟的本质。
为什么对中断的响应不是瞬时的?总延迟并非单一、巨大的障碍,而是一系列微小、不可避免的延迟的序列,其中一些由软件施加,另一些则源于硬件的基本规律。我们可以将总延迟 看作是这些部分的总和:CPU 不愿意 听的时间、无法 听的时间,以及正忙于听别人说话的时间。
让我们将中断想象成一封到达邮局的信。延迟是从信件投入邮箱到指定职员开始阅读它之间的时间。什么会延误这个过程呢?
有时,CPU 必须挂起“请勿打擾”的标志。它通过屏蔽或禁用中断来做到这一点。当这个标志挂起时,任何肩上的轻拍都会被忽略——或者说,它们被记录下来,但处理被推迟了。此时,CPU 正处于一个临界区,即一个精密的、不容打扰的操作序列,否则系统状态可能会被破坏。
想象一位外科医生正在进行精细的切口操作。此刻肩上的一拍将是灾难性的。同样,CPU 可能正在更新一个关键的数据结构,比如正在运行的进程列表。如果中途被打断,列表可能会处于一种荒谬的状态,导致系统崩溃。操作系统的调度程序通常有这样的临界区,切换不同运行任务的代码也是如此。
延迟的最坏情况发生在中断信号恰好在“请勿打扰”标志挂起时到达。中断必须等待整个临界区执行完毕。如果一个内核临界区禁用了 的抢占,并且调度器本身还需要 来切换任务,那么一个高优先级的用户线程可能需要等待 才能运行。然而,一个中断请求只需等待这段时间内中断被明确屏蔽的部分,这个时间可能更短,比如 。
我们可以将这种行为建模为处理器状态的时间线,在中断启用()和禁用()的片段之间交替。在 片段期间到达的中断几乎可以立即处理。在 片段期间于时间 到达的中断必须等到该片段结束,从而产生 的延迟,其中 是下一个 片段的开始时间。这个等待期,即中断屏蔽时间,通常是延迟中最大且变化最不定的由软件控制的组成部分。
如果 CPU 正在处理一个中断时,另一个更紧急的中断到达了,会发生什么?这就引出了优先级和抢占的概念。并非所有中断都生而平等。来自电源的、预示即将发生故障的信号,远比一次按键重要得多。中断控制器设计有固定的优先级系统;来自高优先级设备的中断可以抢占——即打断——低优先级设备的处理程序。
这又产生了另一个延迟来源。一个低优先级中断获得服务所需的时间,现在取决于所有更高优先级设备的行为。在最坏的情况下,来自我们关注的设备(比如设备 4)的请求,与一个阻塞性的低优先级 ISR(设备 5)开始的时刻完全相同,并且也与所有更高优先级设备(1、2 和 3)的请求同时到达。我们的设备 4 必须首先等待设备 5 的阻塞性 ISR 完成,然后等待设备 1、2 和 3 的 ISR 运行完毕。总延迟是它们所有执行时间的总和。这种堆积被称为干扰。
更有趣的是,这种层级结构可以被颠覆。一个 ISR 在运行时,可以临时提高“请勿打扰”的阈值,从而有效地屏蔽通常优先级更高的中断。在一个奇特但可能的情景中,最低优先级设备的 ISR 可能会被编程为屏蔽来自更高优先级设备的中断,从而造成一种优先级反转,并增加了另一种阻塞延迟的来源。
现在,我们可以为一个设备所经历的最坏情况下的中断延迟 建立一个更完整(尽管是简化的)公式:
在这里, 是软件在禁用中断的情况下运行的最长时间。(代表“嵌套”)表示所有可能执行的更高优先级 ISR 所带来的干扰。最后, 是固有的硬件开销——处理器自身执行上下文切换所需的时间,这是一系列微小延迟的总和,例如刷新指令流水线、保存寄存器、获取中断向量,以及处理来自 DMA 控制器等其他硬件的总线竞争。对于现代处理器来说,这可能是几微秒,但每一微秒都至关重要。
这个方程式是实时系统设计的核心。构建飞行控制系统的工程师知道任务的截止时间 和其执行时间 。为了保证系统的安全,他们必须确保总响应时间——中断延迟与所有其他处理时间之和——小于截止时间。利用我们的公式,他们可以计算出最大允许的中断屏蔽时间 ,以确保系统保持安全和响应性。
理解延迟的来源是一回事;控制它们是另一回事。这正是操作系统设计艺术的闪光之处。
如果一个临界区太长,显而易见的解决方法是让它变短。但工作仍然需要完成。优雅的解决方案是将中断服务程序(ISR)分为两部分。第一部分,即上半部,在禁用中断的情况下立即运行。它只做绝对必要的、时间关键的工作:确认硬件、获取数据,或许再入队一张“工作票据”。然后,它立即重新启用中断。更长的、非关键的处理被推迟到下半部(或工作队列),它被调度在稍后像一个普通任务一样运行,此时中断是完全启用的。这种巧妙的分工将“请勿打扰”的时间降至绝对最低,从而显著提高了系统的整体响应能力。
为什么强大的 CPU 要把时间花在将数据从设备复制到内存这种琐碎的任务上?更好的方法是授权。大多数系统都包含一个直接内存访问(DMA)控制器,这是一个专门用于移动数据的协处理器。CPU 可以指示 DMA 控制器:“请将 8 KB 的数据从网卡移动到内存中的这个位置,并在完成后拍拍我的肩膀。” 于是 CPU 就可以自由地执行其他计算。DMA 在后台工作。当它完成后,它会发出一个中断。现在,ISR 的工作变得微不足道:数据已经就位。处理程序可能只需要更新一个指针,这个操作耗时一微秒或更少。这是减少 ISR 工作负载并从而降低延迟的最有效技术 [@problemid:3652993]。
对抗延迟的斗争甚至重塑了内核设计的理念。一个标准内核可能包含许多不可抢占的临界区以简化其逻辑。而一个实时内核,比如打了 PREEMPT_RT 补丁的内核,则采取了更激进的立场。它使几乎整个内核都可抢占,通过细粒度锁来保护数据,而不是全局禁用中断。在这种模型中,ISR 通常被提升为具有固定优先级的完整内核线程。这并未消除延迟,而是改变了其性质。来自中断屏蔽的长的、不可预测的延迟,被来自线程调度的可能更短、更可预测的延迟所取代。对于具有特定任务组合的系统,这可以显著降低最坏情况下的延迟。
最后,我们来到了中断处理最深刻的规则:ISR 上下文是神圣的。它是一种脆弱的、高度特权的状态,存在于操作系统的常规规则之外。如果一个 ISR 在禁用中断的情况下运行,试图访问一段由于内存压力被操作系统临时从 RAM 移到硬盘上的自己的代码,会发生什么?这会导致一个页错误(page fault)。为了服务这个错误,操作系统必须从磁盘读取页面。但它如何知道磁盘读取何时完成?磁盘控制器会发出一个中断!
于是,我们遇到了一个精妙而可怕的死锁。ISR 在等待来自磁盘的页面。页错误处理程序在等待磁盘完成。磁盘在等待发出中断以 signalling it's finished。但 CPU 无法接收那个中断,因为最初的 ISR 已经禁用了它们。系统因自身的聪明才智而陷入停顿,冻结了。
解决方案简单而绝对:任何可能在 ISR 内被触及的代码或数据——处理程序代码、其数据、其堆栈——都必须被锁定在物理内存中,使其永久驻留,免于被换出。这是硬件和软件之间的一个盟约:这片小小的、神圣的内存区域将永远存在,保证响应外部世界的关键过程永远不会被内存管理的内部机制所破坏。这一原则揭示了计算机系统深刻而复杂的统一性,即最高层的操作系统策略必须尊重最基本的硬件事件约束。
在窥探了中断的机制及其延迟的本质之后,我们可能会 tempted to file this knowledge away as a mere technicality of computer engineering。但这样做将只见树木,不见森林。中断延迟并非数据手册上的一个抽象数字;它是任何交互系统的一个基本自然常数,一个以深刻且往往令人惊讶的方式塑造我们技术能力的因素。它是决定两种设计取舍的无形之手,是稳定机器与不稳定机器之间的界限,也是安全与灾难之间的区别。现在,让我们走出处理器核心,进入更广阔的世界,看看理论的橡胶在现实的道路上如何摩擦。
想象一下,你是一名程序员,接到一个简单的任务:从键盘读取一个字符。你怎么做?最直接的方法是不断询问。你可以写一个循环, relentless地检查一个状态寄存器:“有字符了吗?现在有了吗?现在呢?”这就是轮询的本质。它很简单,但效率低得令人发指。处理器完全被这种不停的询问所消耗,在大多数时间里燃烧着时钟周期和能量,却一无所获。
另一种选择是中断的优雅。系统告诉键盘硬件:“别给我们打电话,我们会给你打……或者说,你有事的时候给我们打电话。”处理器现在可以自由地做其他有用的工作。当一个键被按下时,键盘硬件发送一个信号——一个中断——处理器暂停当前任务来处理新字符。
然而,在这里,我们遇到了第一个权衡,一个工程学中的经典困境。中断尽管效率高,但并非瞬时。从按键到处理器开始响应之间存在一个延迟——中断延迟。轮如果我们愿意足够频繁地询问,那么轮询尽管浪费,却可以有非常低的响应时间。哪个更好?答案,正如物理学和工程学中常见的那样,是:视情况而定。
对于像人打字这样不频繁且不可预测的事件,中断无疑是效率的冠军。但如果事件像来自高速网卡的 torrent 一样,以每秒数千或数百万次的频率到来呢?如果每次中断的开销很高,处理器可能会因为忙于处理工作的信号而没有时间处理工作本身。在这种情况下,一个精心调整的轮询循环实际上可能更优越,通过减少花在协议上的时间,让系统处理更多数据。这个选择是在 CPU 周期成本和延迟预算之间进行的一场微妙的舞蹈。
在任何领域,中断延迟的重要性都比不上实时系统。这些不是你日常的台式电脑,而是隐藏在汽车、飞机、医疗设备和工厂机器人内部的大脑。它们的决定性特征不仅在于必须产生正确的结果,而且在于必须在严格的截止日期前完成。一个迟到的答案就是错误的答案。
想象一个微控制器正在监控一台工业机械中的一个关键传感器,每秒精确采样一千次。每次采样都由一个周期性中断触发。周期是毫秒。这毫秒不仅仅是一个时长;它是一个预算。在这个微小的时间窗口内,所有事情都必须发生:物理中断信号必须传播,处理器必须保存其状态并跳转到服务程序(即延迟),程序必须执行其逻辑,并且必须在下一次中断到来之前完成。
最坏情况下的中断延迟是对这个预算征收的第一笔税。如果延迟是,比如说,微秒,那么在程序员的一行代码运行之前,总时间预算的近八分之一就已经被消耗掉了。更长的延迟直接转化为可用于实际计算——即系统需要进行的“思考”——的时间更少。
此外,由于中断通常具有最高优先级,它们的执行时间对整个系统施加了一种“中断税”。花在处理中断上的每一个周期都是不能用于任何其他任务的周期。对于一个需要 juggling 多重责任的系统,中断所消耗的总时间必须从处理器的总容量中减去,为所有其他应用程序逻辑留下一个更小的剩余预算。
在某些系统中,超出时间预算不仅仅是性能问题,更是一种安全隐患。考虑一个处理器正在监控一个大功率计算机芯片的温度以防止其熔化。一个传感器报告温度,如果超过某个阈值,中断服务程序(ISR)必须立即触发断电。
但物理世界不会等待 CPU。当中断信号在硅片中传播时,当 ISR 被分派时,当 CPU 读取传感器值并与阈值比较时,芯片温度仍在持续上升。总响应时间是所有这些延迟的总和:传感器样本的 age,中断延迟,代码本身的执行时间,甚至在发出关机命令后电源轨物理衰减所需的时间。
为了保证安全,关机阈值温度 不能设置为临界失效温度 。相反,它必须设置为一个较低的值,安全裕度 必须足够大,以计及在最大可能端到端响应时间内可能出现的最大温度升高。这个响应时间的很大一部分是中断延迟。从一个非常真实的意义上说,中断系统中的延迟直接决定了它所控制的物理系统的安全裕度 [@problem id:3653007]。
延迟的后果延伸到了古典工程学中最优雅的领域之一:控制理论。想象一下试图用手掌平衡一根长杆。你的眼睛(传感器)看到它开始倾斜。你的大脑(控制器)计算出一个纠正动作。你的肌肉(执行器)移动你的手。现在,想象一下用一秒的视频延迟来做这件事。你的纠正总是基于杆过去的位置,而不是它现在的位置。系统很快变得不稳定,杆子摔到地上。
这正是在数字控制系统中存在延迟时发生的情况。一个微控制器采样一个对象的状态(例如,一个机器人手臂的位置),一个 ISR 计算下一个控制输入,然后一个执行器应用它。中断延迟是'计算'和'执行'阶段之间的一个延迟。
从控制理论的角度来看,这种延迟是一种毒药。它可以将一个简单的稳定系统转变为一个复杂的、 склонный к колебаниям的高阶系统。如果延迟变得太大,系统的反馈回路就会变得不稳定,输出可能会剧烈振荡或发散到无穷大。像 Jury 稳定性判据这样的数学工具可以用来计算给定系统在分崩离析前可以容忍的精确最大延迟 。在这里,我们看到了一个美丽而深刻的统一:处理器中断系统的时间行为与它所管理的物理世界的稳定性密不可分。
让我们将焦点从单一的关键事件转移到高性能网络和存储中 relentless 的数据洪流。当每秒有数百万个数据包到达,每个都触发一个中断时,处理器可能会进入一种“中断风暴”或“活锁”状态,花费 的时间仅仅用于确认事件,而没有周期来实际处理它们。解决方案是一种称为中断合并或中断调节的巧妙技术。
这个想法很简单:硬件不是为每个单一事件都产生中断,而是收集一批事件(例如 个网络数据包)或等待一个小的时间窗口过去,然后为整批事件触发一个单一的中断。这大大降低了每个数据包的 CPU 开销。但这是有代价的:一批中的第一个数据包现在必须等待该批的其他数据包到达,从而引入了新的延迟源。
我们再次发现,正确的策略取决于应用。对于硬实时传感器,这种增加的、不可预测的延迟通常是不可接受的。但对于像处理网络数据包这样的软实时任务,平均吞吐量比任何单个数据包的截止日期更重要,合并是一项至关重要的优化。工程师必须进行仔细的分析,以找到尽可能大的批处理大小 ,即使考虑到系统中其他更高优先级中断的延迟,也能将任何单个完成的最坏情况延迟保持在其要求的预算 内。
这种延迟和效率之间的权衡也出现在电源管理领域。为了节省能源,现代芯片被设计成将组件置于深度睡眠状态。然而,唤醒一个组件,如网络接口的物理收发器(PHY),并非没有代价;它既消耗能量,也至关重要地消耗时间。这种唤醒延迟可能长达数百微秒。在决定让一个组件进入睡眠状态之前,系统必须问:考虑到我的中断响应时间要求,我能承受这种唤醒延迟吗?如果一个传入网络数据包的截止日期小于 PHY 的唤醒时间,那么睡眠根本不是一个选项。决定睡眠涉及一个简单而优美的“收支平衡时间”计算——空闲持续时间,当睡眠节省的能量最终超过唤醒的固定能量成本时。通过这种方式,中断延迟约束直接影响我们移动设备的电池寿命和大型数据中心的能源足迹。
随着计算机体系结构变得越来越复杂,中断延迟的来源也变得越来越复杂。延迟不再是一个单一的数字,而是一个由核心、插槽和软件层组成的 labyrinthine 系统的涌现属性。
现代服务器通常包含多个处理器插槽,每个插槽都有自己直接连接的内存。这 tạo ra một 非统一内存访问(NUMA) 架构。这就像一个有几个城市(插槽)的国家。在自己的城市内访问内存(本地访问)很快。访问不同城市的内存(远程访问)需要走一条高速公路(插槽间互连),并且速度明显更慢。
现在,考虑一个配置错误的虚拟机:其 I/O 设备(例如网卡)物理上插入插槽 A,但其虚拟 CPU 和内存却在插槽 B 上运行。这是一个性能噩梦。每次设备使用直接内存访问(DMA)写入数据时,数据都必须通过互连从 A 传输到 B。每次设备发送中断时,中断消息也必须 traversing the same path。每次 CPU 需要访问设备寄存器时,该命令也必须从 B 跨越到 A。延迟突然变成了机器内部物理地理的函数。实现最佳性能需要 NUMA 感知的配置,确保设备、为其服务的 CPU 以及其使用的内存都保持在同一个“城市”。
在一个拥有多个核心的系统中,应该如何处理中断?存在两种主要哲学。在非对称多处理(AMP)中,所有中断都被汇集到一个指定的单一核心。这易于管理,但该核心很容易成为瓶颈。在对称多处理(SMP)中,中断分布在所有可用核心上。这分散了负载,但需要更复杂的硬件和软件。
哪种方法能产生更低的延迟?我们可以求助于排队论的数学来寻找答案。AMP 系统可以建模为单个 M/M/1 队列,其中到达率 的到达(中断)为一个服务率 的单个服务器(核心)排队。SMP 系统可以建模为 个并行的 M/M/1 queues,每个队列的到达率要低得多,为 。该理论为每种情况下的预期延迟提供了优雅的 closed-form expressions: and 。快速查看一下就能揭示并行的力量:对于负载下的系统(当 在 AMP 情况下接近 时),延迟 会爆炸性地趋向无穷大。在 SMP 情况下,分母 要大得多,从而保持低延迟。分散工作显著减少了队列中的等待时间,展示了性能建模的一个基本原则。
也许对延迟最大的现代挑战是虚拟化。当一个中断注定要发送到一个在虚拟机(VM)中运行的客户操作系统时,它不能直接到达那里。相反,物理中断被底层的虚拟机监控程序(hypervisor)捕获。这会触发一个昂贵的上下文切换,称为“VM exit”。然后,hypervisor 必须检查中断,决定它属于哪个 VM,然后向客户机“注入”一个虚拟中断,接着是另一个昂贵的“VM entry”来恢复 VM。
这整个往返过程为延迟增加了一个显著的“虚拟化税”,通常是数千个时钟周期。更糟糕的是,这个税可能是可变的;如果 hypervisor 忙于其他任务,虚拟中断的注入可能会被进一步延迟。对于作为客户机运行的实时操作系统来说,这种增加的、不可预测的延迟对其满足截止日期的能力可能是致命的。在虚拟化环境中保证实时性能需要一个专门设计的“实时 hypervisor”,它能够提供一个专用的物理 CPU 和一个优先级对齐、低延迟中断交付的承诺——这是一个标准的、尽力而为的云 hypervisor 根本无法做出的硬性承诺。
我们的旅程从轮询与中断的简单选择,一直到虚拟化、多插槽服务器的复杂动态。我们看到,中断延迟远非微不足道的延迟。它是一个关键参数,塑造了安全、稳定、高效和强大的计算机系统的设计。它是决定物理控制系统中安全裕度的力量,是驱动电源管理策略的约束,也是云中性能工程师 tirelessly 努力最小化的瓶頸。
就像科学中许多基本原理一样,它的影响遍及看似无关的领域——控制理论、操作系统、硬件架构和性能建模。理解中断延迟就是理解计算的节奏,即数字世界与物理时间不可阻挡的前进之间持续而微妙的舞蹈。它是现代技术宏伟织锦中最重要但往往最无形的线索之一。