李少迪 吳俊敏 張 屹 周亞偉
1(中國(guó)科學(xué)技術(shù)大學(xué)軟件學(xué)院(蘇州) 江蘇 蘇州 215123) 2(中國(guó)科學(xué)技術(shù)大學(xué)計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院 安徽 合肥 230026)
并行程序間的通信是并行程序之間進(jìn)行相互協(xié)作、共同完成任務(wù)的基礎(chǔ),隨著計(jì)算機(jī)技術(shù)的廣泛應(yīng)用,單純的計(jì)算任務(wù)已經(jīng)不再是制約程序性能的唯一因素,程序之間的通信對(duì)程序執(zhí)行的效率的影響也越來(lái)越大。尤其是在互聯(lián)網(wǎng)、云平臺(tái)等商業(yè)并行環(huán)境下,程序間的高效通信對(duì)提升系統(tǒng)整體性能有重要意義。
申威26010處理器是由我國(guó)上海高性能集成電路設(shè)計(jì)中心研發(fā)的一種異構(gòu)眾核處理器,主要應(yīng)用于高性能計(jì)算領(lǐng)域,是“神威太湖之光”超級(jí)計(jì)算機(jī)[1]的主要組成部分。申威26010處理器在許多高性能計(jì)算領(lǐng)域取得了應(yīng)用[2-3]。但是,由于申威26010處理器存在運(yùn)行環(huán)境復(fù)雜、軟件開(kāi)發(fā)與底層硬件結(jié)構(gòu)高度相關(guān)等特點(diǎn),申威26010處理器上普通商業(yè)應(yīng)用的開(kāi)發(fā)移植有一些困難。因此,本文利用了協(xié)程的思想,在申威26010處理器上實(shí)現(xiàn)了協(xié)程的運(yùn)行框架,以協(xié)程的方式代替對(duì)從核上線程的直接使用,構(gòu)建了更適合開(kāi)發(fā)的虛擬化環(huán)境,并且使申威26010處理器能夠?qū)崿F(xiàn)更高的并發(fā)能力。
作為協(xié)程運(yùn)行框架中的一個(gè)重要部分,協(xié)程間的通信模塊需要高效地實(shí)現(xiàn)。本文首先設(shè)計(jì)以循環(huán)緩沖區(qū)為基礎(chǔ)的生產(chǎn)者-消費(fèi)者模式的通道通信方式,并且基于主核與從核上支持的不同原子操作,在主核與從核上分別設(shè)計(jì)了通道通信的同步機(jī)制來(lái)保證在有多個(gè)生產(chǎn)者或多個(gè)消費(fèi)者進(jìn)行競(jìng)爭(zhēng)時(shí)保證通道消息傳遞的正確性;然后,本文根據(jù)協(xié)程切換的便捷性,設(shè)計(jì)了生產(chǎn)者與消費(fèi)者互相喚醒的機(jī)制,減少了由于程序的等待造成的時(shí)間浪費(fèi);并且,由于協(xié)程在從核上的通信性能表現(xiàn)較差,本文基于從核間的寄存器通信方式設(shè)計(jì)了從核陣列上新的通信方式。
申威26010處理器是一種由我國(guó)上海高性能集成電路設(shè)計(jì)中心自主研發(fā)設(shè)計(jì)的一種異構(gòu)眾核處理器,屬于申威處理器系列,申威26010處理器采用片上計(jì)算陣列集群和分布式共享存儲(chǔ)相結(jié)合的異構(gòu)眾核體系結(jié)構(gòu),常用于超級(jí)計(jì)算機(jī)的搭建與高性能計(jì)算程序的運(yùn)行,申威26010眾核處理器擁有獨(dú)特的計(jì)算與存儲(chǔ)結(jié)構(gòu),其硬件設(shè)計(jì)如圖1所示。
圖1 申威26010處理器
每一個(gè)申威26010處理器芯片包含了260個(gè)核心,劃分為4個(gè)核組(CG),每個(gè)核組中包含了一個(gè)運(yùn)算控制核心(MPE),稱(chēng)為主核,從屬的64個(gè)計(jì)算核心(CPE),稱(chēng)為從核,主從核的頻率都為1.45 GHz。64個(gè)從核按照8×8結(jié)構(gòu)組合成一個(gè)從核陣列。每個(gè)核組通過(guò)內(nèi)存控制器(MC)與一塊8 GB內(nèi)存相連,四個(gè)核組之間由片上網(wǎng)絡(luò)(NoC)連接在一起,申威26010處理器基于alpha指令集設(shè)計(jì),其中:主核支持完整的alpha指令集;從核上支持精簡(jiǎn)的alpha指令集。存儲(chǔ)結(jié)構(gòu)上,主從核都能對(duì)內(nèi)存進(jìn)行訪問(wèn),主核有兩級(jí)緩存結(jié)構(gòu),保證主核對(duì)內(nèi)存的快速讀寫(xiě),而從核沒(méi)有對(duì)內(nèi)存讀寫(xiě)的緩存,但每一個(gè)從核包含一塊64 KB的局部存儲(chǔ)器(LDM),可以存儲(chǔ)從核上運(yùn)行的程序以及從核運(yùn)行所需的數(shù)據(jù)。每一個(gè)從核可以對(duì)自己的LDM進(jìn)行快速讀寫(xiě),但不能訪問(wèn)其他從核的LDM,從核對(duì)主存的訪問(wèn)有兩種模式,一種是細(xì)粒度的全局讀入/讀出,這種方式的通信帶寬較低;另一種是粗粒度的DMA訪問(wèn)方式,可以將主存上的連續(xù)數(shù)據(jù)傳輸?shù)綇暮说木执嬷校巧晖姾颂幚砥魍瓿筛咝阅苡?jì)算主要的數(shù)據(jù)I/O方式。單處理器的峰值雙精度浮點(diǎn)計(jì)算性能為3.06 Tflops。
申威26010處理器支持Linux操作系統(tǒng),在支持的語(yǔ)言類(lèi)型上,主核上支持C/C++、FORTRAN程序的運(yùn)行,在從核上支持C、FORTRAN語(yǔ)言程序的運(yùn)行。由于申威26010處理器上的主核與從核有不同的運(yùn)行環(huán)境,所以對(duì)主核與從核上的程序需要分別編寫(xiě)與編譯,最后通過(guò)混合編譯將主核與從核上的運(yùn)行程序打包在一個(gè)可執(zhí)行文件中,通過(guò)作業(yè)提交命令提交給系統(tǒng)執(zhí)行。
從申威26010處理器的計(jì)算構(gòu)成可以看出,從核的計(jì)算能力占申威26010處理器計(jì)算能力的98%以上,所以申威處理器上程序的開(kāi)發(fā)需要發(fā)揮出從核的運(yùn)算能力,一般以主從核并行模式為基礎(chǔ),使用Athread加速線程庫(kù),在主核上完成計(jì)算任務(wù)的分配,將計(jì)算任務(wù)進(jìn)行劃分并分配給從核來(lái)運(yùn)算執(zhí)行,主核完成從核所不能完成的計(jì)算部分以及通信。主從核并行方式讓從核來(lái)程序核心計(jì)算部分,主核只負(fù)責(zé)管理,是申威上高性能計(jì)算程序開(kāi)發(fā)的必然選擇。
協(xié)程是一種由用戶控制的,不需要操作系統(tǒng)調(diào)度就能夠進(jìn)行程序的切換運(yùn)行程序,實(shí)現(xiàn)并發(fā)的方式,協(xié)程的概念并不復(fù)雜,基本原理是在程序運(yùn)行時(shí)一個(gè)運(yùn)行程序主動(dòng)讓出自己的運(yùn)行控制權(quán),這樣就能切換到其他的程序運(yùn)行。由于協(xié)程相比于線程消耗的系統(tǒng)資源很少,因此常用于高并發(fā)場(chǎng)景中[4-5]。由于申威26010處理器的一個(gè)從核上僅有一個(gè)線程運(yùn)行,并且不能進(jìn)行線程的切換操作,從核上程序的并發(fā)受到限制,而使用協(xié)程的方式,可以突破從核的并發(fā)限制,能夠在只有單線程的從核上實(shí)現(xiàn)多并發(fā)。于是我們團(tuán)隊(duì)決定在申威眾核處理器上開(kāi)發(fā)一個(gè)協(xié)程的運(yùn)行框架。基于申威眾核處理器的主從并行結(jié)構(gòu),設(shè)計(jì)實(shí)現(xiàn)一個(gè)集合了調(diào)度、執(zhí)行、通信等模塊的協(xié)程運(yùn)行庫(kù),將從核上的線程以協(xié)程的方式來(lái)利用,取代原本對(duì)從核線程的直接使用,這樣能獲得更高的并發(fā)度。協(xié)程運(yùn)行框架基于申威26010處理器硬件結(jié)構(gòu)與申威Athread加速線程庫(kù),為上層應(yīng)用提供協(xié)程使用接口,上層應(yīng)用程序使用協(xié)程進(jìn)行并發(fā)設(shè)計(jì)時(shí),能夠?qū)⒂?jì)算任務(wù)進(jìn)行更細(xì)的劃分,從而獲得更高的性能實(shí)現(xiàn)。協(xié)程運(yùn)行庫(kù)的層級(jí)如圖2所示。
圖2 協(xié)程運(yùn)行庫(kù)的層級(jí)
申威眾核處理器上協(xié)程的實(shí)現(xiàn)包含以下幾個(gè)部分:
(1) 調(diào)度器。調(diào)度器運(yùn)行在主核上,負(fù)責(zé)完成協(xié)程的初始化任務(wù),創(chuàng)建協(xié)程并根據(jù)從核的負(fù)載情況將協(xié)程分配到不同從核上執(zhí)行器的執(zhí)行隊(duì)列,等待執(zhí)行器的執(zhí)行。
(2) 執(zhí)行器。執(zhí)行器運(yùn)行在從核上,每一個(gè)從核上只能運(yùn)行一個(gè)執(zhí)行器,所以每個(gè)核組包含64個(gè)執(zhí)行器,能夠執(zhí)行具體的程序,每個(gè)執(zhí)行器包含了兩個(gè)隊(duì)列,分別是可運(yùn)行任務(wù)隊(duì)列與阻塞隊(duì)列,可運(yùn)行隊(duì)列中包含能夠直接運(yùn)行的協(xié)程程序,阻塞隊(duì)列中包含由于通信等原因阻塞的協(xié)程任務(wù)。
(3) 通信模塊。協(xié)程間如果想要完成相互協(xié)作,則需要在協(xié)程間進(jìn)行數(shù)據(jù)的通信,本文的主要工作即為實(shí)現(xiàn)協(xié)程間的通信,包含通道通信方式與基于寄存器通信的方式。
通道的設(shè)計(jì)目標(biāo)是能夠在主核與從核、線程、協(xié)程間進(jìn)行數(shù)據(jù)的通信。本文以生產(chǎn)者-消費(fèi)者模式實(shí)現(xiàn)消息通信。由于主核與所有的從核都能夠訪問(wèn)主存,通道設(shè)計(jì)中將消息數(shù)據(jù)保存在主存中,并使用循環(huán)緩沖區(qū)的結(jié)構(gòu)來(lái)存儲(chǔ)消息數(shù)據(jù)。循環(huán)緩沖區(qū)是一種先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu),相對(duì)于隊(duì)列減少了對(duì)地址的反復(fù)操作,增加了穩(wěn)定性,被廣泛應(yīng)用在不同領(lǐng)域中[6-7]。循環(huán)緩沖區(qū)能夠方便地實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者機(jī)制的數(shù)據(jù)交換,并且能夠?qū)?shù)據(jù)的寫(xiě)入與讀取操作分離開(kāi)來(lái),避免讀取線程與寫(xiě)入線程的相互競(jìng)爭(zhēng),提高通信效率。本文使用循環(huán)緩沖區(qū)作為通道的基礎(chǔ)結(jié)構(gòu),循環(huán)緩沖區(qū)的工作原理如圖3所示。
圖3 循環(huán)緩沖區(qū)原理
圖3是通道的緩沖區(qū),其中空白的區(qū)域代表可以接收消息的空間,實(shí)心區(qū)域代表已經(jīng)存放消息的空間,read指針指向緩沖區(qū)內(nèi)下一個(gè)能進(jìn)行讀取的數(shù)據(jù),write指針指向下一個(gè)能存放數(shù)據(jù)的單元。使用循環(huán)緩沖區(qū)可以輕松地實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模式,在一個(gè)生產(chǎn)者向一個(gè)消費(fèi)者發(fā)送數(shù)據(jù)的過(guò)程中,生產(chǎn)者從通道獲取write的值,根據(jù)write值獲得buffer中將要寫(xiě)入數(shù)據(jù)的位置,若緩沖區(qū)未滿,則將數(shù)據(jù)復(fù)制到buffer,同時(shí)將write的值加一,就完成了一次消息的發(fā)送。同理,當(dāng)消費(fèi)者讀取時(shí),讀取read值并讀取數(shù)據(jù),將read值加一。當(dāng)read或write超過(guò)緩沖區(qū)的容量時(shí),通過(guò)除以緩沖區(qū)容量獲得的余數(shù)來(lái)獲得相應(yīng)位置。當(dāng)read與write相等時(shí),說(shuō)明緩沖區(qū)為空,當(dāng)write與read的差值等于緩沖區(qū)容量時(shí),說(shuō)明緩沖區(qū)已滿。由于生產(chǎn)者只影響write指針,消費(fèi)者只影響read指針,所以在只有一個(gè)讀線程與一個(gè)寫(xiě)入線程的情況下,無(wú)須對(duì)緩沖區(qū)進(jìn)行同步操作,通信的效率較高?;谘h(huán)緩沖區(qū)的結(jié)構(gòu),通道的數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)如算法1所示。
算法1通道的數(shù)據(jù)結(jié)構(gòu)
struct channel {
unsigned char *buffer;
unsigned int elem_size;
unsigned int capacity;
unsigned int read;
unsigned int to_read;
unsigned int write;
unsigned int to_write;
list read_wait;
list write_wait;
};
其中buffer指向存放數(shù)據(jù)的緩沖區(qū),elem_size代表一條消息數(shù)據(jù)的大小,capacity代表緩沖區(qū)的容量,write是緩沖區(qū)寫(xiě)入下標(biāo),read是緩沖區(qū)讀取下標(biāo),to_read與to_write作為read與write的對(duì)照,用于在多生產(chǎn)者或多消費(fèi)者并發(fā)地進(jìn)行通道的發(fā)送與接收時(shí)保證數(shù)據(jù)同步。兩個(gè)list是為了存放因不能向通道發(fā)送或接收消息而進(jìn)入阻塞的生產(chǎn)者或消費(fèi)者協(xié)程的隊(duì)列,是通道上生產(chǎn)者協(xié)程與消費(fèi)者協(xié)程互相喚醒機(jī)制的一部分。
利用循環(huán)緩沖區(qū),可以在單生產(chǎn)者單消費(fèi)者的情況下不需要同步機(jī)制就能安全地進(jìn)行消息的傳遞。但是在有多個(gè)生產(chǎn)者或多個(gè)消費(fèi)者時(shí),多個(gè)線程對(duì)同一個(gè)數(shù)據(jù)的爭(zhēng)奪可能會(huì)產(chǎn)生數(shù)據(jù)被覆蓋的情況,在多線程競(jìng)爭(zhēng)時(shí),使用同步機(jī)制是有必要的[8]。在申威26010處理器中,主核上可以有多個(gè)線程運(yùn)行,每個(gè)從核上有一個(gè)線程運(yùn)行,當(dāng)主核或從核上運(yùn)行的程序間進(jìn)行通道通信時(shí),有可能產(chǎn)生競(jìng)爭(zhēng),必須使用同步機(jī)制來(lái)保證通信的正確性。在申威異構(gòu)眾核處理器中,主核與從核有不同程度的指令支持,所以在主核與從核上有不同的同步機(jī)制實(shí)現(xiàn)。
2.2.1主核上通道同步的實(shí)現(xiàn)
在多線程同步機(jī)制中,可以使用CAS(compare-and-swap)原子操作對(duì)多線程競(jìng)爭(zhēng)的情況進(jìn)行處理,CAS操作能在一條指令中完成數(shù)據(jù)的比較與交換,常用于無(wú)鎖算法的實(shí)現(xiàn)[9]。GCC中的CAS接口如下:
bool__sync_bool_compare_and_swap(type*ptr,type oldval,type newval,…)
這是返回原子操作是否成功的一個(gè)CAS接口,輸入?yún)?shù)分別為:需要更新的變量的地址ptr,與變量進(jìn)行對(duì)比的值oldval,變量要更新為的值newval。當(dāng)讀取到變量地址上的數(shù)據(jù)值與進(jìn)行對(duì)比的值oldval相等時(shí),就能成功地將變量的值更新為新的值newval,此時(shí)返回true,若從變量地址讀取到的值與所認(rèn)為的值不等,則不進(jìn)行數(shù)據(jù)的更新,返回false。
當(dāng)兩個(gè)線程同時(shí)使用CAS指令時(shí),只有一個(gè)線程能夠成功,其他的線程將會(huì)失敗,從而保證了只有一個(gè)線程能夠繼續(xù)對(duì)數(shù)據(jù)的處理。利用CAS操作構(gòu)建通道消息發(fā)送的一致性保護(hù)機(jī)制如算法2所示。
算法2主核上的通信同步實(shí)現(xiàn)
do {
if(full(chan))
continue;
temp=chan->write;
if(temp !=chan->to_write)
continue;
ok=CAS(&chan->write,temp,temp+1);
} while (!ok);
//復(fù)制數(shù)據(jù)到緩沖區(qū)
CAS(&chan->to_write,temp,temp+1);
同步的消息發(fā)送中,此算法使用CAS操作并利用to_write作為write值的對(duì)照,通過(guò)比較write與to_write的值是否相等來(lái)判斷是否進(jìn)行發(fā)送操作,如果不相等,說(shuō)明有其他的生產(chǎn)者正在對(duì)通道發(fā)送數(shù)據(jù),需要等待另一個(gè)生產(chǎn)者完成操作;若write的值與to_write相等,說(shuō)明沒(méi)有其他的生產(chǎn)者在進(jìn)行操作,就可以對(duì)通道進(jìn)行消息發(fā)送;使用CAS操作更新write的值,若成功,說(shuō)明沒(méi)有其他的協(xié)程成功改變write值,就能根據(jù)write將要發(fā)送的數(shù)據(jù)復(fù)制到緩沖區(qū)相應(yīng)位置;最后,對(duì)to_write的值進(jìn)行CAS操作,使其加一,就完成了一次消息的發(fā)送。由于write與to_write的初值相等,每一次的消息發(fā)送操作對(duì)兩個(gè)變量都加一,所以在沒(méi)有生產(chǎn)者正在進(jìn)行消息發(fā)送時(shí),write的值與to_write的值一定相等,若發(fā)現(xiàn)兩個(gè)變量的值不等時(shí),說(shuō)明有生產(chǎn)者在對(duì)通道進(jìn)行消息的發(fā)送。從通道中接收消息時(shí)也同理,對(duì)read與to_read進(jìn)行CAS操作來(lái)保證在有多個(gè)消費(fèi)者進(jìn)行競(jìng)爭(zhēng)時(shí),緩沖區(qū)內(nèi)的數(shù)據(jù)不會(huì)被重復(fù)讀取。這樣,此算法就實(shí)現(xiàn)了主核上向通道發(fā)送消息以及從通道讀取消息的同步。
2.2.2從核上通道同步的實(shí)現(xiàn)
在主核上,可以使用CAS原子操作實(shí)現(xiàn)通道消息發(fā)送與接收的同步,保證通信的正確性。但是在從核上,由于指令支持不同,并不支持CAS操作,僅支持對(duì)數(shù)據(jù)直接修改的原子操作,如下:
updt_addw(_n_,_addr_)
參數(shù)_n_是需要讓變量增加的數(shù)值,_addr_是變量的地址。從核上的原子操作直接改變數(shù)據(jù)的值,而不進(jìn)行比較,因此相比于CAS操作,同步實(shí)現(xiàn)更加復(fù)雜。從核上利用原子操作來(lái)實(shí)現(xiàn)通道的同步如算法3所示。
算法3從核上的通信同步實(shí)現(xiàn)
while(1) {
if(full(chan))
co_swap_out();
temp=chan->write;
if(temp==chan->to_write)
updt_addw(1,&(chan->write));
else
continue;
if(chan->write==temp+1){
//復(fù)制數(shù)據(jù)到緩沖區(qū)
updt_addw(1,&chan->to_write);
return 0;
}else{
updt_addw(-1,&chan->write);
continue;
}
}
與主核上的同步實(shí)現(xiàn)類(lèi)似,從核上的同步使用to_write作為write的對(duì)照。不同的是,在對(duì)write值使用原子操作進(jìn)行更新后,由于沒(méi)有判斷write的值是否曾被其他的生產(chǎn)者修改,依然有可能發(fā)生比較和修改操作被兩條線程以比較->比較->修改->修改的方式分別執(zhí)行,導(dǎo)致write的值并不一定為修改前加一。因此需要再次判斷更新后write的值是否為預(yù)期值,若相等,說(shuō)明沒(méi)有其他的生產(chǎn)者修改write值,可以進(jìn)行消息發(fā)送并修改to_write,若不等,說(shuō)明其他的生產(chǎn)者也修改了write值,此時(shí)需要使用原子操作將write恢復(fù)為被此生產(chǎn)者訪問(wèn)前的狀態(tài),重新請(qǐng)求消息的發(fā)送。這樣,在多個(gè)生產(chǎn)者訪問(wèn)時(shí),最多只有一個(gè)生產(chǎn)者能夠向通道發(fā)送消息,保證了通道消息發(fā)送的同步。但是,在多個(gè)生產(chǎn)者進(jìn)行原子操作后對(duì)數(shù)據(jù)進(jìn)行對(duì)比時(shí),也有可能出現(xiàn)沒(méi)有生產(chǎn)者讀取到更新后的write值為更新前的值加一,導(dǎo)致所有的生產(chǎn)者都將write值進(jìn)行回退,沒(méi)有一個(gè)生產(chǎn)者完成對(duì)通道的消息發(fā)送,這會(huì)導(dǎo)致運(yùn)行時(shí)間的極大浪費(fèi),也使得在同樣數(shù)量的生產(chǎn)者或消費(fèi)者互相競(jìng)爭(zhēng)的條件下,從核上對(duì)通道的發(fā)送與接收效率可能會(huì)低于主核。
在通道通信中,想要進(jìn)行通信的線程有時(shí)無(wú)法進(jìn)行消息通信,如通道已滿時(shí)的生產(chǎn)者或通道為空時(shí)的消費(fèi)者,這時(shí)程序只能進(jìn)行等待。當(dāng)以多線程方式實(shí)現(xiàn)時(shí),可以選擇循環(huán)訪問(wèn)或線程切換的機(jī)制,但是由于線程的切換消耗的系統(tǒng)資源較多,會(huì)導(dǎo)致程序的性能下降,而協(xié)程的切換完全在用戶空間內(nèi)進(jìn)行,所消耗的資源很少,所以在協(xié)程間的通信無(wú)法進(jìn)行時(shí),我們選擇讓當(dāng)前協(xié)程直接進(jìn)入阻塞,讓其他協(xié)程運(yùn)行,來(lái)減少等待造成的時(shí)間占用。
當(dāng)一個(gè)消息生產(chǎn)者協(xié)程向通道發(fā)送數(shù)據(jù)時(shí),首先會(huì)判斷通道緩沖區(qū)是否已滿,若未滿,則發(fā)送消息并繼續(xù)運(yùn)行;若已滿,則此消息無(wú)法發(fā)送,通道會(huì)進(jìn)入阻塞,并由協(xié)程執(zhí)行器調(diào)度其他的協(xié)程來(lái)運(yùn)行。阻塞的協(xié)程將被記錄在通道的等待隊(duì)列read_wait上。被阻塞的協(xié)程不會(huì)自動(dòng)喚醒,也不是由協(xié)程執(zhí)行器喚醒,而是當(dāng)一個(gè)消費(fèi)者協(xié)程從通道取出消息,使通道不再為滿時(shí),會(huì)喚醒一個(gè)等待發(fā)送的生產(chǎn)者,此時(shí)阻塞的生產(chǎn)者協(xié)程重新進(jìn)入運(yùn)行隊(duì)列繼續(xù)運(yùn)行,并有較大概率成功向通道內(nèi)發(fā)送消息。同理,消費(fèi)者協(xié)程在通道為空時(shí)也會(huì)進(jìn)入阻塞,記錄在隊(duì)列write_wait上,并被一個(gè)向通道發(fā)送數(shù)據(jù)的生產(chǎn)者協(xié)程喚醒。這種互相喚醒的機(jī)制,讓一個(gè)協(xié)程在不能進(jìn)行通信的情況下直接讓出執(zhí)行權(quán),讓其他的協(xié)程運(yùn)行,而不是進(jìn)行循環(huán)等待,也沒(méi)有像線程切換那樣消耗大量的系統(tǒng)資源,更有效地利用了處理器核心的運(yùn)算能力。生產(chǎn)者與消費(fèi)者互相喚醒的流程如圖4所示。
圖4 生產(chǎn)者與消費(fèi)者的互相喚醒
互相喚醒的機(jī)制保證了一個(gè)協(xié)程因?yàn)椴荒苓M(jìn)行發(fā)送或接收操作而進(jìn)入阻塞,當(dāng)它被喚醒時(shí),通道的狀態(tài)能夠讓這個(gè)協(xié)程進(jìn)行消息發(fā)送或接收。相比于輪詢(xún)或者線程的切換,協(xié)程之間的互相喚醒的方式消耗系統(tǒng)資源更少,因此程序運(yùn)行的效率更高。
在進(jìn)一步的實(shí)驗(yàn)測(cè)試中,我們發(fā)現(xiàn),從核上通道通信的效率遠(yuǎn)低于主核,原因是:(1) 由于從核訪問(wèn)主存的性能較低;(2) 由于從核間多生產(chǎn)者或多消費(fèi)者競(jìng)爭(zhēng)時(shí)同步機(jī)制產(chǎn)生的性能損失大于主核。由于申威26010眾核處理器的主要計(jì)算能力來(lái)源于從核,因此提高從核上的通信效率對(duì)提高整個(gè)系統(tǒng)的性能有重要意義。于是,本文結(jié)合申威眾核處理器上獨(dú)特的從核間寄存器通信機(jī)制,在從核上實(shí)現(xiàn)更高效的數(shù)據(jù)通信。寄存器通信是一種申威眾核平臺(tái)上獨(dú)特的通信機(jī)制,可以在一個(gè)從核陣列上同行或同列的從核間高效地傳輸數(shù)據(jù)。同行間寄存器通信的接口如下:
LONG_PUTR(var,dest)
LONG_GETR(var)
LONG_PUTR用于向同行的從核發(fā)送數(shù)據(jù),其中:參數(shù)var代表進(jìn)行交換的數(shù)據(jù),dest指示目標(biāo)從核,dest低四位有效,當(dāng)最高位為1時(shí)向整行進(jìn)行廣播,最高位為0時(shí),低三位代表目標(biāo)從核在行或列中的位置。寄存器通信每次發(fā)送數(shù)據(jù)的大小為256位,并且延遲很低。LONG_GETR用于接收發(fā)送到本從核的通信緩沖中的數(shù)據(jù),當(dāng)通信緩沖為空時(shí),會(huì)等待直到接收到數(shù)據(jù)。使用寄存器通信可以為申威26010處理器上的程序帶來(lái)很大的性能提升[10-11]。
從寄存器通信的接口中可以看到,使用一次寄存器通信只能與同行或同列的其他從核進(jìn)行通信,不能向不同行且不同列的從核發(fā)送數(shù)據(jù)。所以,如果想要向一個(gè)不同行且不同列的從核發(fā)送數(shù)據(jù)時(shí),需要一個(gè)從核作為中轉(zhuǎn),如圖5所示。
圖5 向不同行也不同列的從核發(fā)送數(shù)據(jù)
以圖5中的方式就形成了一個(gè)單生產(chǎn)者-單消費(fèi)者的消息通信。只是一個(gè)從核需要作為中轉(zhuǎn)而無(wú)法執(zhí)行計(jì)算任務(wù)。并且這個(gè)從核與兩個(gè)從核中的其中一個(gè)在同一行,與另一個(gè)在同一列。從陣列的結(jié)構(gòu)中可以輕松地看出,可以作為中轉(zhuǎn)核的從核有兩個(gè)。作為中轉(zhuǎn)的從核從生產(chǎn)者從核由寄存器通信接收消息數(shù)據(jù),再通過(guò)寄存器通信發(fā)送到消費(fèi)者從核。
利用從核進(jìn)行中轉(zhuǎn)可以讓任意位置的生產(chǎn)者與消費(fèi)者之間進(jìn)行快速的消息傳遞,但是中轉(zhuǎn)的從核不能執(zhí)行計(jì)算任務(wù),這會(huì)導(dǎo)致計(jì)算資源的浪費(fèi)。為了在整個(gè)從核陣列上最大化用于計(jì)算的從核的數(shù)量,減少中轉(zhuǎn)導(dǎo)致的計(jì)算能力損失,應(yīng)當(dāng)盡可能減少中轉(zhuǎn)的從核數(shù)量。由于一行上的從核如果需要向其他行發(fā)送數(shù)據(jù),至少需要一個(gè)核向外發(fā)送數(shù)據(jù),所以使用8個(gè)從核作為中轉(zhuǎn),就能完成整個(gè)陣列上從核之間的數(shù)據(jù)傳遞。整個(gè)從核陣列上生產(chǎn)者-消費(fèi)者的通信設(shè)計(jì)如圖6所示。
圖6 整個(gè)從核陣列上生產(chǎn)者-消費(fèi)者的通信
圖6中第一列的8個(gè)核作為中轉(zhuǎn)核,隨機(jī)向后四行的從核發(fā)送消息,前四行其他列的從核作為生產(chǎn)者,進(jìn)行消息數(shù)據(jù)的生產(chǎn),后四行其他列的從核作為消費(fèi)者,接收消息并處理。通過(guò)這種方式,在從核陣列的64個(gè)從核中,形成了28個(gè)生產(chǎn)者與28個(gè)消費(fèi)者的生產(chǎn)者-消費(fèi)者模式通信,并且每一個(gè)生產(chǎn)者生產(chǎn)的消息都有可能被任意一個(gè)消費(fèi)者接收,在一個(gè)從核陣列上實(shí)現(xiàn)了最大規(guī)模的生產(chǎn)者與消費(fèi)者的隨機(jī)配對(duì)。
為了了解通道通信的效率,需要在不同的條件下對(duì)通道通信的性能進(jìn)行測(cè)試。由于通道的同步機(jī)制,需要在不同的生產(chǎn)者/消費(fèi)者數(shù)量條件下,在主核與從核上進(jìn)行通道通信效率的測(cè)試。本文按照以下步驟來(lái)進(jìn)行通信性能的測(cè)試:(1) 創(chuàng)建通道,通道的消息數(shù)據(jù)類(lèi)型設(shè)置為整型,通道的容量設(shè)為能夠容納所有生產(chǎn)者發(fā)送的消息的容量,以避免通道充滿而產(chǎn)生生產(chǎn)者協(xié)程的阻塞從而導(dǎo)致消息發(fā)送的性能下降。(2) 模擬消息數(shù)據(jù)的生產(chǎn),使用隨機(jī)生成的整型數(shù)據(jù)作為生產(chǎn)者要發(fā)送的消息數(shù)據(jù),然后經(jīng)過(guò)多次向通道發(fā)送獲得總時(shí)間,取平均值作為一條消息發(fā)送的時(shí)間。(3) 模擬消費(fèi)者接收消息,消費(fèi)者從已有足夠數(shù)據(jù)的通道內(nèi)獲取消息數(shù)據(jù),多次獲取消息的總時(shí)間取平均值作為一條消息獲取的時(shí)間。在不同條件下處理一條消息的平均時(shí)間如表1所示。
表1 不同條件下處理一條消息的平均時(shí)間 單位:μs
可以看出,從核上通道的通信效率低于主核,并且在有多個(gè)生產(chǎn)者或多個(gè)消費(fèi)者進(jìn)行競(jìng)爭(zhēng)時(shí),通道通信的時(shí)間明顯增加,并且從核上通信時(shí)間增加的幅度遠(yuǎn)高于主核。
從核上的通信效率低于主核有兩方面的原因,(1) 從核訪問(wèn)主存的性能低于主核;(2) 從核上的同步機(jī)制相比于主核上的同步機(jī)制會(huì)造成更高的性能損失,當(dāng)并行的生產(chǎn)者/消費(fèi)者之間發(fā)生競(jìng)爭(zhēng)時(shí),從核上的同步機(jī)制會(huì)產(chǎn)生更多的回滾操作,從而使得通信的平均時(shí)間增加。
需要將基于寄存器通信的通信方式與從核間的通道通信進(jìn)行比較,以觀察新的通信方式相比于通道通信獲得的性能提升。本文將測(cè)試單生產(chǎn)者-單消費(fèi)者情況下的性能與使用了整個(gè)從核陣列進(jìn)行通信的整體性能。同樣使用隨機(jī)生成的整型數(shù)據(jù)作為消息數(shù)據(jù),使用多次發(fā)送的平均值作為一條消息處理時(shí)間。結(jié)果如表2所示。
表2 基于寄存器通信的通信方式平均一條消息處理時(shí)間 單位:μs
將表2中的結(jié)果與表1中從核間通道通信的平均時(shí)間進(jìn)行對(duì)比可以看出,基于寄存器通信的方式處理一條消息的時(shí)間遠(yuǎn)低于通道通信,并且在有多個(gè)生產(chǎn)者相互競(jìng)爭(zhēng)的情況下,單條消息的發(fā)送時(shí)間相比于只有一個(gè)生產(chǎn)者的情況下也大幅增加,說(shuō)明寄存器通信同樣存在著同步導(dǎo)致通信時(shí)間增加的情況。由于基于寄存器通信的方式使用了部分從核作為中轉(zhuǎn)核,不參與消息的生產(chǎn)與接收,所以為了更準(zhǔn)確地描述整體通信性能與使用從核數(shù)量的關(guān)系,本文使用基于寄存器通信方式的單個(gè)從核提供的平均帶寬與通道通信單個(gè)從核提供的平均帶寬進(jìn)行對(duì)比,結(jié)果如表3所示。
表3 單個(gè)從核提供的平均帶寬 單位:GB/s
可以看出,在單生產(chǎn)者-單消費(fèi)者的情況下,基于寄存器通信的方式相比于通道通信單個(gè)從核能提供的帶寬提升了82倍,而使用了整個(gè)從核陣列進(jìn)行生產(chǎn)者-消費(fèi)者通信的情況下,基于寄存器通信的方式下單個(gè)從核提供的帶寬相比于通道通信方式下有658倍的提升。這說(shuō)明基于寄存器通信的方式有效地提高了從核間通信的性能。
本文為申威26010處理器的協(xié)程運(yùn)行框架設(shè)計(jì)了生產(chǎn)者-消費(fèi)者模式的通信,在適用于主核與從核的通道通信的設(shè)計(jì)中,本文基于循環(huán)緩沖區(qū)設(shè)計(jì)了通道的數(shù)據(jù)結(jié)構(gòu),并基于主核與從核上不同的原子操作設(shè)計(jì)了主核與從核上通道消息收發(fā)的同步機(jī)制,保證了通信的正確性,還設(shè)計(jì)了生產(chǎn)者與消費(fèi)者的互相喚醒機(jī)制,避免等待造成的計(jì)算能力損失。為了進(jìn)一步提高從核間通信的效率,本文基于申威26010處理器獨(dú)特的寄存器通信機(jī)制,設(shè)計(jì)一種從核陣列上的從核間相互通信的方式,極大地提高了從核之間進(jìn)行消息通信的效率。本文的研究為申威26010處理器上的協(xié)程運(yùn)行提供了有效的通信模塊,為上層應(yīng)用開(kāi)發(fā)提供了高效的通信接口,也為申威26010處理器提供了一種低粒度的通信實(shí)現(xiàn)。