当发生中断时,管道中的指令会发生什么?

Rag*_*thy 22 computer-architecture

假设一个5级流水线架构(IF =指令获取,ID =指令解码,EX =执行,MEM =存储器访问,WB =寄存器写回).有4条指令必须执行.

(这些样本说明不准确,但我相信这一点会被理解)

在第五个时钟周期,这些指令将在管道中,如下所示.

添加a,b,c [IF ID EX MEM WB]

添加a,b,d [IF ID EX MEM]

添加a,b,e [IF ID EX]

添加a,b,f [IF ID]

现在,如果发生硬件中断,这些指令会发生什么.只有在执行流水线中的所有指令后才能处理中断吗?是否会以不同的方式处理软件中断和异常?

Kra*_*lew 21

首先,术语:

通常,至少在英特尔,中断是来自外部世界的东西.通常它与处理器上执行的指令不同步,即它是异步外部中断.

在英特尔术语中,异常是由处理器上执行的指令引起的.例如页面错误或未定义的指令陷阱.

--- +中断清除飞行中的所有指令

在我熟悉的每台机器上 - 例如自P5(我使用P6)以来的所有英特尔处理器,AMD x86s,ARM,MIPS - 当收到中断信号时,管道中的指令几乎总是被刷新,丢弃.

我说"几乎总是"的唯一原因是,在某些机器上,您并不总是在允许接收中断的地方.因此,您将前往允许中断的下一个位置 - 通常是任何指令边界 - 然后扔掉管道中的所有指令.

就此而言,可能会阻止中断.所以你继续进行,直到中断被解锁,然后你扔掉它们.

现在,这些机器并不是简单的5级管道.尽管如此,这种观察 - 大多数机器抛弃了管道中的所有指令,在中断逻辑所在的管道之前的管道中 - 仍然几乎普遍存在.

在简单的机器中,中断逻辑通常位于管道的最后阶段WB,大致对应于高级机器的提交管道.有时它会被移动到之前的管道阶段,例如示例中的MEM.因此,在这些机器上,IF ID EX中的所有指令(通常是MEM)都会被丢弃.

--- ++我为什么关心:避免浪费工作

这个话题离我很近,因为我建议不要这样做.例如,在我们计划构建P6时的客户访问中,我向客户询问了他们的首选 - 低延迟中断,正在进行的刷新指令,或(略微)更高的吞吐量,允许至少部分飞行指令完成,以稍长的延迟为代价.

然而,虽然有些顾客更喜欢后者,但我们选择做传统的东西,立即冲洗.除了较低的延迟,主要原因是复杂性:

例如,如果你接受了一个中断,但是如果你已经在飞行中的一条指令也有异常,那么你在重新启动IF(取指令)之后但是在中断的任何指令已经提交之前,哪个优先?答:这取决于.这种事情很难处理.

--- +++民俗:大型机操作系统中断批处理

这与报告某些IBM大型机操作系统的运行方式非常相似:

  • 除定时器中断外,所有中断在正常操作中被阻塞;
  • 在定时器中断中,你取消阻塞中断,并处理所有中断;
  • 然后以中断阻塞模式返回正常操作

可以想象,他们可能只在重载时才使用这种"中断批处理"模式; 如果装载很轻,它们可能不会阻止中断.

--- +++延迟机器检查例外

推迟中断以使管道中的指令有机会执行的想法也类似于我称之为延迟机器检查异常 - 这个概念我包含在原始的英特尔P6系列机器检查架构中,大约在1991-1996,但是似乎没有被释放.

这是一个问题:机器检查错误,例如(un)可纠正的ECC错误可能在指令退出之后发生(即,在假设较年轻的指令已经提交状态之后,例如写入寄存器),或者在指令退出之前.

AFTER错误的典型示例是由商店触发的无法纠正的ECC,该商店在分级时被放入写缓冲区.几乎所有现代机器都这样做,所有机器都带有TSO,这几乎意味着如果你不足以缓冲商店,总是有可能出现不精确的机器检查错误.

BEFORE错误的典型例子是......好吧,每个指令都在带有管道的任何机器上.但更有趣的是,错误路径指令的错误,在分支错误预测的阴影下.

当加载指令获得无法纠正的ECC错误时,您有两种选择:

(1)你可以立即拉链,不仅杀死指令YOUNGER而不是加载指令,还杀死任何OLDER指令

(2)或者您可以将某种状态代码写入控制推测的逻辑中,并在退休时采用异常.这几乎是您必须为页面错误做的事情,它会使这些错误变得精确,有助于调试.

(3)但是,如果获得无法纠正的ECC错误的加载指令是错误的路径指令,并且因为较旧的机上分支错误预测并以另一种方式进行而从未退休,该怎么办?

