天天看點

《OpenACC并行程式設計:性能優化實踐指南》一 1.3 Amdahl定律及其擴充

繪制任務運作時間,可以看到并行增加應用程式的擴充行為。并行計算的理論性能:運作在有N個處理單元的并行計算機上,理論上可以獲得N倍加速。換一句話說,一個程式運作在10核處理器上可能獲得10倍加速(對于固定大小的問題),在支援1000個并發執行線程的GPU上獲得1000倍加速。開發人員依據Amdahl定律來讨論并行與串行間的加速比。

用計算機架構師Gene Amdahl來命名Amdahl定律。它不是實際上的定律,但是修改串行程式使其并行執行時,它相當接近模型理論加速比。為使這個近似值有效,在并行化時有必要保持問題規模相同,通常稱為強擴充。換句話說,假定修改串行程式使其并行執行,在并行版本代碼中程式執行的工作量并沒有顯著地變化。顯然,并行部分可能運作得更快,這取決于硬體能力。是以,使用N個處理器,串行代碼并行執行期望的加速比S(N)由程式可并行比例P和不可并行比例(1―P)決定。公式(1-1)顯示了這種關系:

《OpenACC并行程式設計:性能優化實踐指南》一 1.3 Amdahl定律及其擴充

Amdahl定律告訴OpenACC開發人員在并行化程式時有兩個目标:

1.表達代碼并行部分,使其盡可能快地執行。理想情況下,使用N個處理器有N倍加速。

2.利用任何的技術或手段來減少1―P串行時間。

并行部分代碼執行很快使得程式運作時間主要由串行部分代碼占據,這是有可能的。這是計算機架構師将強大的順序處理器(如CPU)與并行處理器和協處理器混合使用的原因之一。

理論上通過增加計數器,accTask.cpp忙工作的任務示例将在所有OpenACC裝置上全速運作,因為它被設計成100%計算限制,意味着處理器是限制性能的系統元件。實際應用中通常要複雜很多,其性能可能受到存儲器和網絡帶寬之類的其他因素影響。随着并行性的增加,許多并行應用程式的性能受到限制,因為它們嚴重依賴于存儲器中的資料。因而增加更多的處理單元并不會提高性能,并且可能損失性能,處理單元大部分時間消耗在等待資料上。accFill_ex1.cpp和accFill_ex2.cpp示例都是存儲器瓶頸,意味着存儲子系統的性能限制了程式性能。

計算機架構的緩存可以幫忙提高性能,在高速緩存存儲器中預取和存放經常通路的或熱點資料。這就是并行程式設計人員對局部性和流行為很感興趣的原因。利用高資料局部性的程式通常運作得更快,因為它們可以用完寄存器或緩沖存儲器。accTask.cpp示例就是一個例子,它使用一個寄存器并且在忙循環中沒有其他的記憶體取操作。将資料流出存儲器的程式也往往運作得更快,是以資料可以被預取到更快的高速緩沖存儲器中。理想情況下,流程式完全不受存儲子系統限制,呈現很好的擴充性。局部性和流行為的關鍵是對每個取出的資料項執行足夠的計算來隐藏存儲器事務的開銷。從記憶體,跨網絡,資料倉庫或跨PCI總線取資料時,這點依舊成立。

大O表示法是一個友善的方式來描述問題規模如何影響算法某些資源的消耗,例如處理器時間或存儲器作為算法輸入的函數。通過這種方式,計算科學家可以描述算法的最壞和平均情況運作時行為。可以用大O描述法來比較算法,以幫助了解并行算法的類型。哪些算法可能對每個取出的資料項表現出高計算性,确定适合OpenACC程式設計的算法。

一些常見的大O增長率如下所示:

O(1):常量時間(或空間)算法,不管輸入集合大小始終消耗相同資源。例如,索引向量中的單個元素不随時間或資料集的大小而變化,是以表現出O(1)運作時增長。

O(N):算法資源消耗随着輸入問題規模N而線性增長。這對于循環資料集(大小為N)的算法是常見的,其中循環内的工作需要的時間是恒定的。

O(N2):性能與輸入資料集大小的平方成正比。典型示例是在輸入資料集上使用嵌套循環的算法,表現出O(N2)運作時。深層嵌套疊代通常顯示更大的運作時(例如,三層循環導緻O(N3),四層循環導緻O(N4),依次類推)。

有很多優秀的算法分析書籍,更精确和全面地講解了大O表示法。其中最流行的一本書籍是<<算法導論>>(Cormen, Leiserson, & Rivest, 2009)。在網絡上也有許多談論和講授大O表示法和算法分析的資源。

