張 昆 過 鋒 鄭 方 謝向輝
(數學工程與先進計算國家重點實驗室 江蘇無錫 214125)
(zhang.kun@meac-skl.cn)
功耗是未來超級計算機的重大挑戰.為了滿足E級計算的目標,美國能源部提出了50GFLOPSW的能效比目標[1].與之相比,目前Green500[2]的第1名,日本Shoubu超級計算機的能效比僅達到7GFLOPSW.為了實現更高的能效比,需要在追求工藝進步的同時,在體系結構、特別是芯片微結構上做出更多的優化.
眾核處理器是高性能計算機的重要實現手段之一.然而,由于片上集成了大量運算核心,眾核處理器的設計在功耗和硬件開銷上有很多限制.大量的運算核心導致眾核處理器功耗較大,過高的功耗會給芯片散熱和穩定性帶來問題.同時,能效比是未來芯片的重要指標,甚至有可能成為比峰值性能更重要的指標,因此,需要進一步提升眾核處理器的能效比.由于片上資源受限,無法采取通用多核處理器的復雜結構、大容量緩存等設計,眾核處理器必須采用硬件開銷較小的設計,這對提升其能效比又提出了更高的要求.
在馮·諾伊曼結構中,所有的運算均依賴于自存儲器中讀取的指令,指令的讀取、譯碼這些輔助工作雖然不能直接提供計算能力,但卻耗費了較多的芯片功耗[3].因此,本文提出1種面向眾核處理器的L0指令緩存設計,同流水線緊耦合的低功耗指令循環緩存.通過同流水線緊耦合的L0指令緩存,可以提供較L1指令緩存更加高能效的取指訪問,同時,本文的指令循環緩存位于流水線的取指和預譯碼站臺之后,當取指命中L0緩存時,可以門控循環緩存之前的流水線站臺以降低功耗.
為了降低L0緩存的硬件復雜度,以適應眾核處理器緊張的硬件資源,本文的L0指令緩存采取了指令循環緩存設計.指令循環緩存技術是經過廣泛研究并被數款商用處理器采用的技術,但是本文的循環緩存結合了眾核處理器的實際要求,具有3個創新和特點:
1) 本文的指令緩存同流水線緊耦合,不僅作為L0級指令緩存,也作為流水線前段和后段之間的解耦合緩存,一方面減少流水線前段的功耗,另一方面流水線前段和后段的解耦合有利于緩解流水線實現的時序壓力.
2) 循環緩存的1個問題是循環出口處帶來的流水線氣泡,本文提出了循環出口預取技術,有效解決流水氣泡問題,使得循環緩存的引入對流水線性能幾乎不造成影響.同時,不同于之前的設計,本文循環緩存技術可以在循環的第2次執行開始從緩存中提供指令.
3) 如前文所述,循環緩存的設計必須以較低的硬件開銷為前提.本文的工作是體系結構研究同硬件可實現性緊密結合的1次嘗試,不僅考慮了指令緩存的可實現性,還討論了指令緩存同1個示例流水線的緊耦合方式.
在循環緩存方面有較多的先前工作,本文同這些工作的首要區別在于本文采用了同流水線緊耦合的循環緩存設計,這就解決了幾乎所有循環緩存都需要經歷“檢測循環、裝填循環、輸出循環”這3個步驟的問題,即直到第3次循環迭代,循環緩存才可以向流水線后段輸出指令.
文獻[4]中提出了利用指令流中的sbb(short backward branch)指令來判斷指令流是否命中循環緩存,sbb指令定義為轉移距離較短的回跳轉移指令,當轉移指令的偏移量小于循環緩存的容量時,可以認為循環體命中了循環緩存.文獻[4]使用1個指令計數器來判斷循環緩存是否已經輸出到sbb指令,這也就意味著文獻[4]的結構中只能夠包含1個循環體而無法處理內嵌循環.文獻[4]面向嵌入式處理器進行設計,且使用了嵌入式應用測試集進行評測,其結果表明在超過32條指令之后其設計的循環緩存命中率就基本上不再增加.
文獻[5]提出了1種基于指令隊列的程序循環代碼動態檢測技術.其設計類似于文獻[4]的循環緩存實現,區別在于該設計不再使用sbb定義而是通過跳轉目標PC同循環緩存存放的第1條指令PC值的關系來判斷是否命中循環緩存,但是其同樣需要到第3次循環迭代時才可以輸出循環.
文獻[6]針對DSP處理器設計了1種兩路循環緩存,該設計直接存儲回跳轉移指令的PC值來判斷循環緩存是否輸出至循環尾部指令.文獻[6]同樣使用1個循環計數器來判斷循環體是否已經輸出結束,因此也導致其無法處理嵌套循環.
文獻[7]利用加入新的指令以及編譯器的幫助,在編譯過程中插入適用于循環緩存的輔助指令,以此應對循環體內部的前向轉移指令.編譯器在進行程序切片時,選擇執行次數多的循環插入輔助指令以提示硬件邏輯對循環進行裝載.同時,該文給出了1種分層次的譯碼后指令存儲,用以減小循環緩存的容量需求.文獻[7]的設計需要編譯器和指令集的支持,一定程度上限制了其兼容性和實用性,另外該技術將前向轉移指令的2個方向都進行緩存,在某些應用中可能造成功耗的浪費.
文獻[8]中利用BTB存儲前向跳轉的信息,按照BTB中的預測方向處理循環中的前向跳轉.這種設計避免了對編譯器和指令集的修改,但是,其對前向跳轉的處理依賴于BTB的預測成功率,在眾核處理器的簡單核心中包含1個足夠大小的BTB以及其相應控制邏輯對硬件資源的需求較高.
指令循環緩存實現為1個先入先出的隊列,存儲動態指令流,當檢測到包含在循環緩存中的循環時,下一次循環執行的指令將直接從指令循環緩存中讀取,進而門控自流水線頭部取指部件到預譯碼部件之間的大部分邏輯,有效減少流水線前段的動態功耗.
包含指令循環緩存的示例流水線前段(front-end,本文指流水線的取指和預譯碼部分)如圖1所示.示例流水線包含2級取指站臺和3級譯碼站臺,指令循環緩存位于預譯碼部件之后.離開預譯碼部件的指令全部寫入指令緩存中,之后再從指令緩存中讀出,送至流水線后段.

