Intel系统编程指南第八章——8.10 空闲和阻塞情况的管理

当在一个MP系统中的一个逻辑处理器(包括多核处理器或支持Intel超线程技术的处理器)处于空闲(没有工作可做)或阻塞(等待一个锁或信号量)时,核心执行引擎资源的额外的管理可以通过使用HLT(中止)、PAUSE或MONITOR/MWAIT指令来完成。

 

8.10.1 HLT指令

 

HLT指令停止正在执行它的逻辑处理器的执行,并将该逻辑处理器放置于一个中止状态,直到进一步的通知。当一个逻辑处理器被中止时,活动的逻辑处理器继续持有对物理包内的共享资源的全部访问。这里,正在被已被中止的处理器所使用的共享资源对活动逻辑处理器变得可用,允许它们更高效地执行。当被中止的逻辑处理器恢复执行时,共享资源再一次,在所有的活动逻辑处理器之间被共享。(见8.10.6.3小节)

 

8.10.2 PAUSE指令

 

PAUSE指令可以提升支持Intel超线程技术的处理器的性能,当执行“旋转等待循环”和其它例程时,在那些例程中,一个线程正在一个紧凑的轮询循环中访问一个共享锁或信号量。当执行一个旋转等待循环时,处理器会遭受严重的性能惩罚,当退出循环时,因为处理器探测到一个可能的存储器次序违背,并冲刷核心处理器的流水线。PAUSE指令给处理器提供了一个暗示,该代码序列是一个旋转等待循环。处理器使用此暗示以避免存储器次序违背,并防止流水线冲刷。此外,PAUSE指令取消旋转等待流水线,以避免它过于消耗执行资源以及消耗不必要的电源。(见8.10.6.1小节)

 

8.10.3 探测支持MONITOR/MWAIT指令

 

流SIMD扩展3引入了两条指令(MONITOR和WAIT)以帮助多线程软件提升线程同步。在初始实现中,MONITOR和WAIT在环(Ring)0对软件可用。指令在大于0级有条件地可用。使用下列步骤来探测MONITOR和MWAIT的可用性:

1、使用CPUID来查询MONITOR位(CPUID.1.ECX[3] = 1)。

2、如果CPUID指示支持,那么在一个TRY/EXCEPT异常处理和为一个异常的陷阱内执行MONITOR。如果一个异常发生,MONITOR和MWAIT在一个大于0的特权级下不被支持。见例8-23:

 

例8-23 校验MONITOR/MWAIT支持

 

 

8.10.4 MONITOR/MWAIT指令

 

操作系统通常实现空闲循环以实现线程同步。在一个典型的空闲循环场景中,可能会有若干个“忙循环”,并且它们将使用一组存储器位置。一个受影响的处理器在一个循环中等待,并轮询一个存储器位置,以确定是否有可用的工作执行。工作的投递一般是对存储器(等待处理器的工作队列)的一次写。启动一个工作并使它被调度的时间是在若干个总线周期的次序上。

从一个资源共享的观点(共享资源的逻辑处理器)来看,在一个OS空闲循环中对HLT指令的使用是要得的,但具有含义。在一个空闲的逻辑处理器上执行HLT指令把目标处理器置为一个非执行状态。这要求另一个处理器(当为被中止的逻辑处理器投递工作时)使用一个处理器间中断来唤醒被中止的处理器。对这么一个中断的投递和服务,在新的工作请求的服务中引入了一个延迟。

在一个共享存储器配置中,从忙循环退出,往往因为可应用于一个特定的存储器位置的一次状态的改变而发生;这样的一次改变趋于被另一个代理(一般是一个处理器)写到存储器位置而被触发。

 

MONITOR/MWAIT补足了HLT和PAUSE的使用以允许对共享物理资源的逻辑处理器之间划分及组合共享资源。MONITOR建立一个有效的寻址范围,用于监视对存储器写的活动;MWAIT将处理器置于一个优化的状态(这在不同实现之间可能不同),直到一次对被监视的地址范围的写发生。

在MONITOR和MWAIT的初始实现中,它们只能在CPL = 0下才可用。

两条指令都依赖于处理器监视器的硬件状态。监视器硬件可以被装备(通过执行MONITOR指令)或被触发(根据各种不同的事件,监视器硬件处于被触发的状态)。如果在执行MWAIT时,监视器硬件正处于一个被触发的状态,那么:MWAIT的行为就犹如一个NOP,并继续执行执行流中的下一条指令。监视器硬件的状态架构上是不可见的,除非通过MWAIT的行为。