大多數計算領域的科學家和程式員都熟悉BLAS(基本線性代數子程式)庫。BLAS是基本線性代數實際上的程式設計接口。為了保持競争力,多數處理器供應商提供高度優化的BLAS庫。也可使用強大的異構高性能稠密線程代數庫,例如田納西大學創新計算實驗室的MAGMA項目。異構計算使用主機處理器(CPU)和很多OpenACC裝置類型的計算能力。MAGMA通過使用所有的系統計算能力來獲得高性能。MAGMA目前可以免費下載下傳。

根據三個不同的級别,随着資料和運作時需求的增加而建構BLAS。

級别1:需要O(N)資料和O(N)任務的向量-向量操作。例如計算兩個向量的内積,或通過常數乘法器縮放向量。

級别2:需要O(N2)資料和O(N2)任務的矩陣-向量操作。例如矩陣-向量乘法,或單個右手三角求解。

級别3:需要O(N2)資料和O(N3)任務的矩陣-向量操作,例如稠密矩陣-矩陣乘法。

假定從主機向OpenACC裝置傳輸N個浮點數值,表1-1說明了每個BLAS級别所要執行的全部任務。

《OpenACC并行程式設計:性能優化實踐指南》一 1.3 Amdahl定律及其擴充

可以看出級别3的BLAS操作應該高效執行,因為對于傳輸到OpenACC并行裝置的每個浮點值執行O(N)任務。任務/資料的分析同樣也能應用于非BLAS相關的計算問題。

為了實作高性能需要盡量把資料儲存在OpenACC裝置和離處理器近的緩沖存儲器上,這點是很明确的。在這之後,為了獲得高性能需要對每個資料執行盡可能多的計算,就像級别3的BLAS操作。建立一個有許多低算術密度計算的流水線有助于提高性能,但是隻有當每個操作使得OpenACC裝置足夠忙碌,以至可以隐藏任何裝置啟動延時時,才能提高性能。或者,結合多個例如級别1和級别2 BLAS操作的低密度操作,可能會(有時會顯著地)提高性能。Kernel子句可以幫助做到這一點。

之前讨論的可以總結出關于異構模型程式設計的三條規則:

在OpenACC裝置上擷取資料并且把資料儲存在裝置上。

這将盡可能地減少或消除資料傳輸開銷。特别地,OpenACC程式設計人員應該學習使用present()子句和條件資料傳輸子句(例如present_or_copy())。當程式運作在共享記憶體裝置(例如多核CPU)上時,允許OpenACC運作時消除資料傳輸。

給OpenACC裝置執行足夠多的任務。

快速運作并行代碼段的一個挑戰是OpenACC裝置的啟動時間大于或等于運作時間。記住大多數現代OpenACC處理器能夠實作多個TF/s(兆浮點/秒)性能。基本上應用程式必須每微秒執行1百萬次操作才可以抵消在這些裝置上啟動并行代碼段的開銷。

注意資料重用以避免存儲器帶寬限制。

正如之前讨論的,針對高局部性的資料重用的程式設計,意味着編譯器和硬體可以把

資料儲存在最高性能的寄存器和高速緩沖存儲器中。OpenACC編譯器還可以幫助優化寄存器複用和預取。同樣,present_and_*子句可以複用已經傳輸到裝置的資料。

如前所述,accTask.cpp代碼被設計為具有極高的局部性參考。實際上,這個代碼使用一個寄存器變量,并且沒有明顯的存儲器性能依賴。圖1-11顯示了在x86 CPU上accTask.cpp單線程版本的運作時間。

請注意,單線程任務串行執行4個任務時,在Intel四核E5630 2.53GHz的系統上需要大約4倍的單任務時間(如57.4627/14.5115=3.95)。這個比例是近似值,因為在時間測量中存在一些粒度。

《OpenACC并行程式設計:性能優化實踐指南》一 1.3 Amdahl定律及其擴充

使用bash腳本(如圖1-12所示)來生成運作時間表,可用來檢視運作時間與核數的關系。

《OpenACC并行程式設計:性能優化實踐指南》一 1.3 Amdahl定律及其擴充

圖1-13闡明了一個運作時間相對于基于核數的單線程值的階梯模式。換句話說,如果每個核超量訂閱相同數量的任務,運作時間是相同的。例如,硬體核超量訂閱2倍任務,運作時間是單線程時間的2倍。繼續訂閱超過處理核數的任務,依舊可以清楚地看到這個行為。

《OpenACC并行程式設計:性能優化實踐指南》一 1.3 Amdahl定律及其擴充

如圖1-14所示,使用PathScale Enzo OpenACC編譯器編譯運作在96核Cavium Thun-derX ARM64系統上的可執行檔案,也可以看到類似的擴充性。

《OpenACC并行程式設計:性能優化實踐指南》一 1.3 Amdahl定律及其擴充

繼續閱讀