流量控制决定了各种资源(网络缓冲器和连接)的分配,如资源如何被分配给消息、分配的粒度、资源如何被不同的消息共享等。良好的流量控制程序可以在少量额外开销的代价下降低消息的延迟,通过有效共享资源来提高网络吞吐量,降低网络功耗。流量控制协议的实现复杂度取决于路由器微架构的复杂性以及路由器之间资源信息的通信所需的布线开销。
消息、包、Flits和Phits
当一个消息被注入网络时,它首先被分割成数据包(简称为包),然后被分割成固定长度的flits(flits是flow control units的简称)。例如,一个128字节的缓存行从共享者发送到请求者,将作为一个消息被发送,如果最大的包大小大于128字节,整个消息将被编码为一个单一的包。这个包会包括一个包含目标地址的head flit、body flits以及表示包结束的tail flit。Flits可以进一步细分为phits(即physical units),对应于物理信道宽度。下图展示了消息到包以及包到flits的分解。简而言之,消息是网络中的通信逻辑单位,而数据包是对网络有意义的物理单位。一个数据包包含目的地信息,而一个flit可能不包含,因此一个数据包的所有flits必须走相同的路线。
消息、包于flits的组成:假设单个flit大小为16字节、缓存行为64字节,那么一个缓存行的包由5个flits组成,一个缓存一致性命令会是一个单独的flit
由于丰富的片上布线资源,片上网络中的信道往往很宽,所以消息很可能由单个数据包组成。不过在片外网络中,信道宽度受到引脚带宽的限制,这种限制导致flits被分解成更小的块,称为phits。迄今为止,在片上网络中,由于片上信道较宽,一个flit往往由单个phit组成,是信息的最小细分单位。注意如上图所示,许多消息实际上是单flit的包。
流量控制是根据资源分配的粒度来分类的,我们将在接下来的章节中讨论基于消息、数据包和flit粒度的技术。
基于消息的流量控制
我们从电路切换开始,这是一种在消息层面上工作的技术,粒度最粗。
电路交换(Circuit Switching)
从Core 0到Core 8电路交换的例子,同时Core 2被停顿(S:Setup Flit,A:Acknowledge flit,D:数据消息,T:Tail (deallocation) flit,每个D都表示一条消息,注意在第12和16周期时,源节点没有数据要发送)
电路交换将资源(链接)预先分配给整个消息,setup的信息被发送到网络,整条链路都被保留,并发回acknowledge信号,随后就可以发送数据,完整的工作流程如上图所示。由于链路是预先保留的,每一跳都不需要缓冲器来保存等待分配的数据包,因此可以节省能耗,但在setup和实际信息传输之间,链路是空闲的,其他想要使用这些资源的消息会被阻断,导致带宽利用率很低。
基于包的流量控制
基于包的流量控制技术首先将消息分解成数据包,然后在链路上交错放置这些包,从而提高链路利用率。与电路交换不同的是,这种技术将需要每个节点在缓冲区中临时存储网络中的包。
存储和转发(Store-and-forward)
在这种技术中,每个节点都会等待,直到收到整个包,然后再将包的每个部分转发给下一个节点。因此,每一跳都会产生较长的延迟,不适合对延迟要求较高的NoC。此外,存储和转发流量控制需要在每个路由器上有足够大的缓冲区来缓冲整个数据包,对NoC的适应性较差。在下图中,我们使用这种技术来发送从0到8的包,每个包需要5跳,因此每一跳传输包的延迟是5个周期。
虚拟直通(Virtual Cut-Through)
为了减少数据包在每一跳所经历的延迟,虚拟直通允许在整个包被当前路由器收到之前,将包传输到下一个节点,减小了延迟。如下图所示,相比之前传输整个包需要25个周期,这种技术只需要9个周期就可以完成。然而,带宽和存储仍然以数据包大小为单位分配,只有在下一个下游的路由器有足够的存储空间来容纳整个数据包的情况下,数据包才能继续发送。对面积和功率都很紧张的NoC来说,当包的尺寸较大时(如64或128字节的缓存行),很难容纳支持 虚拟直通所需的大型缓冲区。在下图b中,整个包在从节点2到节点5的过程中被延迟了,即使节点5的缓冲区可以容纳5个flits中的2个。
基于Flit的流量控制
相比前文中提到的技术,基于流量控制的机制对缓冲区大小的要求较低,有助于路由器满足芯片上严格的面积或功率限制。
虫洞(Wormhole)
与虚拟直通一样,虫洞流量控制也会对流量进行切割,允许flits在当前路由器接收到整个包之前,将流量转移到下一个路由器。然而,与存储和转发或虚拟直通不同,虫洞将存储和带宽分配给flits而非整个包,允许每个路由器中使用相对较小的缓冲区。这种技术延迟低,可以用更少的缓冲实现,对面积和功率的要求低,成为了现在采用的主要技术。
这种方式虽然有效使用了缓冲,但是对带宽的使用并不高效。尽管这种技术以flit的大小为单位分配存储和带宽,但一条链路会在路由器中的包的整个寿命期间都会被保留。因此,当一个包被停顿时,这个包所保留的所有物理链路都是空闲的。由于虫洞是以flit为单位分配缓冲,一个由许多flit组成的包可能跨越多个路由器,导致大量空闲的物理链路,导致吞吐量降低。如下图所示,每个路由器的缓冲大小为2个flit,节点1缓冲区空间不足导致停顿,整个通道被该数据包占用,如灰色所示。
虚拟通道(Virtual Channels)
虚拟通道被称为互联网络的“瑞士军刀”,最早是作为避免死锁的解决方案被提出的,但也被用于缓解流量控制中的队列头部阻塞(head-of-line blocking)以提升吞吐量,这种阻塞在上面所有技术中都会出现,具体来说就是每个输入口都有一个队列,当队列头部的数据包被阻塞时,就会使排在后面的后续数据包停顿,即使停顿的数据包还有可用资源可以使用。
从本质上来说,一个虚拟通道(VC)是路由器中的独立队列,多个VC共享两个路由器之间的物理连接,通过将多个独立的队列与每个输入端口连接起来,可以减少队列头部阻塞。VC在一个周期内对物理链路带宽进行仲裁,当一个占用某个虚拟通道的包被阻塞时,其他包仍可通过其他虚拟通道穿越物理链路。因此,VC提高了物理链路的利用率,提升了整个网络的吞吐量。
从技术上来说,VC可以应用于上述所有的流量控制技术,以减轻队列的压力。比如说,电路交换可以用虚拟通道而非物理信道来实现,这种技术称为虚拟电路交换。存储和转发流量控制可以和VC一起使用,有多个数据包的缓冲队列,VC在链路上逐包复用,虚拟直通也类似。由于NoC绝大多数采用虫洞流量控制,之后我们提到虚拟通道流量控制时,我们就默认是和虫洞一起使用的,以flits的粒度对缓冲和链路进行管理和复用。
VC流量控制的例子:A和B两个包各自被分解为4个flits(H:head,B:body,T:tail)
上图是一个说明VC流量控制的例子。A最初占用VC 0,目的地是节点4,B最初占用VC 1,目的地是节点2。在T=0时,A和B都有flit在节点0的左边输入VC中等待。A的head flit被分配到路由器1的左边输入VC 0,并获得开关分配,在T=1时前往路由器1。在T=2时,B的head flit获得开关分配并前往路由器1,存储在VC 1,与此同时,A的head flit未能获得路由器4(A的下一条)的VC,节点4的两个VC都被其他包的flit占用。A的第一个body flit继承了VC 0,并在T=3时前往路由器1,与此同时,B的head flit可以在路由器2分配VC 0并继续前进。在T=4时,B的第一个body flit从head flit继承了VC 1,并获得开关分配,继续前往路由器1。到了T=7时,B的所有flit都到达了路由器2,但A的head flit仍然被阻塞,继续等待一个空闲的VC以前往路由器4。
通过这个例子可见,首先在每个路由器上分配一个VC给head flit,其余的flit继承该VC,通过虚拟通道流量控制,不同的包可以在同一物理通道上交错传输。这种技术也被广泛用于解决死锁,包括网络内死锁以及协议级死锁。
下表给出了上述各种技术关于资源分配和利用的总结。
无死锁流量控制
死锁可以通过使用有特定限制的路由算法来解决,也通过我们接下来讨论的无死锁流量控制来解决,可以允许使用任何路由算法。
日期变更线(Dateline)和VC分区(VC Partitioning)
上图展示了两个VC如何解决路由协议中出现的死锁。每个VC都和单独的缓冲队列绑定,在物理链路上逐周期地进行时间多路复用。在途中,所有消息都通过VC 0发送,直到跨过日期变更线,消息被分配到VC 1,且不能重新被分配到VC 0,这就确保了信道依赖图(channel dependency graph, CDG)是无环的。
类似的想法也适用于各种流量无关的或自适应的路由算法,例如一个在X-Y和Y-X路线之间随机选择的路由算法可以通过强制所有X-Y数据包使用VC 0以及所有Y-X数据包使用VC 1来避免死锁。
逃逸虚拟通道(Escape VCs)
之前例子中,所有的数据包最初都被分配到VC 0并保持在VC 0,导致VC 1利用率很低。A new theory of deadlock-free adaptive routing in wormhole networks一文中Duato提出了逃逸虚拟通道的概念来解决这个问题。只要有一个无死锁的逃逸VC,所有其他VC就可以使用没有路由限制的完全自适应路由,而不是在所有虚拟通道之间强制要求一个固定的顺序或优先级,逃逸VC通常使用无死锁路由技术。
逃逸虚拟通道的例子(VC 1作为逃逸VC,采用维度顺序X-Y路由)
气泡流量控制(Bubble Flow Control)
另一个避免死锁的想法是,在不需要多个VC的情况下,确保缓冲之间的封闭循环依赖关系不会产生。即使使用DOR这样的无死锁路由,k元n维在每个维度存在一个环形网络,也可能产生循环依赖。气泡流量控制可以和虚拟直通结合使用,具体来说就是向网络中注入一些气泡,保证缓冲区中有充足的空间。下图展示了一个例子,R1有两个气泡,允许数据包P1输入。其余的路由器只有一个气泡,阻塞了P0和P2的输入。
缓冲区反压(Buffer Backpressure)
由于大多数NoC设计不能丢弃数据包,因此必须有缓冲区反压机制来进行停顿。当下一跳没有可用的缓冲区时,就不能继续传输flits。缓冲区反压的最小单位取决于流量控制协议,可以以包或flit为单位来管理,注意电路交换是一种无缓冲区的流量控制技术,因此不需要反压机制。两种常用的反压机制是基于信用(credit-based)和开关信号(on/off signaling)。
基于信用(credit-based):信用(credits)记录了下一条可用的缓冲区数量或容量,buffer被空出时,往前一跳发出信号增加信用计数,当一个flit离开当前路由器发往下一跳时,向其发出信号递减信用计数。
开关信号(on/off signaling):开关信号涉及相邻路由器之间的信号,当缓冲区的数量或容量低于阈值时,该信号被设置,以停止前一跳的传输。这个阈值需要提前设定。
实现
流量控制协议的实现复杂度取决于路由器微架构的复杂性以及路由器之间资源信息的通信所需的布线开销。这一节中我们主要讨论后者。
为周转时间(Turnaround Time)确定缓冲区大小
由于缓冲区过小导致的流量限制(C:Credit send,C-LT:Credit link traversal, C-Up:Credit update)
周转时间是指连续flits可以重复使用一个缓冲区之间的最小空闲时间,这个值如果较大会导致缓冲区的无效重复使用,从而导致网络吞吐量下降。如果缓冲区大小不能覆盖周转时间,那么网络就需要在每个路由器上限制流量,降低性能。周转时间会影响缓冲区大小,从而影响面积开销。如上图所示,两个路由器之间的连接在等待下游路由器空出缓冲区时,会空闲6个周期。
基于信用和开关信号的反压机制时间线如上图所示。在基于信用的反压中,周转时间至少是一个flit到下一个节点的延迟、返回信用信号的延迟和流水线延迟之和,如上图a。相比之下,在开关信号的反压中,周转时间至少是开关信号传播延迟的2倍、数据flit传播延迟和流水线延迟之和,如上图b。
反向信号线
虽然开关信号反压与基于信用的反压相比性能较差,但在信号线开销方面表现更好,如上图所示。不过,对NoC而言,面积和吞吐量通常更重要,因此基于信用的反压机制仍然更合适。