250 likes | 413 Views
HELIX: Automatic Parallelization of Irregular Programs for Chip Multiprocessing. 2012-11-25 謝政宏. 介紹 HELIX 介紹 迴圈平行化演算法 正規化迴圈 標識資料相依性來滿足要求 開始下個迭代 計算序向片段 減少序向片段 最大限度地減少信號 插入執行緒間的通信 與輔助執行緒耦合 合併程式裡的平行迴圈 選擇迴圈進行平行化. 大綱. 1. 介紹. 現在多核處理器是常見的,因此編譯器有必要能從普通不規則的單執行緒來源編譯成多執行緒程式碼。
E N D
HELIX: Automatic Parallelization of Irregular Programs for Chip Multiprocessing 2012-11-25 謝政宏
介紹 HELIX 介紹 迴圈平行化演算法 正規化迴圈 標識資料相依性來滿足要求 開始下個迭代 計算序向片段 減少序向片段 最大限度地減少信號 插入執行緒間的通信 與輔助執行緒耦合 合併程式裡的平行迴圈 選擇迴圈進行平行化 大綱
1. 介紹 • 現在多核處理器是常見的,因此編譯器有必要能從普通不規則的單執行緒來源編譯成多執行緒程式碼。 • 對於迭代間沒有資料相依關係的迴圈,一個簡單延展性佳的平行化方法,即將每個迭代實現成一個單獨的執行緒。 • 但對於一般的迴圈,執行緒間的通信會阻礙編譯器撰寫者簡單地從每個迭代分配執行緒。 • 迭代間迴圈相依不只意謂著計算結果必須在執行緒前轉發,也代表迴圈本體一些部分必須要序向執行和同步。 • 基於這些觀察,我們開發了迴圈平行化的新技術,稱為HELIX,用於分配選定的迴圈迭代,並將執行緒綁定到核心的一環。
2. HELIX (1/3)介紹 (1/4) • HELIX利用程式碼轉換,以最大限度地減少效率低落的序向片段、資料傳輸、信號傳遞、和執行緒管理。 • 只要有可能,HELIX會平行執行不同的序向片段。 • 如圖1中所示序向片段1和3重疊了。
2. HELIX (1/3)介紹 (2/4) • 核心之間資料的傳輸會是開銷的一個重大來源,相較於每個迭代之間花費的數量,可以保持核心間轉送的資料量較小。 • 圖2表明我們所選擇的迴圈中的RAW相依,唯一可能導致資料傳輸的相依。因為指令a和b之間的資料相依,在這裡我們有三個依序執行的程式碼區塊。 • 對於連續的迴圈迭代i和i+1分別運行在內核ci和ci+1,只有當迭代i執行a和迭代i+1執行b時資料需要從ci傳送到ci+1。 • 假設迴圈本體中的每個分支有著相同的機率發生或不發生,這種情況發生的機率只有6.25%。
2. HELIX (1/3)介紹 (3/4) • 另一個效率低落的來源在於通知執行緒已經發生的事件(例如,序向片段的結束)。 • 最後,HELIX有效的組織執行緒,使得一個主要執行緒在平行迴圈之外執行程式碼。 • 在平行迴圈之間,主要執行緒藉由平行化來參與,而輔助執行緒則是使用如執行緒池來執行個別的迴圈迭代和預取信號。 • 針對N個核心,HELIX會產生2N個執行緒,包含1個主執行緒、N-1個平行執行緒、和N個輔助執行緒。 • 圖3(b)顯示出兩個迭代迴圈在四核處理器上的執行結果。 • 主執行緒在迴圈外執行時,用於配置平行執行緒和輔助執行緒。 • 接著平行執行緒和輔助執行緒平行的運行迴圈迭代,並在運行結束時通知主執行緒。 • 最後主執行緒則繼續執行迴圈後的序向程式碼部分。
2. HELIX (1/3)介紹 (4/4) Figure 3: (a) Normalization of a loop so that it can be parallelized by HELIX. (b) Overview of the execution of two loop iterations.
2. HELIX (2/3) 2.1 迴圈平行化演算法 (1/12) • 第1步:正規化迴圈。 • HELIX藉由將迴圈形成如圖3(a)的形式來轉換迴圈。正規化的迴圈包含兩個區域,序言(prologue)和本體(body)。 • 序言是用來決定下一迭代序言是否被執行,而必須被執行的最小指令集合。 • 本體則是迴圈的其餘部分。 • 第2步:標識資料相依性來滿足要求。 • 為檢測資料相依關係,HELIX利用程序間指標分析(interprocedural pointer analysis)[17]於整個程式。 • 為避免不必要同步,HELIX只能滿足必要於迴圈進行的資料相依性。 • 有一部分的迴圈資料相依,包含排除暫存器或堆疊呼叫的假相依(即WAW、WAR),因為每個迭代被執行在個別的核心上,有著自己的內部暫存器和堆疊呼叫而不會暴露給其他執行緒。
2. HELIX (2/3) 2.1 迴圈平行化演算法 (2/12) • 第3步:開始下個迭代。 • 迭代以非預測的方式來執行,一旦前一迭代的序言已經執行,每個迭代將開始於平行執行緒中。 • 為了滿足迴圈的控制相依關係,迭代i+1只有(至少)當它的序言被執行時才會開始。 • 第4步:計算序向片段。 • 對於每一個資料相依,d = (a, b)∈Ddata,HELIX插入Wait和Signal操作,以確保在不同迴圈迭代發生的a和b會以正確的順序執行。 • 指令Wait(d)區塊阻礙執行緒的執行,直到前一個執行緒執行Signal(d)來發送一個信號(例如資料信號)。 • 例如在圖4中,程式碼區塊B以迴圈迭代順序運行,而程式碼區塊A和C則是平行執行。
2. HELIX (2/3) 2.1 迴圈平行化演算法 (4/12) • 第5步:減少序向片段。 • HELIX應用行內方法(method inlining)和程式碼排程,以確保序向片段很小。 • 如果在迴圈中函式呼叫和另一個指令存在有一個資料相依,則會使用行內函式呼叫,來提供該情況不會發生在子迴圈中。 • 在使用行內後,程式碼會被排程。對於每個包含資料相依d = (a, b)∈Ddata的序向片段,不直接相依於指令a或b會在片段之後移動。 • 這減少了在圖5中顯示的問題。 • 平行程式碼尚未在迴圈迭代中作很好的平衡,如果序向片段保持在迴圈後端,這將導致不必要的延遲。 • 基於相同的原因,屬於序向片段的其餘指令會盡可能上升到控制流圖。
2. HELIX (2/3) 2.1 迴圈平行化演算法 (5/12) Figure 5: Reducing execution stalls by percolating sequential segments upwards.
2. HELIX (2/3) 2.1 迴圈平行化演算法 (6/12) • 第6步:最大限度地減少信號。 • HELIX利用程式碼優化,來移除因插入Wait和Signal操作的冗餘部分 • 藉由資料流分析,移除多餘的Waits操作。 • 如果每個控制路徑到Waiti,包含另一個有著相同相依性的Waitj,則Waiti是冗餘的。 • 此外,序向片段會因步驟5而滲漏出,可以藉由部分合併來減少整體的信號量。 • 如果他們可以被排程而不需要平行程式碼時,HELIX會合併序向片段。 • 最後,HELIX使用一個相依的同步dj,來同步其他者,例如di,使得di因為dj而成為冗餘。 • 如果Wait(dj)在每個Wait(di)發生時是可用的,則資料相依di會因dj而成為多餘的。
2. HELIX (2/3) 2.1 迴圈平行化演算法 (7/12) • 第7步:插入執行緒間的通信。 • 對於迴圈進行所需的相依同步,是利用被執行序記憶體緩衝所呼叫的個別執行序記憶體區域來實現,其駐留在系統的共享記憶體中。 • 執行緒使用其執行緒記憶體緩衝區來接收從先前迭代執行時所發送的信號。 • 執行緒只能從它自己的記憶體緩衝區中讀取,且只能在其繼承者(下一個執行的迴圈迭代)的記憶體緩衝區寫入。 • Wait和Signal操作則可以簡單的由讀取和存入來實現。 • 第8步:與輔助執行緒耦合。 • 當一個核心ci,發送信號到另一個核心cj,其寫入一個值到執行緒記憶體緩中的特定記憶體位置,即放至ci的第一私有快取。 • 該值不會被轉發到cj的私有快取,直到cj處理了相對應的Wait指令(例如,一個讀取操作)。然後,cj需要幾個週期來接收該值。
2. HELIX (2/3) 2.1 迴圈平行化演算法 (8/12) • 第8步:與輔助執行緒耦合。(續) • 圖7顯示了平行迴圈的執行,包含3個序向區段SS1、SS2、SS3。 • 1) No prefetching,代表在第7步驟所產生的程式碼的執行。 • 因為只有當接收者試圖進入相對應的序向片段時,信號才會開始,每個信號花費S個時脈週期轉移到每個核心。 • 2) Prefetching without balancing,表示輔助執行緒沒有使用圖6的演算法時的執行狀況。 • SS3和SS1之間的時間間隔夠長來預取信號,因此只有來自SS1的信號被完全預取,而其他的只是稍微預取。 • 3) Prefetching with balancing,展示了如何均勻的預取信號,以更好地利用內核的閒置時鐘週期。 • 最後請注意,這三種情況(A+B+C)花費在執行平行程式碼的總體時間是固定的。
2. HELIX (2/3) 2.1 迴圈平行化演算法 (11/12) • 圖6的程式碼排程演算法以未預取和完全預取的排程迴圈、平台相依延遲來作為輸入。 • 一開始,程式碼屬於迴圈L,並且未標示可以並行運行者(第2行)。 • 演算法持續運行,直到有沒有更多未標記的平行程式碼(第5行)或所有的序向片段對有足夠的空間(第8行)。 • 因為我們希望能均勻的預取信號,該演算法考慮的兩個最親密的的序向片段(即j和j+1)(第7行)。 • 為了防止平行程式碼的貪婪配置,演算法也考慮未來兩個最親密的序向片段(即k和k+1)(9~10行)。 • 未標記的平行程式碼會被移動到最靠近序向片段,來增加1到他們的即時空間,以及兩個序向片段的最大差異(11~15行)。 • 移動後的平行程式碼接著會被標誌,以避免再次被移動(16行)。
2. HELIX (2/3) 2.1 迴圈平行化演算法 (12/12) • 第9步:合併程式裡的平行迴圈。 • 包含平行迴圈的函式,可能/可能不會被正平行運行的迴圈給呼叫。 • 由於一個迴圈只能平行運行一次,HELIX保留著每個平行迴圈的序向版本,以避免其他已經平行運算的情況。 • 如果沒有其他平行迴圈被執行(由全域變數辨識),就直接執行平行迴圈。否則改執行迴圈的序向版本 • 當迴圈中有多個後繼者,HELIX與每個出口路徑的序言關聯一個獨特的數值。 • 執行最後迭代的執行緒設置出口變數到出口路徑所選擇的數值。 • 當所有平行執行緒都完成後,主執行緒檢查該變數然後轉跳到正確的後繼者。
2. HELIX (3/3) 2.2 選擇迴圈進行平行化 (1/5) • 將迴圈轉變成平行執行緒可以加快迴圈的執行,其提供並行的好處超過了執行緒之間的通信代價。 • 我們的方法將處理器中的所有核心同一時間只給一個平行迴圈專用,因此多個獨立的迴圈無法同時運行,平行迴圈中的巢狀迴圈也無法被選為平行化。 • 因此,選擇最有利的迴圈來轉換(即如果平行化該迴圈可以最加快程式)是用來實現顯著加速性關鍵。 • 我們的啟發式方法使用動態迴圈巢狀圖(dynamic loop nesting graph)來辨識最有利的迴圈進行平行化。 • 這是一個根據Amdahl定律的簡單搜索模型。
2. HELIX (3/3) 2.2 選擇迴圈進行平行化 (2/5) • 加速模型: • 在選擇迴圈時,我們合併了Amdahl定律中的開銷,來產生下述平行化程式的加速模型: • Loops是平行化迴圈的數量,Pi是迴圈i程式碼運行在序向片段所花費的時間(為了確保程式語法而運行的序向程式碼區域),Oi是該迴圈的其他開銷(例如,執行緒同步的開銷)。 • Pi和Oi項依賴於平行迴圈所使用的特定程式碼轉換技術。
2. HELIX (3/3) 2.2 選擇迴圈進行平行化 (3/5) • 迴圈選擇演算法: • 我們的最佳平行化迴圈的選擇演算法,是使用上述的加速模型和動態迴圈巢狀圖。 • 我們分析的範圍是整個程式(因此有多個函式),並且我們將迴圈中的函式呼叫視為迴圈的子迴圈[6]。 • 圖8顯示出了SPEC CPU2000測試程式179.art.的動態迴圈巢狀圖。 • 迴圈選擇演算法在動態迴圈巢狀圖中對每一個節點(迴圈)加入兩個特性,保留時間(T)和最大保留時間(maxT)。 • T是由加速模型所計算,設置為執行序向版本和平行版本的時間差。 • maxT提供目前迴圈或其子迴圈組合平行化後所能省下的時間資訊。
2. HELIX (3/3) 2.2 選擇迴圈進行平行化 (4/5) • 迴圈選擇演算法有兩個階段。 • 該演算法的第一階段由內向外傳遞maxT穿過圖。 • 如果一個迴圈的子迴圈的maxT總合超過目前maxT值,則該總和將成為其新maxT。 • 在動態迴圈巢狀圖中重複此步驟,直到到達某固定點。 • 該演算法的第二階段,一開始從最外層的迴圈節點向內搜尋,直到它到達一個maxT等於T的節點。 • 演算法是由上到下的,是因為藉由越深入巢狀圖,我們會越失去程式碼的平行性。理想情況下,我們會選擇最外層的迴圈。 • 每當有路徑上有分裂時(當迴圈有多個子迴圈時),繼續在各個方向上搜索。 • 圖8顯示出在兩階段演算法被應用後的動態迴圈巢狀圖。