120 likes | 334 Views
Parallel Programming of General-Purpose Programs Using Task-Based Programming Models. 2012-12-16 è¬æ”¿å®. I. INTRODUCTION III. NESTED TASK MODEL WITH TASK DEPENDENCIES IV. VERSIONED HYPEROBJECTS A. Dependency Tracking B. Versioning VII. POTENTIAL FOR SPECULATIVE EXECUTION. Outline.
E N D
Parallel Programming of General-Purpose Programs Using Task-Based Programming Models 2012-12-16 謝政宏
I. INTRODUCTION III. NESTED TASK MODEL WITH TASK DEPENDENCIES IV. VERSIONED HYPEROBJECTS A. Dependency Tracking B. Versioning VII. POTENTIAL FOR SPECULATIVE EXECUTION Outline
I. INTRODUCTION • 多核心處理器的出現帶來了新的並行程式設計模型的成長。 • 許多嘗試將執行緒和基於鎖的同步更換成更佳的抽象化。 • OpenMP使用任務的抽象化,一個並行工作的基本單元,作為替代執行緒的一種抽象。 • Cilk標示程式中遞迴且並行任務,並有一個排程器在運行時優化任務的同步執行。 • 遞迴任務的並行抽象Cilk,可以容易地描述一些並行模式。 • 管線並行性(pipeline parallelism)、平行階級管線(parallel-stage pipelines)、和使用巢狀平行任務的預測性並行(speculative parallelism)皆不容易描述。 • 本文擴展了Cilk程式設計模型,大大提高了設計這樣的並行結構的可讀性和密度。 • 透過添加任務參數所造成的相依性,我們擴充了Cilk並行執行模型,其相較於Cilk更加便利,且不損失效能。
III. NESTED TASK MODEL WITH TASK DEPENDENCIES (1/4) • 我們的巢狀任務模型支援巢狀地任務創建,如同在Cilk++和在SMPSS的任務參數相依型態。 • 我們擴增了輸入、輸出和輸入/輸出的相依型態到程序參數上,透過排程器在運行時執行。 • 如果任務沒有標記任何相依形態到參數上,則任務spawn是獨立的,執行spawn產生的任務總是有效。 • 如果任務簽名(task signature)至少列出一個有相依形態的參數,則該任務spawn是獨立的而且可能不會被立即執行。 • 如果任務相依關係不滿足(即在輸入或輸入/輸出中列出的相依物件尚未被其他任務計算),則我們會延遲任務的執行點。 • 我們採用排程器來重新考慮,像是程式執行時(例如在同步敘述句中)的任務延遲。
III. NESTED TASK MODEL WITH TASK DEPENDENCIES (2/4) • 相同的,同步敘述句現在可能是獨立或是相依的。 • 獨立的同步敘述句不帶任何參數,並且暫停同步任務直到所有子任務結束,如同在Cilk一般。 • 相依同步敘述句使用一組物件作為參數,並暫停工作,直到所有的參數都已經被計算。 • 這允許任務得以存取其一些孩子所計算的物件,而不限制所有獨立同步的孩子的並行性。 • 圖1顯示了一個使用我們程式設計模型的範例程式。 • 我們擴展任務參數上的相關型態到Cilk。只有versioned object可以被傳遞到這樣的參數,由versioned標籤標示。 • 該標籤附加中繼資料到物件上,允許運行時系統來追蹤生產者/消費者關係,並在執行時創建多個版本的物件。 • 相依型態完全捕獲管線性質:程式設計師僅宣告管線各個階段任務實現的輸入和輸出,然後排程器將會按照正確順序執行所有任務。
III. NESTED TASK MODEL WITH TASK DEPENDENCIES (3/4) 01int stage A(outdep<int[]> ab, inoutdep<struct S> a); 02 void stage B(indep<int[]> ab, outdep<float[]> bc); 03 void stage C(indep<float[]> bc, inoutdep<struct S> c); 04 05 void a pipeline() { 06 versioned<struct S> a, c; 07 versioned<int[100]> ab; 08 versioned<float[200]> bc; 09 while( 1 ) { 10 if (stage A(ab, a)) 11 break; 12 spawn stage B(ab, bc); 13 spawn stage C(bc, c); 14 } 15 sync; 16 } Fig. 1. A program containing pipeline parallelism expressed in the proposed task-based programming model.
III. NESTED TASK MODEL WITH TASK DEPENDENCIES (4/4) • 為了提高我們系統的可信度,我們將相依性解析演算法公式化,來顯示其產生執行順序相等於程式序向執行的順序。 • 也就是說,我們定義簡單功能性語言的序向和平行操作語義,和類似Cilk的遞迴並行和相依感知的排程器。 • 我們的序向的操作語義將spawn視為簡單的函數調用。 • 我們定義sequential equivalence屬性,等同於任何終止並行執行到序向執行且產生相同結果者,並顯示這樣的序向執行總是存在我們的相依排程。 • 為了證明相依感知排程器滿足序向等價性,我們展示了如何建構序向執行軌跡,其計算結果與任何給定的並行執行軌跡相同。 • 我們在平行軌跡中定義重新排序操作,因為其可以被重新排序而不需要改變最後的計算結果。 • 證明是由執行軌跡歸納而得,我們分解平行執行軌跡到平行軌跡之後的序向軌跡,然後藉由重新排序操作到執行軌跡來歸納成長序向執行軌跡。
IV. VERSIONED HYPEROBJECTS (1/2) A. Dependency Tracking • Versioned hyperobjects實現了運行系統的兩個功能: • 1) 追蹤任務參數的相依性。 • 2) 將物件版本化(重新命名或私有化),當它有利於提高並行性。 • Versioned objects是hyperobject的一個型態,因為它們會自動提供不同的視圖給存取相同變數的執行緒。 • 運行時系統監測物件是否就緒來追蹤並執行參數相依性。 • 相依性追踪的中繼資料,包含讀取者/寫入者的頭/尾的指標,如同FIFO的頭/尾指標。 • 嘗試spawn任務時,尾指標會遞增。當任務完成時,頭指標會遞增。
IV. VERSIONED HYPEROBJECTS (2/2) B. Versioning • Versioning只發生在spawn任務且有輸出相依性。 • 只有當先前的讀取者或寫入者正在等待才發生這種情況。 • Inout相依性從沒在我們實現中重新命名過,雖然這在某些情況下可能是有意義的,例如,避免拖延inout相依任務,只要有讀取者(輸入相依)啟用。 • 當一個versioned object被傳遞到有著輸入或輸入/輸出的相依spawn任務,則運行時系統會為父親和孩子程序安排共享相同的物件視圖。 • 當孩子返回後,父親的視圖會維持。如果孩子是最後一個使用者的視圖者,則孩子的視圖會被破壞。
V. TASK SCHEDULING • 我們實現了一個類似Cilk的work-first排程器,並假設是使用共享記憶體模型。 • 不含相依形態參數的情況下,排程器的行為類似Cilk排程器如[5]中所描述,嘗試序向執行內部迴圈,並喜好在外層迴圈層級竊取工作。 • 當子任務的參數尚未就緒,則任務會被加到父堆疊框架的等待任務列表中。 • 現在有幾種設計,選擇何時重試執行等待的任務。 • 在我們目前的實現中,當排程器嘗試執行provably-good-steal操作時,會檢索等待就緒任務們。 • 當與其父親並行執行而從spawn返回時,或當程序等待其孩子結束的同步敘述句時[5],provably-good-steal會發生。
VII. POTENTIAL FOR SPECULATIVE EXECUTION • 預測性執行是並行性的一個重要來源[3,13,14,15]。 • 我們描述基於任務的程式設計模型是如何促進預測執行。 • 圖4顯示了一個程式碼,模擬基於任務的預測程式。 • 預測並行存在於演算法階段,其中accept()很少被執行。 • 它可以透過重新指定try_swap()參數的輸入相依,作為預測輸入相依(specindep)。 • 這表明spawn任務的預測本質,但同時也暗示等待的相依outdep可能會被忽略。 • 例如,try_swap()不考慮先前accept() 的相依性,因為其預測共享state參數。 • 當accept()執行時,abort敘述句指示所有遞迴相依於目前版本的變數state和i的計算,應該要被重新執行。
VII. POTENTIAL FOR SPECULATIVE EXECUTION 01 void try_swap(indep<struct S> state, outdep<int> success, 03 outdep<struct C> changes); 04 void accept(inoutdep<struct S> state, 05 indep<struct C> changes); 06 07 void speculated() { 08 versioned<struct S> state; 09 versioned<struct C> changes; 10 versioned<int> success; 11 versioned<int> i; 12 13 for( i=0; i < N; ++i ) { 14 spawn try_swap((specindep<struct S>)state, success, changes); 16 spawn { 17 if ( success ) { 18 abort state, i ; 19 accept(state, changes); 20 } 21 } 22 } 23 sync; 24 } Fig. 4. Code mock-up for speculative parallelization.