多个事件,而不是对触发地址范围的一次写,会使得一个执行了MWAIT的处理器被唤醒。这些包括那些会导致自动的或非自动的上下文切换,诸如:

1、外部中断,包括NMI、SMI、INIT、BINIT、MCERR、A20M#

2、错误,中止(包括机器检查)

3、架构TLB无效化,包括对CR0、CR3、CR4和某些MSR的写;执行LMSW(发生在发布MWAIT之前,但在设置监视器之后)

4、由于快速系统调用和远程调用而引起的自动变迁(发生在发布MWAIT之前,但在设置监视器之后)

电源管理相关的事件(诸如热监视器2或芯片组驱动的STPCLK#断言)将不会使得监视器事件未决标志被清0。错误将不会使得监视器事件未决标志被清0。

软件不应该允许在指令流中的MONITOR/MWAIT之间自动的上下文切换。注意,MWAIT的执行并不重新装备监视器硬件。这意味着MONITOR/MWAIT状态可能会起因于一个条件,而不是对触发地址的一个写;软件应该显式地检查触发数据位置,以判定写是否发生。软件也应该检查跟在监视器指令的执行之后(以及在MWAIT指令的执行之前)的触发地址的值。这个检查用于标识任一对在MONITOR执行的过程期间所发生的触发地址的写。

提供给MONITOR指令的地址范围必须是回写Cache类型。只有回写存储器类型对被监视的地址范围的存储将触发监视器硬件。如果地址范围不在回写类型的存储器中,地址监视器硬件可能不被适当地建立,或监视器硬件不被装备。软件也有责任确保:

1、不打算使得一个忙循环的退出,不写到正在被监视器硬件监视的地址区域内的一个位置的写,

2、打算使得对一个忙循环的退出被写到被监视的地址区域内的位置的写。

不这么做将导致更多的错误的唤醒(一个从MWAIT状态的退出非起因于一次对目的数据位置的写)。这些具有负面的执行含义。对于软件,可能有必要使用填充以防止错误唤醒。CPUID提供了一个机制来判定监视的数据位置的大小,以及一个填充的大小的机制。

 

8.10.5 Monitor/Mwait地址范围确定

 

要使用MONITOR/MWAIT指令,在一个多处理器系统中,软件应该知道被MONITOR/MWAIT指令监视的区域长度以及Cache窥探交通的相应行大小。这个信息可以使用CPUID监视子功能(EAX = 05H)来查询。你将需要最小和最大的监视器行大小:

1、为了避免错过的唤醒:确定用于监视写的数据结构适应最小监视器行大小。否则,在一次打算触发一个来自MWAIT的退出的写之后,处理器可能无法唤醒。

2、为了避免错误唤醒:使用最大监视器行大小来填充用于监视写的数据结构。软件必须确保在该数据结构上,在MWAIT的触发区域,没有非相关数据变量退出。一次填充可能是需要的,以避免这种情况。

上述这两个不承担任何系统中的Cache行大小,并且软件不应该对那个效果做任何假定。在一单个簇系统内,这两个参数应该默认是相同的(监视器触发区域的大小与系统相关行大小相同)。

 

基于由CPUID所返回的监视器行大小,OS应当动态地分配带有适当填充的结构。如果静态数据结构必须被一个OS使用,那么需要试图适应该数据结构并且使用一个动态分配的数据缓存用于线程同步。当后者技术不可能时,在使用静态数据结构时,考虑不使用MONITOR/MWAIT。

 

为了要在多簇系统上为MONITOR/MWAIT正确地建立数据结构:处理器、芯片组和BIOS之间的交互是需要的(系统相关行大小可能依赖于在系统中所使用的芯片组;该大小可能不用于处理器的监视器触发区域)。BIOS负责使用IA32_MONITOR_FILTER_LINE_SIZE MSR为系统相关行大小设置正确的值。依赖于监视器触发区域对写入IA32_MONITOR_FILTER_LINE_SIZE MSR的值的相对大小,较小的参数将被报告为最小监视器行大小。较大的值被报告为最大监视器行大小

 

8.10.6.1 在旋转等待循环中使用PAUSE指令

 

Intel建议一条PAUSE指令应该被放置在运行在支持Intel超线程技术和多核处理器的Intel处理器上的所有旋转等待循环中。

使用旋转等待循环的软件例程包括多处理器同步原语(旋锁、信号量和互斥体变量)以及空闲循环。这样的例程保持处理器核心忙于执行一个加载-比较-分支循环,当一个线程等待一个资源变得可用时。在这样的一个循环中包含一条PAUSE指令可极大地提升效率(见8.10.2小节)。下面的例程给出了一个使用一条PAUSE指令的一个旋转等待循环的例子:

 

上述的旋转等待循环使用了一个“test, test and set”技术来判定同步变量的可用性。当在写旋转等待循环时,这个技术是推荐的。

在比奔腾4处理器更早的IA-32处理器中,PAUSE指令被对待为一条NOP指令。

 

8.10.6.2 在C0空闲循环中的MONITOR/MWAIT的潜在用法

 

一个操作系统可以为不同的空闲状态实现不同的处理。在一个ACPI兼容OS上的一个典型的OS空闲循环在例8-24中展示:

例8-24: 一个典型的OS空闲循环

 

 

MONITOR和MWAIT指令可以被考虑在C0空闲状态循环中使用,如果这对指令被支持的话。

例8-25 在C0空闲循环中带有MONITOR/MWAIT的一个OS空闲循环

 

 

8.10.6.3 暂停空闲逻辑处理器

 

如果两个逻辑处理器的一个处于空闲状态或处于长时间的旋转等待循环中,那么用一条HLT指令显式地暂停那个逻辑处理器。

在一个MP系统中,操作系统可以将空闲处理器放置在持续检查为可运行的软件任务的队列的一个循环中。执行空闲循环的逻辑处理器相当大量的核心执行资源,这些资源可能被在物理包中的其它逻辑处理器使用。为这个理由,暂停空闲逻辑处理器会优化性能。如果在一个物理包内的所有逻辑处理器被暂停,那么处理器将进入一个省电状态。

 

8.10.6.4 MONITOR/MWAIT在C1空闲循环中的潜在使用

 

一个操作系统也可以考虑在其C1空闲循环中用MONITOR/MWAIT来代替HLT。在例8-26中给出了一个例子:

 

例8-26:在C1空闲循环中带有MONITOR/MWAIT的一个OS空闲循环

 

 

 

8.10.6.5 在共享执行资源的逻辑处理器上调度线程的指导方针

 

因为逻辑处理器,线程被分派到逻辑处理器执行的次序会影响一个系统的整体效率。以下指导方针推荐用于调度线程执行。

1、在将线程分配到共享同一个处理器核心中的执行资源的另一个逻辑处理器之前,将线程分派到每个处理器核心的一个逻辑处理器。(译者注:分配线程的时候应该针对一个物理处理器的所有处理器核心,为每个核心将线程分配到其中一个逻辑处理器上,而不仅仅只关注其中一个核心上的两个逻辑处理器。)

2、在带有两个或多个物理包的MP系统中,将线程分派出,给所有物理处理器,而不是将这些线程仅仅关注于其中一个或两个物理处理器。

3、使用处理器亲和性(affinity)将一个线程分派给一个指定的处理器核心或包,依赖于Cache共享拓扑。这个实践增加了处理器的Cache将含有一些线程的代码与数据的机会,当它在被挂起之后分派执行时。

 

8.10.6.6 消除基于执行的定时循环

 

Intel不鼓励使用依赖于处理器的执行速度的定时循环来测量时间。有几个原因:

1、当定时循环在一个IA-32处理器上被校准到一个时钟速度运行时,而在一个处理器以另一个时钟速度运行时就会发生问题。

2、校准基于执行的定时循环的例程,当运行在一个支持Intel超线程技术的IA-32处理器上时会产生不可预测的结果。这是由于在一个物理包内的逻辑处理器之间的执行资源的共享。

 

为了避免上述描述的问题,定时循环例程必须使用一个不依赖于系统中的逻辑处理器的执行速度的循环定时机制。下列源通常可用:

1、一个高分辨率的系统定时器(比如,Intel8254)。

2、一个在处理器内的高分辨率定时器(诸如,本地APIC定时器或时间戳计数器)。

 

8.10.6.7 将锁、信号量放置在对齐的,128字节的存储块

 

当软件使用锁或信号量来同步进程、线程或其它代码段时;Intel建议,仅有一个锁或信号量出现在一个Cache行内(或128字节扇区,如果128字节扇区被支持)。在基于Intel NetBurst微架构的处理器中(支持由两个Cache行组成的128字节扇区),遵循这个建议意味着,每个锁或信号量应该被包含在一个128字节的存储块中,该存储块在一个128字节的边界上开始。该实践最小化了服务锁所需要的总线交通。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值