本文分析了Intel Haswell微架构的事务内存的可能实现方式,属于翻译文章,其中添加了一些译者自己的理解。
原著:David Kanter
原名:Analysis of Haswell’s Transactional Memory
原文:http://www.realworldtech.com/haswell-tm/
翻译:CoryXie <cory.xie@gmail.com>
我(译注:当然是指本文原作者)个人的兴趣和专长,是推测性的多线程(speculative multithreading, SpMT)和事务内存(TM)。 两者都是旨在使多核处理器和并行编程更适合于开发者的技术。我作为Strandera的联合创始人(Strandera是一个初创公司),几年来在事务内存(transactional memory)和动态二进制翻译的基础上开发推测性的多线程(speculative multithreading)。 Strandera给我提供了一个极好的机会,使得我在过去5年可以接触到在这些领域的许多领先的学术和商业研究人员,以及一些x86微处理器架构师。
前阵子,我的朋友和同事,Andreas Stiller报告了一个英特尔即将推出的Haswell微架构将包括事务性内存的传闻 。 这个传闻最近被证明是真实的,英特尔证实,Haswell包括了事务性同步扩展(Transactional Synchronization Extensions),或TSX。 对我来说这是非常令人兴奋的,我很高兴能利用我的专业知识和经验,来讨论这些创新。
学术研究
现代软件开发中最深刻的挑战之一是多核处理器的出现。 在过去的10年中,单个CPU内核的速度越来越快,但应用程序必须针对并行执行进行优化,以充分利用摩尔定律的动力和性能优势。 在此之前,并行编程技术主要用于科学计算或关键任务,以及性能敏感的工作负荷,如数据库和ERP系统。 多核趋势意味着消费类应用的开发者第一次被推到了多线程和并发编程的世界中。
事务内存(Transactional memory)是一个软件技术,简化了并发程序的编写。 TM借鉴了在数据库社区中首先建立和发展起来的概念,该社区已处理并发性大约30年。 基本的想法是要申明一个代码区域作为一个事务。一个事务(transaction ) 执行并原子地提交所有结果到内存(如果事务成功),或中止并取消所有的结果(如果事务失败)。 TM的关键是提供原子性(Atomicity),一致性(Consistency )和隔离性(Isolation )这些素质,使数据库和SQL可以被普通的开发人员访问。 这些事务可以安全地并行执行,以取代现有的痛苦和容易犯错误的技术,如锁和信号量。 还有一个潜在的性能优势。 锁是悲观的(pessimistic ),并假设上锁的线程将写入数据,因此,其他线程的进展被阻塞。 访问锁定值的两个事务可以并行地进行,且回滚只发生在当事务之一写入数据的时候。
推测性的多线程(SpMT)侧重于使用多个硬件线程(或多个内核)携手合作,加速一个单一的软件线程。 在本质上,单一的软件线程推测性地分裂成多个线程,可以并行地执行。 事务是推测性线程的自然契合(natural fit),因为它提供了一种简单的方法来回滚不正确的猜测。 SpMT的主要优点是,它使现有的单线程代码(这是所有软件的绝大多数)可以利用多核处理器带来的好处。
SpMT,特别是TM,在学术界有一个长期和著名的历史,我由于我所工作的Strandera的原因对此相当熟悉。 TM是由Maurice Herlihy 和 Eliot Moss于1993年在一份论文中首提出的,这先于多核处理器。 SpMT可追溯到1995年Guri Sohi的 Multiscalar项目。 随着时间的推移,这两个领域成为非常流行的研究点,且几乎所有的计算机体系结构部门都有关注这两个主题的项目。 2000年前后,研究人员开始将TM当作一种多核编程技术,并且许多人意识到,这是SpMT的一个自然匹配。
软件TM已经存在数年,许多程序员都玩过TM库。 但是,软件TM性能开销极大,2-10倍的速度下降是常见的,这就排除了软件TM的广泛使用。 为了使得TM不仅仅是用于研究的玩具,硬件加速和支持是必要的。
一个与事务内存(transactionalmemory)相关的技术,叫做锁省略( lockelision),是在2001年,由Ravi Rajwar 和 James Goodman率先提出的。 该想法是设计硬件来更有效地处理锁,而不是使能事务。 如果两个线程都被预测到只会读取被锁的数据,则锁就会被删除(或被省略),从而两个线程可以并行执行。 类似于TM,如果一个线程写了该被锁定的数据,处理器就必须回滚,并使用锁来重新执行,以保证正确性。 锁省略( lockelision)的优势是,可以很容易地与传统代码集成,而TM需要软件做出很大的变化。
商业发展
其中一个最早的事务内存实现是Transmeta的Crusoe和Efficeon处理器,在该处理器中使用了门控存储缓冲器(gated store buffer)。 然而,这只是用来帮助对二进制翻译的推测性优化(speculativeoptimizations),而不是任何形式的SpMT或直接将它暴露给程序员。 Azul Systems还实现了硬件TM来加速他们的Java设备,但是这也同样被隐藏着不为外界所知。 对于所有意图和目的,TM大多只是作为学术界的一个有趣想法而被冷落。
幸运的是,SunMicrosystems公司决定在高端的Rock微处理器中实现硬件TM以及有限的SpMT。 总设计师Marc Tremblay,在众多的会议文件和会谈中讨论过这一点。 该TM是相当不错的,Sun的开发人员表明,它可用于锁省略和更复杂的混合TM系统中,其中事务被硬件和软件相结合的处理。 不幸的是,Rock被 Sun在2009年取消了。 虽然产品没有出来,还是有一些原型系统提供给研究人员,这是对研究社区的一个巨大帮助。
在2009年,AMD提出了先进同步工具(Advanced Synchronization Facility),这是一组x86扩展,提供了一个非常有限的硬件TM支持。 其目标是提供硬体原语,可用于更高水平的同步,如软件TM或无锁算法。 但是,AMD还没有宣布ASF是否将在产品中使用,如果是的话,以什么样的时间表推出。
最近,IBM在2011年宣布,Blue Gene/Q 的硬件支持TM和SpMT。 该TM可被配置在两种模式下。 第一个是无序的(unordered )单一版本模式,一个事务的写操作将导致与读相同内存地址的任何事务冲突。 第二种模式是SpMT,是一个有序的(ordered)多版本TM。 推测性线程(Speculative threads)可以对相同的内存地址有不同的版本,硬件跟踪每个线程的年龄。 年轻的线程可以访问旧线程的数据(但是反之则不行),并且写入同一地址是基于线程的顺序的。 在某些情况下,线程之间的依赖关系可能会导致中止年轻的版本。
最近的发展当然是英特尔的TSX,以及在Haswell中的实现。 Haswell是第一款配备了硬件事务内存的x86处理器。 英特尔的TSX规范描述了如何将TM暴露给程序员,但隐瞒了实际TM的实现细节。 这篇文章的第一部分讨论了英特尔TM的软件接口。 基于此,第二部分,根据我的经验分析了英特尔TM可能的实现细节。
英特尔的事务性同步扩展
TSX(Transactional Synchronization Extensions)规范提供了两个接口,供程序员利用事务内存。 首先是硬件锁省略(Hardware Lock Elision,HLE),非常紧密地映射到以前由Rajwar 和Goodman的工作。 这应该没有什么可惊讶的,因为RaviRajwar已经在英特尔工作了相当长的一段时间。 第二种模式是受限的事务内存( RestrictedTransactional Memory,RTM),它类似于经典的TM建议。 两者都采用了新的指令来利用底层基础TM硬件,但目标是相当不同的。
底层TM跟踪事务的read-set 和write-set ,以一个64字节的高速缓存行为粒度。这里的read-set 和write-set 分别表明事务在执行过程中已读出或写入的所有高速缓存行。 如果事务的read-set中的一个高速缓存行被另一个线程写入,或者事务的write-set 中的一个高速缓存行被另一个线程读取或写入,则事务就遇到冲突(conflict)。 对于那些熟悉TM术语的人而言,这就是所谓的强隔离(strong isolation),因为一个非事务性(non-transactional)内存访问可能会导致事务中止(abort)。 冲突通常导致事务中止,且在一个高速缓存行内还可能发生假冲突(falseconflicts)。
TSX可以允许事务相互嵌套,在概念上是通过将嵌套展平成单个事务来处理的。 然而,嵌套的数量有一个具体实现特定的限制,超过此限制将导致中止。 在一个嵌套事务内的任何中止,都将中止所有的嵌套事务。
事务只能使用可高速缓存的回写内存操作(write-back cacheable memory operations),但可以在所有的权限级别下使用。不是所有的x86指令都可安全地用于事务内。 有几个x86指令将导致任何事务(对于HLE或RTM)中止,特别是CPUID和PAUSE。
此外,在特定的实现中,还有些可能导致中止的指令。 这些指令包括x87和MMX,混合访问XMM和YMM寄存器,EFLAGS寄存器的非状态部分的更新,更新段(segment),调试(debug )或控制(control )寄存器,ring 转换,高速缓存和TLB控制指令,任何非写回(non-writeback)内存类型的访问,处理器状态保存,中断,I / O,虚拟化(VMX),可信执行(SMX)以及一些杂项类型。 注意,这意味着上下文切换(context switch),通常使用状态保存(state saving)指令,几乎总是会中止事务。 一般来说,TSX 实现的目的是要相对于指令向上兼容。 例如,如果一个实现在事务中新增对VZEROUPPER的支持,则该功能将不会在未来的版本中删除。
也有运行时的行为可能会导致事务中止。大多数的错误和陷阱都会导致中断,而同步例外和异步事件可能会导致中止。自修改代码和访问非写回内存类型也可能导致中止。
事务的大小也有具体实现特定的限制,且各种微架构的缓冲(buffers)可能是限制因素。 一般情况下,英特尔对有关事务的执行没有提供保证。虽然对于程序员而言这是令人沮丧的,因为它需要一个非事务性的(non-transactional)回退路径,这样就避免了未来的向后兼容性问题。即便当程序员写了一个不太可能成功的事务,它也避免了使系统死锁。
受限的事务内存
具有讽刺意味的是,RTM(Restricted Transactional Memory)是更强大的而有颠覆性的(powerful and disruptive)技术,但在概念上却更简单。 RTM将可嵌套的事务内存暴露给程序员,这是一个用来表达并行性的非常强大的模型。不足之处是,它需要开发不同的事务性执行代码,而不是插入到现有代码的提示。
RTM对于开发者来说,是一个选项(option),但不是要求(requirement)。在一个事务之外的代码不必服从前面提到的限制。考虑到事务的所有要求,这是必要的。这也给英特尔引入新的x86功能提供了一次奢侈的机会,不必担心TM的实现细节或开销。
有三个新的指令,XBEGIN,XEND和XABORT。 XBEGIN指令启动一个事务,还提供了到回退地址(fallback address)的一个16位或32位的偏移。 如果在任何时候事务中止,该线程将跳到回退地址继续执行。在整个事务的执行过程中,存储器访问都被使用read-set 和write-set 做跟踪,以检测冲突。
如果在事务期间发生冲突,就可能会触发一个中止(abort)。 然而,实际结果是实现特定于的。 例如,如果两个事务冲突,都可能被中止。 一个更明智的做法是中止两个事务其中之一,但用于确定哪一个成功的一致规则,将是有益的。
XEND指令表示事务的结束。如果XEND指令是嵌套事务的最后一个(即最外层的事务,outermost transaction),那么它会尝试以原子方式提交更改。 一次成功提交会用在事务过程中产生的新值来覆盖原有的体系结构状态(architectural state),包括寄存器和存储器。 从内存序(memory ordering)的角度来看,所有的内存操作表现得像是在以原子方式执行。 如果提交失败,则对体系结构状态(architectural state)的变化都将被中止。
【译注:下图是从IDF 2012一份介绍Intel TSX的文档摘录的,介绍了如何使用RTM。
】
中止(abort)将会回滚事务的执行过程中产生的所有体系结构状态(architectural state)发生的任何变化,恢复到第一个XBEGIN指令(即最外层的事务,outer most transaction)之前的状态。 这包括对任何体系结构寄存器(architectural registers)或内存的写操作。在一组嵌套的事务中,任何中止都将导致整个嵌套事务中止。 此外,中止(abort)会更新EAX寄存器,使用8位值来说明中止的可能原因。 最后,执行重定向到回退点(fallback point)。 如果一组嵌套的事务中止,那么回退地址是从第一个XBEGIN指令处(即最外层的事务)取得。
【译注:下面是《Intel Architecture Instruction Set Extensions Programming Reference》中RTM abort状态定义:】
XABORT指令立即触发一个中止(abort),就好像一个提交不成功一样。在程序员可以决定一个事务要失败的时候,一个明确的中止(abort)命令是非常有用的,不需要来自硬件上的任何帮助。 提前中止事务可以帮助降低性能和功耗代价(performance and power penalty)。
硬件锁省略
HLE(Hardware Lock Elision)更容易与现有的x86软件集成,并且也向后兼容没有TSX支持的x86微处理器。 就像它的名字所说,其目标是对共享数据使能不冲突的同时访问,以提高同步的性能。
HLE引入了两个新的指令提示前缀,称为XACQUIRE和XRELEASE,用来表示锁省略的范围。 XACQUIRE指令,是获取锁的前缀。它表示锁省略区域的开始。 锁指令的内存地址被添加到事务的read-set,但不写入新数据到锁地址。
线程接着进入事务性执行(transactional execution),继续运行HLE内部区域中的指令,并将内存访问添加到 read-set 和 write-set中。 任何HLE区域内部读该锁地址都将返回新数据(译注:该新数据虽然没有写入锁地址,但是被本地硬件保持,在读这个锁地址时返回,用以造成锁已经被获得的假象,实际上并没有做获得锁的操作),但另一个线程的任何读操作都将返回旧数据(译注:这样就造成别的线程可以与正在事务性执行的线程并发执行,直到出现冲突而中止并真正带锁重新运行该区域,或者在没有冲突时无锁完成)。 这使得许多线程可以同时获得锁,并对共享数据做无冲突的内存访问。
XRELEASE是用于释放锁地址的指令前缀,它标志着HLE区域结束。 由于锁地址没有在该区域的起始处被写入,无需进一步的写操作将其恢复到原来的值。 在最外层的XRELEASE,处理器试图提交事务,如果成功的话,那么HLE区域被顺利执行,但是没有获取或释放锁。
【译注:下图是从IDF 2012的一份介绍Intel TSX的文档摘录的,示例了如何使用HLE。】
如果发生冲突,则处理器体系结构寄存器(architectural registers)的状态将恢复到XACQUIRE之前,并丢弃任何在HLE区域内写入的内存。 线程将再次执行该区域,就像没有HLE,而使用标准的悲观锁行为(pessimistic locking behavior)。 跨越高速缓存行的任何锁都不能被省略,并会自动触发没有HLE的重新执行。
可以同时被省略的锁数量,也有一个具体实现特定的限制;任何更多的锁都将被正常执行。 尽管嵌套的HLE是存在的,但是递归锁是不被支持的(译注:这就限制了对某些操作系统中可嵌套锁的优化,例如VxWorks中由semMCreate创建的互斥量)。在HLE区域内对锁地址进行写操作,将导致HLE中止。
【译注:在《US20070136289A1-Lock elision with transactional memory》这个专利中,描述了可以允许递归的锁省略的情形。】
另一个潜在的HLE中止的来源是驻留在同一高速缓存行的锁。由于英特尔TM只能以高速缓存行为粒度进行跟踪,两个相同的高速缓存行上的锁会导致别名(aliasing)以及不必要的HLE中止。
没有HLE支持的硬件,将简单地忽略提示前缀,并使用标准的行为执行该区域。HLE的主要好处之一是,兼容现有的基于锁的编程模型,只需要开发人员很少的努力就可实现。
【译注:下图说明了HLE是如何实现的。
】
Haswell的背景
虽然英特尔的TSX文档相当精确地描述了RTM和HLE的语义,却没有底层TM和Haswell的具体实现的关键细节。 但是,有足够的信息来推测Haswell的TM性质。 让我们看看什么是已知的:Haswell实现了一个无序的(unordered),单一版本的(single version),具有强隔离的(strong isolation)嵌套TM。 TM以一个固定的64B的高速缓存行为粒度,跟踪read-set和 write-set。
作为一个起点,假设Haswell的内存层次结构可能类似于Sandy Bridge的,每个核大约32KB L1和256KB L2高速缓存(由两个线程共享),以及一个由所有核共享的L3缓存。几乎可以肯定,Haswell 扩展了英特尔现有的高速缓存行为和MESIF一致性协议 ,以支持事务内存的语义。目前完全重新定义一致性协议太冒险,这也将大大增加保持完全兼容性的挑战。它也完全不同于英特尔的一贯做法,往往倾向于对主流x86产品不断增强而不是激进的重新设计。
英特尔的服务器团队以现有的CPU核心,建立自定义的模块,包括L3高速缓存,QPI逻辑,I / O,内存控制器和电源管理,通过一个高性能互连绑在一起。 Haswell的一致性的变化很可能仅限于L1和L2高速缓存,严格位于核内。 这具有以下优点,英特尔的服务器组可以利用Haswell 的工作,只需要用最小的额外投资和努力。 最重要的是,限制核的变化,避免额外的验证,这是对服务器处理器的成本和进度的最大贡献之一。
Haswell的事务内存
基于上述假设,我们可以勾勒出最有可能的Haswell的事务内存(transactional memory)的实现细节。 最重要的被遗漏的细节涉及到的TM版本管理,冲突处理以及提交和中止操作。
Haswell的事务内存(transactional memory)最有可能是延迟更新系统(deferred update system),使用每个核的高速缓存(per-core caches)作为事务数据和寄存器检查点。 具体而言,L1D和L2的每个高速缓存行中的标签可能包含一些比特位,表明该行是否属于可以在Haswell 核上执行的两个线程的read-set(RS)或write-set(WS)。事务中的一个存储(store)操作将简单的写高速缓存行,而共享的L3缓存保存原始数据(对于事务中的第一次写,可能需要更新L3为Modified )。 这与自从Nehalem以来一直沿用的共享和包容性的L3缓存(shared and inclusive L3 cache)是一致的。 为了避免数据损坏,任何事务性数据(即RS或WS中的缓存行)必须留在L1D或L2,而不是被驱逐(evicted)到L3或内存。 体系结构寄存器(architectural registers )被设置检查点(checkpointed),并存储在芯片中,且事务可以自由地读取和写入寄存器。
或者,事务被限制到Haswell的L1D缓存也是可能的。这将简化设计,但使TM健壮性减小。对于中等规模的事务,L1D真的是关联度不够;关联性驱逐(associativity evictions)可能会在少到9个高速缓存行时就发生,即使每线程大约有256个缓存行。 使用L2几乎消除了大部分的关联性驱逐,并且每个线程将有大约平均2.2K个缓存行,且固定的最大约为4.5K个缓存行。 同样,英特尔很可能同时将L1D和L2用于事务数据,以避免潜在的关联性问题。
【译注:根据http://www.realworldtech.com/haswell-cpu/5/,实际上,Haswell的事务内存是将事务的write-set 和 read-set维持在L1数据高速缓存中的。L2高速缓存是非事务性的(non-transactional),因此如果一个write-set的缓存行被驱逐(evicted),事务就会中止。有趣的是,在某些情形下,似乎read-set的缓存行可以被安全地驱逐(safely evicted)出L1,并且使用另外一个硬件机制来跟踪。一种可能性是使用一个片上的transactional victim buffer,或者某种内存存储。在中止(abort)的情况下,所有的write-set的缓存行都被从L1D中清除,而提交(commit)则会使得write-set缓存行原子地可见。由于构建于TSX的吞吐量的益处之上,相比于Sandy Bridge的16个周期,Haswell的最小锁延迟可以小到大约12个周期,稍微比两个相互依赖的L1D命中多点。下图说明了具体的TSX实现。】
冲突检测
我上面列出的基于缓存的系统的优点是,Haswell的冲突检测可以通过现有的一致性协议来处理,只需要对内存排序缓冲(memory ordering buffers),L1D和L2高速缓存做轻微的增强。 发生冲突只可能会有三种方式,所有这些都可以被轻易地检测到。
首先要考虑的情况是,一个RS的缓存行被另一个核写。在英特尔的MESIF协议中,写一个潜在的共享高速缓存行,需要无效任何其他私有高速缓存的副本。另一个核将发送一个read-for-ownership请求给共享的L3缓存,这将检查嗅探过滤器(snoopfilter),并发送一个无效(invalidate )命令给具有该缓存行副本的任何缓存。如果L1D和L2高速缓存接收到对一个RS高速缓存行的无效(invalidate )命令,这表明另一个线程在试图写,并发生了冲突。
第二个要考虑的情况是,被另一个核访问(读或写)WS的高速缓存行。为了事务在第一时间能写高速缓存行,其他的核不能有副本,这是处于Modified一致性状态的标准语义。 然而,包容性的L3高速缓存(inclusive L3 cache)将保留事务之前的过时原始版本。 因此,如果另一个核试图访问WS中的高速缓存行,它就会在其本地L1D和L2高速缓存中扑空(miss),进而探测L3。 然而,L3将访问嗅探过滤器( snoop filter),然后发送read(或read-for-ownership)请求给WS中具有该高速缓存行的核。如果L1D和L2的WS中的一个高速缓存行收到任何读请求(或无效请求),就发生了冲突。
上述两种情况处理的是不同的核干扰事务的情形。第三个可能性是,在同一个Haswell内核中共享该内核的L1D和L2高速缓存的另一个线程干扰事务的情形。 在这种情况下,另一个线程将命中(hit)共享的L1D和L2缓存,而不通过L3高速缓存触发任何一致性通信。 然而,这可以通过检查高速缓存行是否在另一个线程的WS中,在加载流水线(load pipeline)中处理;也可以通过检查高速缓存行是否在另一个线程的(RS)或WS中,在存储流水线(store pipeline)中处理。
最后的预防措施是,如果任何RS或WS的高速缓存行被驱逐到L3或内存中,必须中止事务。 对于WS缓存行的情况,这是为了防止事务数据覆盖L3保持的原来的高速缓存的拷贝。 从严格意义上讲,RS缓存行可以被保持在L3高速缓存中,但这会使得问题相当复杂,而简单地中止事务却很容易。很有可能英特尔修改了L2高速缓存行的替换和驱逐策略,以避免驱逐事务性数据。 将L2高速缓存用于事务的另一个优点是,相比于L1D高速缓存,L2替换算法可以容忍显著更多的延迟,在这里他们是在任何L1D 扑空(miss)的关键路径上。
【译注:下图说明了如何实现冲突检测。
】
提交和中止
在上面列出的系统中,提交(commit)事务是一个简单的问题。 L1D和L2高速缓存控制器,确保在WS中的任何高速缓存行处于Modified 状态,并将WS比特位清零。同样地,任何RS(但不是WS)中的高速缓存行必须是在Shared状态,RS比特位被清零。老的寄存器文件检查点被删除,且寄存器文件的现有内容成为体系结构状态(architectural state)。
基于一致性的冲突检测方案可以在其发生时就尽早识别到冲突(而不是在提交时)。 一旦冲突被早期发现,很有可能会立即终止该事务。然而,在某些实现方式中,其他的问题也可能会导致延迟中止(deferred aborts)。
中止事务,比提交事务更简单。高速缓存控制器改变所有WS的缓存行为Invalid状态,并将WS比特位清零。控制器也必须清零RS比特位,但它不必无效高速缓存行(虽然Haswell 可能做了这一点)。最后,从旧的检查点恢复体系结构寄存器文件(architectural register file)。
在Haswell中,使用适当的指令,英特尔的受限事务内存(Restricted Transactional Memory)或多或少提供了一个对底层TM的直接接口。 硬件锁省略(Hardware Lock Elision)可能使用了相同的基本技术,但需要一些额外的缓冲。 被省略的任何锁,都可能被保持在Haswell的存储缓冲区(或者是一个小型的专用结构,可以并行访问)。 因此,在 HLE区域内的任何访问都读取新的锁值,而旧值被保留在缓存中,以便其他线程可以同时执行。
TSX分析
TSX的成功完全取决于Haswell如何工作好。幸运的是,英特尔Haswell的事务内存(transactional memory)似乎是直截了当的,逻辑相对简单,只要事务可以跨越L1D和L2高速缓存,性能应该是不错的。 基于几种实现(Azul, Sun Rock, Transmeta)的后见之明,TSX似乎已经避免了许多问题。以前的硬件TM系统被关联性冲突所困扰,英特尔可能将L2高速缓存用于事务数据而解决【译注,不幸的是,Intel似乎还是走了老路,只使用了L1D】。 TSX中止操作可以返回一个代码,表示中止的原因,以帮助诊断硬件和软件错误,且调试器支持也是规范的一个组成部分。基于TM系统构建硬件锁省略(Hardware Lock Elision)是一个聪明的举动,有助于以最小的努力使得现有代码很容易获得性能提升,使开发人员能够在承诺写基于受限事务内存(Restricted Transactional Memory)的代码之前测试TSX。
【译注:默认情况下,RTM区域内的任何调试异常都将导致事务中止,控制流重定向到回退指令地址,体系结构状态(architectural state)被恢复,且EAX第4位被设置。不过,为了让软件调试器在出现调试异常时拦截执行,RTM架构提供了额外的功能。
如果DR7的第11位和IA32_DEBUGCTL_MSR1的第15位都是1,任何由于调试异常(#DB)或断点异常(#BP)导致的RTM中止,都会导致执行回滚并从XBEGIN指令重新启动,而不是跳到回退地址(fallback address)。在这种情况下,EAX寄存器也将被还原回到XBEGIN指令点。】
RTM没有担保向前推进的事实,以及要求非事务性的备用路径是有点鱼龙混杂。 一方面,它创建了一个额外的负担,对于程序员来说,这相当不具吸引力。 然而,它也巧妙地避开了处理写得不好的事务代码和兼容性的问题。最终会有人写出可怕的事务代码,使得任何可行的系统都会死锁。强制程序员处理微妙的细节,如高速缓存的关联性冲突是不合理的,但底层的硬件资源有限。 如果没有某种形式的虚拟化的事务内存(transactional memory),总会有对于事务不能成功的担心。
一般情况下,英特尔的TSX对于提高并发工作负载的可编程性和可扩展性,应该是有帮助的。 即使是中等数量的线程,锁也可以很容易地限制更多核的好处。虽然对于2-4个核的处理器这是没有问题的,这却是一个更大的向前发展的阻碍因素。非常流行的应用程序(如MySQL)具有著名的由锁引起的问题,HLE或RTM可以显著缓解。
在一些领域,特别是集中在低层次的软件系统中,有直接的应用。 首先,Azul 和Sun已经证明,锁省略(lock elision)和TM是用于Java和其他动态语言的可扩展垃圾收集的功能强大的工具。 此外,所有现有的软件TM系统的研究可以充分利用英特尔的RTM,以减少开销。多伦多大学的研究表明,软件TM可以为Quake游戏服务器提供一个中等性能增益(基于锁的版本),而英特尔的RTM应该有更好的效果。 看看不同的软件供应商可以基于英特尔已经提供的构建模块做出些什么将是很迷人的。
事务内存的演化
展望未来,英特尔的事务型内存(transactional memory)有一些潜在的改进点。 第一,最明显的是走向一个多版本TM,更适合推测性多线程(speculative multithreading)。 英特尔并没有从这条道路开始有点令人失望,即使它潜在的要更复杂些。 也许IBM Blue Gene/Q能够表现出足够的好处,以鼓励更复杂的TM系统。 其他改进可能包括对嵌套事务的部分中止(partial aborts),以及让程序员可以控制冲突事务的处理。
对英特尔的其他途径是,在整个x86产品线扩散事务内存。今天主要是针对移动设备的SoC,而即将到来的是多核的Knight’s Corner。 很难看到Atom这个功耗非常敏感的变体的直接应用,但那可能取决于将TSX应用于主流产品。 如果TSX展示出一种特别吸引人的好处,也许是为运行微软的.NET语言或Android的Dalvik,未来的移动CPU很可能附带事务内存的支持。
事务内存适合于未来的多核产品是自然和明显的。 英特尔的RTM比许多替代品无疑是一个更简单的编程模型,通过库和扩展可以增强现有的语言,如C + +。 此外,对于有几十个内核和数百个线程的设计,能显著提高可扩展性的潜力有令人难以置信的吸引力。 例如,DougCarmean的演讲强调了在Larrabee早期版本中处理锁争用面临的挑战。 TSX可能会去除大多数程序的锁争用的问题,除了在真的存在依赖时需要串行化来确保正确性的时候。 总体而言,如果Knight’sCorner的后继不支持某些版本的TSX将是令人惊讶的。
除了英特尔外,行业的其余厂家似乎有可能在未来几年内采用不同的事务内存。 甲骨文曾公开表示,未来的SPARC处理器将包括memory versioning(TM的另一种说法)。 IBM已经推出Blue Gene/Q,虽然目前还不清楚何时(或是否)POWER 或zArchitecture处理器将采用TM。 ARM的TM立场还不清楚,但一旦ARMv8扩展被敲定就可能演变。
AMD正在继续努力于ASF,其中有几个与TSX的实质性差别:特权指令,向前发展的保证,中止时没有寄存器回滚等仅仅是几个例子。AMD和英特尔面临一个抉择:将x86的生态系统用不兼容的扩展分段,或者协调ASF和TSX。 从行业的角度来看,后者显然是最好的,并且有一个风险,即软件供应商可能不愿意容忍这种不兼容。不过,这可能需要几年的时间来让英特尔和AMD使它们的实现一致。
英特尔采用事务内存是计算机体系结构的一个新时代。 Haswell代表近二十年的旅程,从最初的事务内存在学术界的提出,到主流微处理器的采用。对于我们这些工作在事务内存领域的人,这是一个非常激动人心的时刻。是时间回过头来审视将这个行业带到这里的那些贡献,并开始思考在未来几年内可能展开的机会了。
术语解释
Speculative multithreading (SpMT),also known as thread level speculation (TLS), is a dynamic parallelization techniquethat depends on out-of-order execution to achievespeedup on multiprocessor CPUs. It is a kind of speculative execution that occurs at thethread level as opposed to the instruction level.