好吧,你可以写下状态,试着让它变得精确.你应该有精确错误和不精确错误的计数器.否则你可以在这样的错误路径指令上忽略错误 - 毕竟,如果它是一个硬错误,它将被再次触摸,或者它可能不会./例如,错误可能在架构上是静默的 - 例如,错误的高速缓存行可能被同一地址的良好高速缓存行覆盖.

并且,如果你真的想要,你可以设置一点,以便如果旧的分支错误预测,那么你在那个时间点检查机器检查异常.

这种错误不会发生在与导致错误的指令相关联的程序计数器上,但可能仍然具有其他精确状态.

我打电话给(2)推迟机器检查异常; (3)你是如何处理推迟的.

IIRC,所有英特尔P6机器检查异常均不准确.

--- ++抓住手:更快

所以,我们已经讨论过了

0)立即接受中断,或者,如果中断被阻止,则执行指令和微指令,直到达到中断未阻塞点.然后冲洗飞行中的所有指令.

1)尝试在管道中执行指令,以避免浪费工作.

但还有第三种可能性:

-1)如果你有微体系结构状态检查点,立即采取中断,永远不要等待中断未阻塞点.只有在最近的"安全中断"点上有一个所有相关状态的检查点时才能执行此操作.

这甚至比0更快,这就是为什么我把它标记为-1).但它需要检查点,许多但不是所有积极的CPU都使用检查点 - 例如英特尔P6不使用检查点.这样的退休后检查点在共享内存的存在下变得时髦 - 毕竟,在中断被阻止时,您可以执行内存操作,如加载和存储.你甚至可以在CPU之间进行通信.即使硬件事务内存通常也不会这样做.

--- +例外标记受影响的指令

相反,例外,例如页面错误,标记受影响的指令.

当该指令即将提交时,此时刷新异常之后的所有后续指令,并重定向指令获取.

可以想象,可以更早地重新获取指令,在大多数处理器上已经处理了分支错误预测的方式,在我们知道异常将要发生的时刻.我不知道有谁这样做.在当前的工作负载上,异常并不重要.

--- +"软件中断"

"软件中断"是通常与系统调用相关的错误指令.

可以想象,可以在不中断管道的情况下处理这样的指令,像分支一样预测.

但是,我熟悉的所有机器都以某种方式序列化.按照我的说法,他们不会重命名权限级别.

--- +"精确中断",EMON,PEBS

另一张海报提到了精确的中断.

这是一个历史名词.在大多数现代机器上,中断被定义为精确的.具有不精确中断的旧机器在市场上并不是很成功.

但是,有一个替代的意思,我参与介绍:当我让英特尔添加在性能计数器溢出时产生中断的能力,首先使用外部硬件,然后在CPU内部,在前几代,完全不精确.

例如,您可以将计数器设置为计算退役指令的数量.退出逻辑(RL)将看到指令退出,并发信号通知性能事件监视电路(EMON).将此信号从RL发送到EMON可能需要两到三个时钟周期.EMON会增加计数器,然后看到有溢出.溢出将触发对APIC(高级可编程中断控制器)的中断请求.APIC可能需要几个周期才能弄清楚发生了什么,然后发出退出逻辑的信号.

即,EMON中断将被不准确地发出信号.不是在事件发生时,而是在此之后的某个时间.

为什么这种不精确?那么,在1992年至1996年,性能测量硬件并不是一个高优先级.我们正在利用现有的中断硬件.乞丐不能选择.

但此外,一些表现本质上是不精确的.例如,你什么时候发信号通知一个中断因为一个从不退休的推测性指令的高速缓存未命中?(我有一个我称为延迟EMON事件的方案,但这仍然被认为太贵了.)就此而言,缓存未命中存储指令,存储放入存储缓冲区,指令已经退役了?

即,有时性能事件发生在与它们相关联的指令已经提交(退休)之后.有时候之前.并且通常不完全符合他们所关联的指令.

但到目前为止的所有实现中,据我所知,这些性能事件被视为中断:管道中的现有指令被刷新.

现在,您可以将性能事件视为陷阱,从而使性能事件更加精确.例如,如果它是一个像退役指令这样的事件,你可以立即使用退出逻辑陷阱,而不是采用我上面描述的那个迂回循环.如果它在管道中较早出现,则可以在ROB(重新排序缓冲区)中的指令故障状态中标记它.英特尔在PEBS(基于精确事件的采样)方面做了类似的事情.http://software.intel.com/sites/products/collat​​eral/hpc/vtune/performance_analysis_guide.pdf.

但请注意,并非所有事件都可以使用PEBS进行采样.例如,上面示例中的PEBS可以计算缓存命中或未命中的负载,但不计算存储(因为存储稍后发生).

所以这就像例外:事件只在指令退出时才传递.因为在某种意义上事件还没有完全发生 - 它是一个加载指令,它会占用缓存未命中,然后退出.标记的PEBS指令之后的指令将从管道中刷新.

我希望--- +关于早期计算机的延迟