阅读文章:Dubois M . Memory Access Buffering in Multiprocessors[C]// International Symposium on Computer Architecture, 1986. ACM, 1986.
摘要
在高度流水的机器中,指令和数据在处理器和高速缓存中将被预取和缓存。这样做是为了减少平均访存延迟并且可以利用内存的交错性。无锁的高速缓存被设计为了避免处理器由于cache miss而阻塞。写缓存经常被包括在流水线机器中为了防止处理器因为写操作而等待。在一个共享内存的多处理器中,缓存访存请求有很多好处,因为每一个访存请求不得不通过内存到处理器的互连并且每一个访存都需要与其他处理器发出的访存请求竞争。同时,缓存访存请求会造成逻辑问题对于多处理器来说。这些问题将会被加剧当每一个处理器有一个私有内存且存储共享可写的数据,例如在一个基于高速缓存的系统又或是在一个拥有分布式全局内存的系统中。在这篇文章中,分析了在共享内存多处理器中缓存访存请求的好处和问题。文中表明缓存的逻辑问题与同步问题直接相关。文章也提出了一个简单的模型来评估由于缓存带来的性能提升。
1.Introduction
- 为了满足数据处理的需求,共享内存的多处理器系统成为趋势;
- 在多处理器中处理器连接到共享内存的互连比单处理器要复杂很多,因此多处理器中处理器到共享内存的传递会更慢,访存冲突和访问延迟问题能够通过分别连接一个本地内存到每个处理器解决。本地内存被作为高速缓存,在多处理器运行的时候动态分配并且关联的分配地址,如果本地内存是一个处理器物理地址看见的一部分,则它将在编译或者装载的时候分配并且随机的分配地址。本地内存可能包含共享数据,存在多个相同数据的副本不一致的问题,这个问题通常由硬件解决。一个处理器写入本地高速缓存的时候发送无效信号给所有拥有一个包含对应改变了的字的块的处理器的本地高速缓存,这样在随机访问到该块的时候,就不会出现多副本不一致问题了,但是本地内存必须被所有处理器编址。(?要所有处理器分别知道别的处理器的本地高速缓存地址)
- 三种不同的多处理器系统被研究,他们代表了共享内存多处理器系统:
- 1.共享全局内存系统,一个多处理器带有共享全局内存和私有的本地内存,共享内存可以被所有的处理器访问,本地内存与具体的处理器关联且不包含任何共享数据;
- 2.分布式全局内存系统,一个多处理器带有由本地内存组成的分布式全局内存。本地内存包含全局和私有数据,且可以被随机访问;图2a与2b的区别在于,对于2a来说远程访问的buffer就是处理器预取的buffer,而2b中处理器远程访问缓存用的buffer独立于处理器预取存储用的buffer;
- 3.基于高速缓存的系统,一个多处理器带有共享内存和私有高速缓存。共享内存包含代码和数据,高速缓存被关联访问。高速缓存可以包含或不包含共享数据,文中仅考虑写透和写会高速缓存;其中根据无效信号存储的位置是在处理器预取和存储用的缓存中还是用独立的缓存存储而分为两中结构。
2.Memory Access Buffering Technique
- 指令操作数预取,在指令被执行之前可以先进行译码,得到操作数地址进而进行访存取指,几个操作数预取可以在任何时间进行,理想的情况下,当指令进入执行单元的时候所有的内存操作数都已经取好了;
- STOREs指令缓存,stores能够在一个时钟周期完成,通过简单的将数据和地址写入一个STORE buffer中;
3.Sequential Consistency And Coherence In Multiprocessors
- 顺序一致性定义:一个系统是顺序一致性的,如果所有处理器的操作是按照某个队列顺序则任何操作的结果都是相同的,并且每个单独的处理器出现在操作队列中的操作是按照程序给定的。(简单的理解就是在所有处理器能够访问到的共享数据需要是最新的,同时多个处理器之间的数据交互需要是合法的即可,在该顺序下可能会造成错误)
- 存储系统一致性定义:一个存储系统是一致的,如果LOAD指令返回的值总是相同地址对应的STORE指令存入的最新的值。(关于“最新值”的概念有些模糊,因为STOREs指令会将值存入与所有处理器相关联的缓冲区中,所以最新值是指STORE指令的执行还是内存的更新呢?)为了理清存储系统一致性的定义,文中区分了初始化、发射和执行一个内存访问。
- 内存请求初始化、发射和执行定义:当一个访存请求被处理器送出且请求的完成与否不受处理器控制的时候一个访存请求就算是被初始化了;一个被初始化的请求当其离开处理器环境在存储系统中传输的时候它就算是被发射了;对于处理器1的LOAD,对于处理器K的相同地址的STORE指令不会影响到处理器1的LOAD指令的返回值,则表示处理器1的LOAD指令执行了;对于处理器1的STORE指令,如果处理器k对于相同地址的LOAD指令返回的值是STORE指令存入的最新的值,则表示处理器1的STORE指令执行了;一个对于处理器1的访问被执行了当所有处理器都执行了;
- 关于发射和执行一个内存执行的基本区别:一个处理器的STORE指令不能影响其他任何处理器在这条STORE发射之前,同理一个内存的LOAD指令不能被任何其他指令影响直到它被发射。当STORE指令被发射但是没有执行的时候,它可能会影响到已经发射的相同地址的其他处理器的LOAD的结果;当STORE指令已经被执行了,则它肯定会影响其他处理器相同地址的LOAD指令的结果。
- 存储访问的强顺序定义:在一个多处理器系统中,存储器访问是强顺序的,如果任何一个处理器访问一个全局数据的初始化、发射、执行都按照程序的顺序并且当处理器1关于全局数据的STORE指令被处理器K观察时,所有在STORE指令发射前到全局数据的访问关于处理器1的执行必须要被关于处理器K执行。(即在STORE前面发射的访存指令必须要在STORE指令发射前执行,确保返回值不被影响)。(强顺序定义保证了:1.访问全局数据的顺序严格按照程序的顺序;2.所有在STORE指令请求发射前的由处理器1发射且观察的全局访问指令在LOAD请求被执行后由处理器K发射且观察的全局访存指令前发生;)
- 在前面给出的系统1中实现强顺序一致性需要满足的条件:1.全局存储访问只能在存储器中执行;2.单个处理器按照程序顺序初始化全局数据访问,这些访问(包括LOAD和STORE)被存储在与处理器关联的本地缓存中。本地缓存符合FIFO策略,缓存内部前递技术严格由条件1限制;3.预取和STORE的组合缓存控制器发射执行存储访问按照FIFO的顺序一个一个进行;
- 强一致性算法导致效率较低的几个原因:1.受限制的争夺在组合缓存中也不被允许;2.组合缓存必须要等到上一个共享存储访问执行才发射下一个访问请求;3.预取和存储缓存分开会提升CPU性能;
- 弱一致性定义:如果一个多处理器系统存储器访问是弱顺序性的则其满足:1.访问全局同步变量是强顺序性;2.在一个处理器中在所有先前的全局数据访问已经执行前没有对于同步变量的访问的指令的发射;3.在处理器访问同步变量执行完之前没有对于全局变量的访问的发射;(在弱一致性中对于共享变量有两种类型需要区分,一是在算法中出现的共享操作数其不影响执行的一致性;二是同步变量其保护共享可写操作数的访问或应用在同步两个不同的处理器;)对于弱一致性中的同步变量,文中认为如果没有程序员的帮助仅靠编译器进行识别是非常困难的,这些变量在编译的时候需要赋给他们特殊的LOAD和STORE指令;
- 在系统1上进行简单的关于缓存的性能分析:用tp表示两个连续的共享数据访问指令在一个处理器实现时候存在的计算时间的均值(计算时间指处理器访问本地数据的时间)、Ps表示一条指令是包含访问一个共享数据的操作的概率、Is.p.表示当所有的访问都是本地访问时候的MIPS 速率。此时可以得到公式tp = 1/(Is.p. Ps);tissue和tperform表示分别发射和执行一个请求的最小时间;系统1中有M个内存模型,他们以相同的概率被访问,且每个内存的访问时间为Tm;用tinref表示平均互相干扰时间在一个处理器的两个两虚的访问共享变量的操作下,它是整个时间包含处理器计算和等待的时间;
- 对于公式1,在没有缓存的时候,根据文中所给的模型,一次访问共享数据首先是处理器访问本地存储(其实是等待一个平均时间直到有访问共享数据的请求到来)时间为tp,接着指令被发射出去需要等待执行时间为tperform,等指令执行完成后,需要进行访存操作进行写回这段时间为Tm(?为什么没有加上发射时间呢);
- 对于公式2,即系统中存在缓存,且为强顺序性要求,所以需要等访存指令执行后才能进行下个访存指令的操作,同时处理器的平均等待时间是tp,所以就要计算一个执行时间和平均等待时间的大值作为结果;
- 对于公式3,与公式2相同只不过是在弱一致性条件下,第二条访存指令可以在第一跳指令发射后就进行操作,所以在处理器平均等待时间和发射时间中取大值为结果;
- 以上公式均为大于等于号是因为文中假设带宽足够且没有考虑访问冲突、依赖性等问题;
4.Multiprocessors with distributed global memory
- 在强一致性的定义中,有两个条件需要满足,一个是所有访存指令的初始化、发射、执行需要按照程序的顺序;另一个就是在STROE指令前的所有访问共享数据的指令要在STORE指令执行前执行;因为在系统2中所有的STORE指令都被视为原子操作,则在系统2中仅需要满足条件1就可以达到强一致性和顺序一致性;
- 在前面介绍的系统2分布式全局内存系统中,存在两种结构,一是将远程访问缓存与预取存储缓存合并为一个缓存;另一种是将远程访问缓存与预取存储缓存独立开来;在第一种结构中:当访问请求被送到互连网络,则一个远程存储访问被发射,当它被放置在远程缓存目的地中它将会被执行;一个本地访存被发射且执行当它被放置在本地缓存中;
- 对于系统2的第二种结构:为了最大化处理器到本地的带宽,远程访问被设置了一个较低的优先级;同时为了在系统中实现强一致性,本地或者远程访问被看作是执行的当他们在本地或远程分别执行;这会导致强一致性下系统的效率很低,此时弱一致性将会显得更好,它发射一个本地引用通过启动一个存储周期,同时发射一个远程引用通过简单的锁存他们在互连的第一阶段。然而无论什么时候,一个处理器执行一个被声称是同步变量(由编译器标记或者使用特殊的指令)时,处理器必须确保所有之前的数据访问已经执行,并且停止发射预取和存储操作数直到同步变量指令执行完;
5.Cache-based Multiprocessors
- 在基于高速缓存的多处理器中,每个处理器有一个本地高速缓存,其中存储来源共享存储中的数据和指令;文中区分该系统下的软件实现和硬件实现的一致性,同时每个处理器拥有的高速缓存可以是写透(直接写入内存)或者写回模式(先写入高速缓存中将其标记为dity,之后再写会内存)的;
- 软件实现一致性:利用编译器和程序员的提示来禁止一致性问题,只要没有共享可写数据能被加载到高速缓存中,就不会存在一致性问题。关于缓存,基于高速缓存的软件实现一致性的系统与系统1面对的问题是相同的。其他的缓存系统用软件实现一致性是可能的,但是在本文中不讨论;
- 对于硬件实现一致性,文中主要讨论存储共享数据的数据高速缓存。如果高速缓存包含了共享可写数据,则多个处理器的高速缓存中该数据副本的一致性将由硬件无效信号维持。同时,在一些一致性算法中,一个处理器可以广播一个LOAD信号给所有高速缓存如果都miss则传给内存,这是为了直接从别的处理器的高速缓存中直接读到数据。在系统3中的事件顺序问题比其他两个系统都要复杂。例如,对于一个STORE指令和它发出的无效信号正在进行时,被改过的变量的副本存在于不同的高速缓存和共享内存中,因此一个STORE指令可能不是原子操作了。文中讨论了关于强一致性定义在系统3的两种结构下的实现,下面的讨论中用Pdata表示在高速缓存中的私有数据,Sdata表示共享在几个高速缓存中的数据;
- 对于系统3a来说,一个由处理器1发出的与处理器K相关的STORE指令当在高速缓存中命中且数据是最新的,或者当数据被放置在内存缓存中且无效信号已经传递给处理器K的本地缓存的时候,这两种情况下指令STORE是被执行的。此时有几种方法来实现强一致定义的第二个条件:方法1.造成缺失的LOAD指令和对共享数据造成无效信号的STORE指令将被广播给所有的高速缓存和内存,使他们能够同时执行针对所有处理器;一个高速缓存能够从另一个高速缓存中读其缺失的数据块。因此假设由处理器1发出的与处理器K相关的LOAD指令在高速缓存周期命中(在处理器1的高速缓存中命中)或者没有命中时,请求已经被传送到处理器K的内存缓和本地缓存后执行。这意味着LOAD和STORE指令可以以原子指令的方式执行;这种方法可以通过少量的总线来实现;方法2.在方法2中高速缓存能够以点对点的形式互连成环或网格。当一个共享数据的STORE指令必须要传递无效信号时候,共享内存中相应的位置会被第一时间锁住防止其他处理器访问。之后无效信号通过点对点连接按照固定的顺序传递。当无效信号已经传递到每个高速缓存的本地缓存时,STORE指令才在内存中执行,这时候STORE指令才被视作执行完成。对于LOAD指令,只有当其成功访问到内存时候才会被视为执行了的(即没有STORE指令锁住内存)。这样LOADs指令在高速缓存或者内存中按照原子指令的方式执行;对私有数据的STOREs指令按照原子指令的方式执行,对共享数据的执行按照一个接一个顺序进行。文中认为这种方法对于无总线结构的基于高速缓存的系统很好;
- 对于系统3b:放置无效信号的缓存和放置预取和存储的缓存不是同一个。当远端的高速缓存块的无效信号是在高速缓存中执行时,这个无效信号被看作执行了。维持STOREs指令的原子性是困难的,因为每个高速缓存的无效信号缓存可能包含不同数量的无效信号请求导致使高速缓存对应的块无效的信号的时间随机。维持强一致性的方案2对于这种情况使有效的,不过需要让无效信号传递的时候将当前高速缓存对于块设为无效。(?为什么3a系统不会出现缓存中存在很多无效信号的问题)对于弱一致性系统,处理器可以不等前面的内存请求执行完就发射新的内存请求,这可以提升处理器效率,但是唯一的问题是对于同步变量的访问。缓存控制器可以记录所有已经发射但没有执行的高速缓存访问请求,以便执行同步变量的访问每当其被探测到的时候,这种缓存控制器实现很复杂不在该文的讨论范围。
6.Conclusion
- 文章提出了一个数据访问被缓存在处理器中并且处理器和共享存储是互连的共享存储多处理器系统中的一致性问题的分析框架。文中介绍了三种共享存储请求可能回出现的三种状态,当数据访问被缓存的时候文中使用这三种状态定义强一致性并且通过显示强一致性和顺序一致性的的等价性来证明这三种状态是基础的。为了解决强一致性对处理器造成的性能问题文中引入了弱一致性概念。
- 文中分析了三个系统分别在无缓存、有缓存强一致性、有缓存弱一致性下的性能。在第一个系统中,文章还给出了一个简单的模型来确认系统在不同一致性策略有效时的参数范围。该模型可以扩展到其他系统并且更多复杂的模型可以保证突出缓存在具体系统中的优势。本文采用的基本方法能确定在非常复杂的系统下添加两种策略的缓存的基本限制,例如在基于高速缓存的系统下。作者认为这方面需要更多的工作。
读后感&记录
- 文章首先介绍了三种多处理器共享内存系统,在此基础上提出了共享内存系统存在的同步问题。同时介绍了顺序一致性、强一致性、弱一致性的概念,并在系统1上进行了简单的共享内存系统的分析,分析了在有无缓存和采用何种一致性策略的情况下,执行一条指令需要的时间;同时分析了不同策略有效的系统参数范围;最后文中分析了在不同的系统下,分别实现强一致和弱一致性所需要的条件和方法;
- 共享内存多处理器系统:1.共享全局内存系统;2.分布式全局内存系统;3.基于高速缓存的系统
- 一致性类别:
- 顺序一致性:所有处理器中指令的执行按照某个队列顺序,单个处理器中指令的执行按照程序所指定的顺序,不同处理器直接指令的执行可以是随意的;
- 强一致性:在顺序一致性的基础上,不同处理器之间指令执行的顺序也要按照某种固定的顺序以保证不会出现共享数据同步性的问题;
- 弱一致性:在访问全局共享同步变量的时候需要满足强一致即可,需要编译器和程序员的帮助,可以提高处理器效率但是比较难实现;
- 一致性原则的实现:
- 系统1:
- 实现强一致性:1.全局存储访问只能在内存中执行;2.每个处理器按照程序给定的顺序初始化全局数据访问指令,这些访问请求被存储在与处理器关联的本地缓存中,该缓存满足FIFO策略;3,存储预取和STOREs指令的缓存控制器按照FIFO的顺序每次发射一条指令;
- 系统2:
- 实现强一致性:在系统2中LOADs和STOREs指令被视为原子操作,因此它们在执行的时候不存在数据同步性问题,所有只要满足强一致性的第一个定义,就可以实现强一致性;
- 系统3:
- 实现强一致性:1.软件实现:利用编译器和程序员的提示来禁止共享可写数据加载到处理器的高速缓存中,则不同处理器的高速缓存之间就不存在一致性问题;2.硬件实现:方法一,将miss的LOAD指令和产生无效信号的STORE指令将被广播给所有高速缓存和内存保证LOAD和STORE指令的原子性;方法二,将处理器的高速缓存连接成环状或者网格状,在访问共享数据的STORE指令需要传递无效信号的时候,共享内存中相应的位置会立即被锁住放置其他处理器访问;
- 系统1: