鞏令欽 沈 莉 周清雷 胡 浩
1(鄭州大學(xué)信息工程學(xué)院 河南 鄭州 450000) 2(中國科學(xué)技術(shù)大學(xué)計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院 安徽 合肥 230000) 3(無錫江南計(jì)算技術(shù)研究所 江蘇 無錫 214083)
底層虛擬機(jī)(LLVM)是一款開源的編譯器架構(gòu),目前已被蘋果、Google、Facebook等各大公司采用[1]。LLVM在重用GCC前端高級(jí)語言處理的同時(shí),提供了獨(dú)特的編譯器后端移植架構(gòu)[2]。為了充分挖掘處理器的計(jì)算潛力,并行處理技術(shù)的實(shí)現(xiàn)顯得尤為重要。軟件層面中,并行處理技術(shù)通過多線程技術(shù)和向量化進(jìn)行實(shí)現(xiàn),其中基于多線程的并行處理技術(shù)對處理器的操作系統(tǒng)環(huán)境改動(dòng)最小[3]。
在多線程環(huán)境下,程序的執(zhí)行由傳統(tǒng)的線性執(zhí)行變?yōu)榉蔷€性執(zhí)行。兩個(gè)或多個(gè)線程訪問相同的內(nèi)存單元時(shí),會(huì)造成系統(tǒng)內(nèi)存的不一致性。由于多個(gè)線程共享同一塊內(nèi)存,當(dāng)內(nèi)存訪問沖突時(shí),將產(chǎn)生錯(cuò)誤的執(zhí)行結(jié)果,同一個(gè)進(jìn)程內(nèi)的其他線程也將受到影響[4]。嚴(yán)重的情況下將導(dǎo)致程序出現(xiàn)死鎖,造成系統(tǒng)資源浪費(fèi)。并行計(jì)算的同步原語和多線程的調(diào)度的正確性都是基于原子指令實(shí)現(xiàn)的,原子指令的實(shí)現(xiàn)方式?jīng)Q定程序的正確性以及運(yùn)行性能的好壞[5]。所以,如何保證多線程環(huán)境下對內(nèi)存操作的原子性,保證訪問內(nèi)存的正確性,是LLVM多線程編譯支持中的重要課題。
原子指令實(shí)現(xiàn)的關(guān)鍵是保證對內(nèi)存操作的原子性。原子性規(guī)定了指令對內(nèi)存單元修改的順序性。在對內(nèi)存操作進(jìn)行處理時(shí),原子指令的讀操作和寫操作之間不能有其他指令對該內(nèi)存單元進(jìn)行修改[6]。除此之外,需要確保LLVM編譯器的指令調(diào)度不會(huì)破壞原子指令的順序性和完整性。
根據(jù)申威處理器的硬件特性,選擇使用鎖機(jī)制實(shí)現(xiàn)LLVM編譯器原子指令的編譯支持,對需要原子性訪問的地址空間加鎖。當(dāng)編譯器進(jìn)行原子指令的翻譯時(shí),使用鎖指令實(shí)現(xiàn)原子指令的原子性。本文在申威處理器下基于LLVM編譯器對鎖機(jī)制進(jìn)行研究與實(shí)現(xiàn)。在多線程環(huán)境下使用并行計(jì)算機(jī)基準(zhǔn)測試集NPB進(jìn)行測試,所有程序均通過自校驗(yàn)。在16個(gè)線程下,F(xiàn)ortran語言程序平均加速比為11.91,最大加速比為15.73,C語言程序平均加速比為8.08,最大加速比為13.32。
鎖機(jī)制是一種可以使所有共享訪問互斥進(jìn)行的同步控制機(jī)制[7]。 鎖機(jī)制在X86和MIPS等架構(gòu)中均有不同的實(shí)現(xiàn)方式。LLVM編譯器后端中,尚未有針對申威處理器架構(gòu)的鎖機(jī)制的編譯支持。
在X86架構(gòu)的Linux內(nèi)核中,提供了3種機(jī)制保證原子性,包括基本操作的原子性、總線鎖機(jī)制(Bus Locking)和Cache內(nèi)部鎖機(jī)制。在基本操作的原子性中,X86處理器保證了對8位、16位、32位、64位共享內(nèi)存讀寫的原子性。在總線鎖機(jī)制中使用LOCK#信號(hào)阻塞其他處理器的總線訪問請求。在Cache內(nèi)部鎖機(jī)制中通過CPU直接使用Cache內(nèi)部的鎖進(jìn)行實(shí)現(xiàn),Cache內(nèi)部鎖可以保證整條cache line不會(huì)同時(shí)被多個(gè)原子指令修改[8]。X86架構(gòu)提供原子操作的指令包括inc、xchg、xand等,通過對原子指令加入LOCK宏可以實(shí)現(xiàn)指令執(zhí)行的原子性。
MIPS架構(gòu)使用精簡指令集計(jì)算機(jī)(Reduced Instruction Set Computer,RISC)架構(gòu)的指令集,未提供諸如X86架構(gòu)支持的inc、xchg、xand等復(fù)雜原子指令。在MIPS架構(gòu)中提供支持實(shí)現(xiàn)鎖機(jī)制的匯編指令鏈接加載(Load Linked,ll)以及條件存儲(chǔ)(Store Conditional,sc)[9]。ll指令的功能是原子性地讀取指定內(nèi)存單元中的值,sc指令的功能是原子性地對內(nèi)存單元進(jìn)行修改。在ll指令和sc指令之間的匯編指令會(huì)被原子性執(zhí)行[10]。MIPS架構(gòu)通過ll指令和sc指令進(jìn)行鎖機(jī)制的實(shí)現(xiàn)。 同時(shí),Alpha、PowerPC和ARM等RSIC指令集架構(gòu)均支持鏈接加載和條件存儲(chǔ)指令[11]。
LLVM編譯器中對X86和MIPS指令集均有相應(yīng)的X86后端和MIPS后端進(jìn)行編譯支持。申威處理器采用自主指令集,LLVM編譯器需要增加后端對申威架構(gòu)的支持。相比于X86架構(gòu),申威處理器不提供LOCK宏及inc、xchg、xadd等復(fù)雜原子指令。相比于MIPS等RSIC指令集架構(gòu),申威處理器不提供鏈接加載和條件存儲(chǔ)作為基本的原子指令。由于申威處理器的硬件特性和指令集與MIPS架構(gòu)和X86架構(gòu)均有較大區(qū)別,所以無法使用X86架構(gòu)或MIPS架構(gòu)下鎖機(jī)制的實(shí)現(xiàn)方式作為LLVM編譯器申威架構(gòu)后端鎖機(jī)制的實(shí)現(xiàn)方式。本文基于LLVM編譯器并結(jié)合申威處理器指令集特性提出了一種鎖機(jī)制的實(shí)現(xiàn)方式,保證了多線程環(huán)境下原子操作的原子性。
LLVM編譯器架構(gòu)分為高級(jí)語言前端、中間代碼優(yōu)化器和后端代碼生成器三個(gè)部分。高級(jí)語言前端主要負(fù)責(zé)將高級(jí)語言轉(zhuǎn)化為LLVM IR,中間代碼優(yōu)化器對LLVM IR進(jìn)行優(yōu)化,后端代碼生成器對IR進(jìn)行降級(jí)和代碼生成操作。在鎖機(jī)制的實(shí)現(xiàn)過程中,前端對高級(jí)語言解析后將原子操作轉(zhuǎn)化為IR中的atomic關(guān)鍵字并傳遞給后端。IR降級(jí)的過程中,后端根據(jù)指令模板對偽指令的定義、原子操作類型和數(shù)據(jù)類型的區(qū)別,將atomic關(guān)鍵字降級(jí)為對應(yīng)的偽指令并繼續(xù)進(jìn)行后續(xù)編譯流程。在偽指令擴(kuò)展Pass中對偽指令進(jìn)行語義映射,最終生成匯編代碼。其過程如圖1所示。
圖1 原子操作指令生成過程
編譯器對偽指令進(jìn)行語義映射處理時(shí),對每條偽指令映射的匯編代碼通過鎖指令進(jìn)行加鎖。多線程環(huán)境下,并行的指令流水在遇到加鎖的匯編代碼時(shí)轉(zhuǎn)為串行執(zhí)行。根據(jù)申威處理器的硬件特性,為8位、16位、32位和64位數(shù)據(jù)類型的數(shù)據(jù)設(shè)計(jì)不同的偽指令。每種數(shù)據(jù)類型的偽指令根據(jù)功能的不同可劃分為2種,分別為原子二元運(yùn)算操作和原子比較并交換操作。原子二元操作包括原子加、原子減、原子與、原子交換、原子或、原子異或。對每條偽指令,在后端實(shí)現(xiàn)偽指令語義映射及鎖機(jī)制降級(jí)處理流程。其中,偽指令含義參考Linux內(nèi)核中內(nèi)建函數(shù)接口設(shè)計(jì),不同數(shù)據(jù)類型的內(nèi)建函數(shù)對應(yīng)不同的偽指令。面向申威處理器的LLVM的偽指令的含義如表1所示。其中,n=8,16,32,64,分別表示8位、16位、32位、64位數(shù)據(jù)類型。
表1 偽指令設(shè)計(jì)及含義
在實(shí)現(xiàn)對每條偽指令的語義映射過程中,將加鎖的匯編代碼作為一個(gè)獨(dú)立的基本塊。該基本塊內(nèi)的指令不參與指令調(diào)度。在設(shè)計(jì)鎖機(jī)制匯編基本塊時(shí),需要考慮指令排布和寄存器的使用,以盡可能少地匯編指令實(shí)現(xiàn)鎖機(jī)制。基本塊的實(shí)現(xiàn)過程如圖2所示。
圖2 鎖機(jī)制基本塊的實(shí)現(xiàn)
圖3 基本塊的插入
LLVM編譯器前端對高級(jí)語言解析后將原子操作轉(zhuǎn)化為IR中的atomic關(guān)鍵字并傳遞給后端。后端將atomic關(guān)鍵字轉(zhuǎn)換為偽指令后,對偽指令進(jìn)行降級(jí)處理,實(shí)現(xiàn)原子指令的語義映射。
申威處理器中鎖機(jī)制需要支持8位、16位、32位和64位數(shù)據(jù)讀寫的原子操作。申威處理器對齊訪存最小粒度為4字節(jié),32位數(shù)據(jù)和64位數(shù)據(jù)類型的地址不需要進(jìn)行對齊處理。8位和16位的數(shù)據(jù)需要鎖機(jī)制對內(nèi)存地址進(jìn)行對齊處理后執(zhí)行存取操作。鎖機(jī)制中對8位和16位數(shù)據(jù)類型處理包括對非對齊內(nèi)存地址的對齊處理和保證非對齊地址中有效數(shù)據(jù)提取和寫回的正確性。
在鎖機(jī)制中,傳入的非對齊內(nèi)存地址的對齊處理可以通過與立即數(shù)的與非操作實(shí)現(xiàn)。如需確保地址N字節(jié)對齊,則傳入的地址與立即數(shù)N-1進(jìn)行與非操作。
非對齊地址中的有效數(shù)據(jù)的正確提取和寫回需要使用有效數(shù)據(jù)位拼接的方式實(shí)現(xiàn)。鎖機(jī)制中使用數(shù)據(jù)抽取操作,數(shù)據(jù)插入操作,數(shù)據(jù)屏蔽操作和數(shù)據(jù)按位或操作對數(shù)據(jù)進(jìn)行處理。數(shù)據(jù)插入處理指將有效數(shù)據(jù)插入全零內(nèi)存區(qū)域,確保存儲(chǔ)有效數(shù)據(jù)的內(nèi)存單元中沒有臟數(shù)據(jù)位。數(shù)據(jù)插入處理如圖4所示。
圖4 數(shù)據(jù)插入處理
數(shù)據(jù)插入操作處理在內(nèi)存單元中,有效數(shù)據(jù)前后均有數(shù)據(jù)位的情況。數(shù)據(jù)插入處理在鎖機(jī)制算法中使用insert函數(shù)表示。
數(shù)據(jù)抽取處理指將有效數(shù)據(jù)抽取至全零內(nèi)存區(qū)域,確保存儲(chǔ)有效數(shù)據(jù)的內(nèi)存單元中沒有臟數(shù)據(jù)位。數(shù)據(jù)抽取處理在鎖機(jī)制算法中使用extract函數(shù)表示。數(shù)據(jù)抽取處理如圖5所示。
圖5 數(shù)據(jù)抽取處理
數(shù)據(jù)屏蔽處理指屏蔽內(nèi)存單元中的有效數(shù)據(jù),將內(nèi)存單元中除有效數(shù)據(jù)外的數(shù)據(jù)位抽取至全零內(nèi)存區(qū)域。確保有效數(shù)據(jù)寫回時(shí)內(nèi)存單元的無關(guān)數(shù)據(jù)位的一致性。數(shù)據(jù)屏蔽處理在鎖機(jī)制算法中使用mask函數(shù)表示。數(shù)據(jù)屏蔽處理如圖6所示。
圖6 數(shù)據(jù)屏蔽處理
通過數(shù)據(jù)插入操作,數(shù)據(jù)抽取操作,數(shù)據(jù)屏蔽操作和數(shù)據(jù)按位或操作進(jìn)行數(shù)據(jù)拼接操作,可保證非對齊內(nèi)存地址中有效數(shù)據(jù)提取和寫入的正確性。數(shù)據(jù)拼接操作過程如圖7所示。
圖7 數(shù)據(jù)拼接操作
從對齊內(nèi)存地址中取出數(shù)據(jù)后,使用數(shù)據(jù)抽取操作和數(shù)據(jù)屏蔽操作將有效數(shù)據(jù)和其余數(shù)據(jù)位抽取到全零區(qū)域中。然后使用抽取后的有效數(shù)據(jù)進(jìn)行運(yùn)算,將運(yùn)算后的有效數(shù)據(jù)與抽取后的其余數(shù)據(jù)位進(jìn)行按位或操作,得到完整的有效數(shù)據(jù)并寫回內(nèi)存。
在實(shí)現(xiàn)鎖機(jī)制的過程中,關(guān)鍵操作包括lock_load32、lock_load64、lock_store32、lock_store64、lock_read、lock_write和barrier。lock_load32操作表示在對齊鎖地址指向的內(nèi)存單元中讀取4字節(jié)數(shù)據(jù),lock_load64操作表示在對齊鎖地址指向的內(nèi)存單元中讀取8字節(jié)數(shù)據(jù)。lock_store32操作對內(nèi)存單元進(jìn)行修改,執(zhí)行4字節(jié)數(shù)據(jù)的原子寫操作,lock_store64操作執(zhí)行8字節(jié)數(shù)據(jù)的原子寫操作。lock_write操作判斷是否獲取鎖。lock_read操作判斷鎖機(jī)制是否成功執(zhí)行。barrier表示存儲(chǔ)器欄柵,編譯器在存儲(chǔ)器欄柵指令之前所有讀寫操作都執(zhí)行后才可以執(zhí)行存儲(chǔ)器欄柵指令之后的操作。
val_cmp_32表示32位數(shù)類型的原子比較并交換操作。以val_cmp_32偽指令為例,不需要鎖機(jī)制進(jìn)行數(shù)據(jù)處理的32位數(shù)據(jù)類型的原子性比較并交換操作在鎖機(jī)制中的偽指令語義映射算法如算法1所示。
算法1val_cmp_32語義映射
輸入: new_val, old_val, lock_ptr。
輸出: res_val。
do{
insert(barrier)
lock_val ← lock_load32(lock_ptr)
res_val ← lock_val
cmp ← old_val == lock_val
flag ← lock_write(cmp)
if cmp is 0 then
break
else if flag is 1 then
lock_store32(new_val, lock_ptr)
end if
flag ← lock_read()
}while flag is 0
算法1是val_cmp_32偽指令語義映射后的邏輯的偽代碼。該算法將參數(shù)中指針指向的值與老值比較,若相等,則將新值寫入內(nèi)存,并返回老值。若比較失敗,則不更改原內(nèi)存地址中的值并返回參數(shù)指針指向的值。當(dāng)lock_write(cmp)為1時(shí),表示獲取寫鎖成功,否則跳出鎖機(jī)制處理。當(dāng)lock_read()為1時(shí)表示鎖機(jī)制成功執(zhí)行,否則重新執(zhí)行該原子操作直至鎖機(jī)制成功執(zhí)行。64位數(shù)據(jù)類型的比較并交換與此類似。
原子加、原子減、原子與、原子交換、原子或、原子異或操作均為二元操作,可以使用相同的處理流程。以原子加的add_fetch_32偽指令為例,鎖機(jī)制的實(shí)現(xiàn)如算法2所示。
算法2add_fetch_32語義映射
輸入: val, lock_ptr。
輸出: res_val。
do{
教育是未來的事業(yè),兒童是民族的未來。教師要把一個(gè)不懂事的孩子培養(yǎng)成國家的棟梁,民族的脊梁,要付出畢生的精力。教師工作是平凡的,每天上課下課、備課、批改作業(yè),為學(xué)生解惑排難;但教師的職業(yè)又是偉大的,教師要把兒童這個(gè)幼苗培育成參天大樹。古人說:“十年樹木,百年樹人?!闭f明創(chuàng)造物質(zhì)是比較容易的,塑造人、鑄造人的精神是要經(jīng)過幾代人的努力。因此,教師要滿懷對學(xué)生的真心關(guān)愛,以學(xué)生的發(fā)展為本,甘為人梯,樂于奉獻(xiàn),用心靈和汗水一點(diǎn)一滴地滋潤學(xué)生的心田,把全部精力和滿腔熱情獻(xiàn)給教育事業(yè)。
insert(barrier)
lock_val ← lock_load32(lock_ptr)
lock_write(1)
res_val ← val + lock_val
lock_store32(res_val, lock_ptr)
}while lock_read() is 0
算法2是add_fetch_32偽指令語義映射后的邏輯的偽代碼。該算法將參數(shù)值與內(nèi)存中的老值相加,返回相加后的新值,并存入內(nèi)存。res_val是執(zhí)行二元運(yùn)算操作后的結(jié)果值。即將指針指向內(nèi)存地址中的值與參數(shù)值執(zhí)行二元運(yùn)算操作,如原子加、原子減等6種二元運(yùn)算操作。64位數(shù)據(jù)類型的二元運(yùn)算操作與此類似。
val_cmp_8表示8位數(shù)據(jù)類型的原子比較并交換操作。以偽指令val_cmp_8為例,鎖機(jī)制中需要對數(shù)據(jù)進(jìn)行處理的8位數(shù)據(jù)原子比較并交換操作的偽指令語義映射算法如算法3所示。
算法3val_cmp_8語義映射
輸入: new_val, old_val, lock_ptr。
輸出: res_val。
do{
insert(barrier)
lock_align_ptr ← nand(lock_ptr,7)
eff_new_val ← insert(new_val, lock_ptr)
ori_lock_val ← lock_load64(lock_align_ptr)
eff_lock_val ← extract(ori_lock_val, lock_ptr)
res_val ← eff_lock_val
cmp ← old_val == eff_lock_val
flag ← lock_write(cmp)
if cmp is 0 then
break
if flag is 1 then
other_lock_val ← mask(ori_lock_val,lock_ptr)
ret_val ← or(other_lock_val, new_val)
lock_store64(ret_val, lock_align_ptr)
end if
}while lock_read() is 0
算法3中,主體算法框架與4.1節(jié)類似,算法中主要新增對8位數(shù)據(jù)類型的有效數(shù)據(jù)和非對齊內(nèi)存地址的處理。nand(lock_ptr,7)表示通過與立即數(shù)7進(jìn)行與非操作,實(shí)現(xiàn)對地址進(jìn)行8字節(jié)對齊處理。or表示數(shù)據(jù)按位邏輯或。該算法將參數(shù)中指針指向的值與老值比較,若相等,則將新值寫入內(nèi)存,并返回老值,若不相等,則返回指針指向的值。16位數(shù)據(jù)類型的比較并交換與此類似。
原子加、原子減、原子與、原子交換、原子或、原子異或均為二元操作,可以使用相同的鎖機(jī)制處理流程。以偽指令add_fetch_8為例,鎖機(jī)制中需要對數(shù)據(jù)進(jìn)行處理的8位數(shù)據(jù)原子加操作的偽指令語義映射算法如算法4所示。
算法4add_fetch_8語義映射
輸入: val, lock_ptr。
輸出: res_val。
do{
insert(barrier)
lock_align_ptr ← nand(lock_ptr, 7)
ori_lock_val ← lock_load64(lock_align_ptr)
lock_write(1)
eff_lock_val ←extract(ori_lock_val, lock_ptr)
ori_res_val ← val + eff_lock_val
eff_res_val ←insert(ori_res_val, lock_ptr)
other_lock_val ← mask(ori_lock_val,lock_ptr)
res_val ← or(other_lock_val, eff_res_val)
lock_store64(res_val, lock_align_ptr);
}while lock_read() is 0
算法4是add_fetch_8偽指令語義映射后的邏輯偽代碼。該算法將參數(shù)值與內(nèi)存中的老值執(zhí)行二元運(yùn)算操作,如原子加,返回二元運(yùn)算操作后的新值,并存入內(nèi)存。使用nand(lock_ptr,7)處理非對齊內(nèi)存地址,使用insert操作、extract操作和mask操作實(shí)現(xiàn)有效數(shù)據(jù)位的提取和寫回。16位數(shù)據(jù)類型的二元運(yùn)算操作與此類似。
在申威1621處理器的LLVM編譯器上對鎖機(jī)制分別進(jìn)行正確性測試和性能測試。LLVM編譯器版本為7.0,并行測試環(huán)境為16個(gè)CPU的并行環(huán)境。正確性測試使用Linux內(nèi)核源碼中的內(nèi)建函數(shù)進(jìn)行測試。性能測試采用NPB(NAS Parallel Benchmark)測試集[12]。 NPB測試集為3.0版本的C語言NPB測試集和3.0版本的Fortran語言NPB測試集。
Liunx內(nèi)核源碼中,通過一系列內(nèi)建函數(shù)實(shí)現(xiàn)原子操作[13]。內(nèi)建函數(shù)以及其完成的功能如表2所示。
表2 Liunx內(nèi)建函數(shù)功能
通過調(diào)用Linux內(nèi)核中的13個(gè)內(nèi)建函數(shù)并分別傳入8位、16位、32位、64位數(shù)據(jù)對LLVM中的鎖機(jī)制進(jìn)行驗(yàn)證。實(shí)驗(yàn)結(jié)果如表3所示。
表3 功能測試結(jié)果
實(shí)驗(yàn)結(jié)果表明LLVM編譯器鎖機(jī)制中新增52條偽指令均正確運(yùn)行,執(zhí)行結(jié)果與標(biāo)準(zhǔn)結(jié)果一致。在申威1621處理器的多線程環(huán)境下,LLVM編譯器可以正確通過鎖機(jī)制實(shí)現(xiàn)原子操作。
NPB是NASA提供的,用于評(píng)估并行超級(jí)計(jì)算機(jī)性能的測試程序集,是并行計(jì)算機(jī)基準(zhǔn)測試程序。其中共包含8道測試題目,分別為EP(Embarrassingly parallel)、MG(3D MultiGrid)、FT(Fast Fourier transform)、IS(Integer sort)、CG(Conjugate Gradient)、LU(Lower upper triangular)、SP(Scalar penta-diagonal)、BT(Block Tri-Diagonal)[14]。每題包含5種測試規(guī)模,分別為S、W、A、B、C。其中S類為樣例程序,W類通常用于工作站,A類通常是運(yùn)行中等性能的工作站系統(tǒng),B類運(yùn)行于高端的工作站系統(tǒng)或者小型的并行系統(tǒng),C類則用于超級(jí)計(jì)算系統(tǒng)[15]。選用B類規(guī)模進(jìn)行測試,B類規(guī)模大小如表4所示。
表4 B類規(guī)模大小
在LLVM編譯器中,C/C++語言采用clang作為前端對進(jìn)行編譯處理,F(xiàn)ortran語言采用flang作為前端進(jìn)行編譯處理。本文測試了C語言的NPB測試集和Fortran語言的NPB測試集,對16個(gè)線程下OpenMP庫的加速情況進(jìn)行了對比。
面向申威1621處理器的LLVM編譯器對于C語言程序的并行加速比如表5所示,平均加速比為8.08,最大加速比為13.32。
表5 C語言程序NPB加速比
續(xù)表5
面向申威1621處理器的LLVM編譯器對于Fortran語言程序的并行加速比如表6所示,平均加速比為11.91,最大加速比為15.73。
表6 Fortran語言程序NPB加速比
由功能性測試可知,鎖機(jī)制中52條偽指令均可完成對應(yīng)的原子性操作。在基于申威1621處理器的LLVM編譯器上加入鎖機(jī)制后,可正確對內(nèi)存進(jìn)行原子性的讀寫操作,實(shí)現(xiàn)了8位、16位、32位、64位數(shù)據(jù)類型的原子加、原子減、原子與、原子交換、原子或、原子異或、原子比較并交換操作,保證了多線程環(huán)境下對內(nèi)存訪問的一致性。
由性能測試可知,在加入鎖機(jī)制后,LLVM編譯器通過使用OpenMP庫,C語言版NPB測試集所有程序和Fortran語言版NPB測試集所有程序在16個(gè)線程的環(huán)境下均正確執(zhí)行并自校驗(yàn)通過。C語言版NPB測試集程序平均加速比為8.08,最大加速比為13.32。Fortran語言版NPB測試集程序平均加速比為11.91,最大加速比為15.73。
本文對鎖機(jī)制和原子指令進(jìn)行了介紹,結(jié)合申威處理器的特性與LLVM編譯器的特點(diǎn),針對鎖機(jī)制的具體實(shí)現(xiàn)進(jìn)行了討論并介紹了52條偽指令及其算法實(shí)現(xiàn)。
通過本文對鎖機(jī)制的實(shí)現(xiàn),LLVM編譯器可以正確穩(wěn)定地在申威處理器下的多線程環(huán)境中運(yùn)行,使得申威處理器的多核化優(yōu)勢得到了利用和體現(xiàn)。下一步的工作將對鎖機(jī)制開銷進(jìn)行進(jìn)一步的分析并充分挖掘申威處理器并行計(jì)算的潛力。