Fig. 1 Pipeline front-end with the loop cache圖1 包含循環緩存的流水線前段
指令循環緩存的總體結構如圖2所示.循環緩存中存放連續的順序指令流,并維護所存順序指令流的首條指令PC值(下文稱為HeadPC).當作為循環體結尾的轉移指令離開循環緩存時,將根據其跳轉目標PC值判斷該循環是否包含在循環緩存中,若目標PC值大于等于HeadPC時,表示循環命中緩存,當拍產生跳轉目標指令的讀地址,下一拍循環緩存開始從循環體頭部輸出指令.

Fig. 2 The structure of the loop cache圖2 指令循環緩存總體結構
循環緩存分為寫入控制邏輯、讀出控制邏輯和存儲體3部分組成.眾核處理器的運算核心一般采用簡單的流水線設計,因此,不同于基于BTB轉移機制的流水線中直接根據取指PC值進行下一拍取指的重定向,本文中的流水線前段重定向信號來自預譯碼的結果.進一步地,重定向信號來自于循環緩存的寫控制邏輯,當寫控制邏輯發現不命中循環緩存的轉移指令時,即可發出取指重定向信號.由于命中循環緩存后,循環體的多次執行將直接由讀控制邏輯從緩存存儲體中取指,指令不再流經寫控制邏輯,因此,在寫控制邏輯和讀控制邏輯中,均含有轉移預測部件.
循環緩存一般設計為“檢測到循環”、“裝填循環體”、“讀取循環體”3個步驟,這種設計的缺點是直到循環體的第3次執行才可以利用循環緩存.本文采取了同流水線緊耦合的循環緩存設計,流水線的動態指令流均需要寫入循環緩存,因此當讀控制邏輯發現有效命中的循環體時,循環的第2遍執行就可以從指令循環緩存中取指.
同一般的L0級指令緩存設計不同,本文的指令循環緩存不僅可以在循環命中時作為L0級指令緩存使用,由于其放置在流水線的預譯碼部件之后,可以有效將流水線的“生成地址、取指部分”同“譯碼、分派、執行部分”解耦合.解耦合有利于減少流水線站臺之間的控制信號依賴,緩解流水線實現的時序壓力.
本文的循環緩存設計考慮了硬件實現代價,如圖2所示,循環緩存主要包括4組觸發器,即首指令PC(HeadPC)、寫指針、讀指針和輸出指令PC.邏輯電路主要基于讀寫指針的操作,因此硬件復雜度較低,在2.2~2.4節中將對各部分邏輯的硬件實現做簡要分析.
寫控制邏輯主要包含循環緩存命中判斷邏輯、寫指針控制邏輯和HeadPC控制邏輯.
寫控制邏輯接收預譯碼部件送來的指令組,判斷指令組中是否有轉移指令且轉移指令是否命中循環緩存.若命中循環緩存,則通知流水線前端暫停取指,循環體的下一次迭代可以從循環緩存中直接取指;若不命中循環緩存,則通知流水線的取指部件進行取指目標重定向.需要特別說明的是,對于向前跳轉的條件轉移指令,若預測其不跳轉,則在本文的寫控制和讀控制邏輯中將其當作順序指令處理,因此本文的結構是部分支持循環體中內嵌前向轉移指令的.
寫控制邏輯根據當前寫入的有效指令數目,為各條指令分配其在存儲體中的寫入位置,同時寫指針相應地增加.在本文的循環緩存中,寫指針值一直取模增加,寫指針增加后,指向下一拍到達的首條指令需要寫入的位置.
當程序初始運行時,HeadPC設置為程序的首PC(即首次到達寫控制邏輯的有效指令的PC值),一旦發生不命中循環緩存的轉移,則將HeadPC置為該轉移指令的目標PC,之后當取指填滿循環緩存并開始覆蓋最先指令時,HeadPC隨之遞增.
硬件開銷方面,循環緩存的命中判斷邏輯核心為一個比較器,比較器用于判斷轉移指令的跳轉偏移量是否小于循環緩存的容量;寫控制邏輯的核心為一個寬度為寫指針寬度的加法器,按照每次寫入指令的數目增加;HeadPC控制邏輯實現為多路選擇器,根據不同的情況對HeadPC進行賦值.
讀控制邏輯包含命中判斷邏輯、讀指針控制邏輯以及輸出PC控制邏輯.
由于在讀控制邏輯中存在轉移預測部件,自循環緩存中讀出指令的預測方向可能異于該條指令在寫入存儲體之前的預測方向,因此,轉移指令需要在讀控制邏輯中重新判斷其是否命中循環緩存.
當循環體的結尾轉移指令在寫控制邏輯判斷為命中且在讀控制邏輯中也判斷為命中時,下一次循環體執行可以直接從循環緩存中取指;當循環體的結尾轉移指令在寫控制邏輯中判斷為命中而讀控制邏輯判斷為不命中,則意味著循環體到達循環出口,需要通知流水線前段從循環出口重定向取指;同時,存在在寫控制邏輯中判斷為不命中而在讀控制邏輯中判斷為命中的轉移指令,這是因為對于同一條指令,其轉移預測方向可能改變,這種情況屬于內嵌的循環,本文的循環緩存完全支持這種內嵌循環而不需要任何軟件支持.
讀控制邏輯根據讀寫指針的關系判斷緩存中是否存在未讀取的指令,只要讀指針位于寫指針之前,則發起有效的讀動作.讀控制邏輯產生存儲體的讀地址,并根據存儲體輸出的指令命中循環緩存的情況,置位下一拍的讀地址.對于命中循環緩存的轉移指令,其目標指令在存儲體中的位置可以通過轉移指令偏移量計算而得.當讀控制邏輯發現需要取指重定向時,直接將讀指針置為寫指針并等待重定向取指到達循環緩存即可.
為了減小存儲體開銷,指令寫入存儲體時,不再保存其PC值,而是通過讀控制邏輯產生.對于順序執行的指令,PC值逐條遞增即可;當在讀控制邏輯發現轉移指令并預測為跳轉時,PC值將置為跳轉的目標地址;當執行部件發現轉移預測失敗時,PC值將設置為流水線恢復后首條到達寫控制邏輯的指令PC值.
硬件開銷方面,讀指針邏輯的核心為一個多路選擇器,用于選擇遞增地址或是命中后的循環首條指令地址;讀控制邏輯中的命中判斷邏輯包含若干種條件(在寫控制邏輯中是否預測為跳轉、在讀控制邏輯中是否預測為跳轉等)的綜合;指令PC值邏輯也是一個多路選擇器和加法器,用于選擇加法器運算得到的順序遞增PC值或是轉移指令的跳轉目標地址.
當循環體命中指令循環緩存時,后續的若干次迭代可以從循環緩存中取指,當循環體尾部轉移指令在讀控制邏輯中預測為不跳轉時,意味著循環體到達循環出口,需要執行其尾部轉移指令的順序后繼指令,由此產生流水線取指重定向,而重定向取指將帶來自流水線頭部到循環緩存站臺之間若干拍的氣泡.若應用中的循環體迭代次數較少,則上述的氣泡將造成性能損失.
為了解決循環出口帶來的性能損失,本文的循環緩存設計引入了循環出口預取機制,通過提前將循環出口的若干條指令寫入循環緩存,可以有效去除循環執行到出口時的性能損失.
循環出口預取由讀控制邏輯發起,當循環體尾部轉移指令首次到達讀控制邏輯并判斷為命中時,意味著循環體即將開始第2次的迭代,此時讀控制邏輯通知流水線頭部取指邏輯進行循環出口地址的預取.預取取指的數目采用信用管理,讀控制邏輯根據當前讀寫指針關系,計算出在不覆蓋已命中循環體的前提下存儲體能夠容納的預取指令數目,通知流水線的取指部件.流水線取指部件按照信用取指若干次后再次暫停取指.
循環出口預取不產生任何額外的開銷,因為循環出口是一定會被執行的.循環出口預取機制的示意如圖3所示.預取取指到達存儲體后,將使寫指針增長.循環迭代過程中,每次到達循環體尾部轉移指令并預測為跳轉,讀指針移動至循環體頭部位置重新開始輸出循環體指令;循環體最后1次迭代,到達尾部指令并預測為不跳轉時,讀指針可以直接移動到順序的下一個位置,即可正確讀取預取的指令.同時,讀控制邏輯通知流水線取指部件恢復取指.

Fig. 3 The prefetching of the loop exit圖3 循環出口預取示意圖
硬件開銷方面,循環出口預取邏輯需要計算預取信用值,通過計算讀指針同循環體頭部指令位置之間的相對關系,可以得到是否有足夠的空間進行出口預取.
本文使用gem5[9]模擬器對指令循環緩存結構進行建模.眾核處理器一般采用大量精簡計算核心,因此本文在雙發射順序流水線上實現循環緩存結構.循環緩存的命中判斷取決于循環體最后1條轉移指令在流水線中的轉移預測結果,因此,轉移預測機制的準確度對循環緩存的性能測試有所影響.由于不同的眾核處理器采用不同的轉移預測實現思路,為了消除轉移預測對測試帶來的影響,本文采用理想的轉移預測器,即保證每次的轉移預測結果都是正確的.
本文測試中使用的主要配置情況如表1所示:

Table 1 The Configuration of the Simulator表1 模擬器配置
表1中流水線前段級數指流水線首部到指令循環緩存之間的站臺數,實驗中按圖1所示結構的數據,該級數將影響循環出口預取的性能,因此特別列出.
本文使用SPEC2006測試集[10]對指令循環緩存結構進行性能測試.gem5模擬器無法正確運行SPEC2006測試集中所有的程序[9].雖然其中部分程序經過對模擬器的修改可以完成運行,為了保證測試結果的一致性,本文選用了SPEC2006中的12道程序進行測試,具體程序如表2所示.測試包括引入循環緩存之后的流水線性能、循環緩存的命中率、循環緩存帶來的功耗降低以及循環出口預取等測試.

Table 2 Benchmark List表2 測試程序列表
本文采用CACTI存儲器功耗模型[11]對指令緩存的訪問功耗進行評估.本文對32條指令、64條指令、128條指令、256條指令這4種配置的循環緩存進行測試,實驗中流水線的L1指令緩存容量設為16 KB.上述5種容量的存儲器訪問功耗如表3所示:

Table 3 The Energy of Memory Accesses表3 存儲器訪問功耗
表3中128 B到1 KB存儲器數據使用單體RAM,行寬度為8 B;16 KB存儲器數據使用4體RAM,行寬度為64 B.表3中數據基于32 nm工藝.
本文分別對容量為32條指令、64條指令、128條指令、256條指令這4種配置的循環緩存進行了命中率測試.圖4展示了4種配置下的命中率結果,橫著給出了12道測試程序,縱軸為各程序在循環緩存中的命中率,不同色塊表示不同容量的指令循環緩存.從圖4可以看出,循環緩存容量的翻倍能夠帶來5%左右的命中率提升,當緩存容量到達256條指令時,其平均命中率達到37%.文獻[4]中的平均命中率在循環緩沖容量到達32條指令之后就不再有效增長,本文的結果同文獻[4]結果的差異主要在于2點:1)同文獻[4]中給出的結果相比,本文使用的是SPEC2006的測試集,由于文獻[4]是面向嵌入式處理器而設計的循環緩存,因此其使用的是針對嵌入式系統的PowerStone[12]測試集,因此在命中率的絕對值上有差異;2)本文的循環緩沖支持內嵌的循環和內嵌的預測為不跳轉的前跳轉移指令,當容量擴大時,滿足該條件的大循環可以被裝載入循環緩沖,因此本文緩存命中率隨著緩存容量的增大而持續增加.為了降低實現復雜度,本文的循環緩存沒有完全支持循環中內嵌前向跳轉的轉移指令,因此本文的循環緩存命中率在某些應用中不足10%.但是后續實驗表明,由于采用了循環出口預取,本文的循環緩存對流水線性能不會帶來影響,因此循環緩存帶來的能效收益始終是存在的.

Fig. 4 Hit rate of the loop cache圖4 指令循環緩存命中率
本文采用同流水線緊耦合的循環緩存設計,并通過循環出口預取來消除循環退出時的流水線氣泡,對循環出口預取的測試如圖5所示.圖5中給出了使用或不使用預取機制時循環緩存對流水線性能帶來的影響,例如,在沒有預取機制且緩存容量為32條指令時,循環緩存會造成流水線性能1.48%的損失.沒有預取機制時,循環緩存容量的增大會導致性能損失略微增加.這是因為更大的循環緩存將帶來更高的命中率,而使得更多的循環體在循環緩存中被讀出,因此遇到循環出口的次數也會增加,如2.4節所述,更多的循環出口會帶來更大的性能損失.由圖5可以看出,采用循環出口預取可以有效地減少循環出口退出時的性能損失.當循環緩存容量達到64條指令或以上時,采用循環出口預取技術可以認為循環緩存不再對流水線性能帶來影響.

Fig. 5 The effect of loop exit prefetching圖5 循環出口預取機制的效果

Fig. 6 The power reduction of pipeline’s instruction unit from the loop cache圖6 循環緩存對流水線指令部件功耗的降低
利用循環緩存的命中率結果以及表3中的數據,可以對循環緩存帶來的存儲器訪問功耗降低進行計算,如圖6所示.如表3所示,不同容量的存儲器訪問功耗不同,當一部分指令取指命中在循環緩存中時,其訪問功耗將顯著降低,按照式(1)可以計算得出1次指令緩存訪問的平均耗能.其中E*表示指令訪問的耗能,P*表示取指在循環緩存或者L1指令緩存中的命中率.利用式(1),可以計算出循環緩存技術可以降低30%左右的指令緩存訪問功耗.
Eave=PL0×EL0+PL1×EL1.
(1)
由于在循環緩存中命中后,可以對流水線前段站臺進行門控,進而節省流水線前段站臺的功耗.顯然,門控前段站臺的比例等于取指命中循環緩存的比例(如圖4中Average所示),因此循環緩存可以進一步降低22%~37%的流水線前段站臺功耗.
本文作為體系結構研究同硬件可實現性緊密結合的一次嘗試,提出了一種同流水線緊耦合的指令循環緩存設計.指令循環緩存不僅充當流水線前段與后段之間的一個解耦合指令隊列,也可以作為L0指令緩存以提供高能效的指令取指.實驗結果表明,在不犧牲流水線性能的前提下,以容量為128條指令的循環緩存為例,指令循環緩存可以降低27%的指令取指存儲器功耗和31.5%的流水線前段邏輯動態功耗.
未來工作可以在考慮有效控制實現復雜度的同時,增加循環緩存對內嵌有前向跳轉指令循環的全面支持,由此可以帶來更大的能效收益.同時,本文的循環緩存實現在流水線的譯碼部件之前,存放的是譯碼前的指令,后續的工作可以考慮將循環緩存放置在譯碼部件之后,但是譯碼部件后的指令循環緩存同流水線的耦合方式將需要重新考慮.