官术网_书友最值得收藏!

1.4 多核并行優(yōu)化

仔細觀察CPU的使用情況后會發(fā)現(xiàn),上述程序?qū)崿F(xiàn)其實只使用了CPU上的一個核心(core)對矩陣乘法進行計算,即可以認為整個程序是串行地進行計算的。這種情況下,我們并沒有把現(xiàn)代處理器的多核硬件資源充分利用起來。為此,可以對矩陣乘法的計算任務(wù)進行合理拆分,并且把拆分后的任務(wù)分別運行在CPU的不同核心上并行處理,從而充分利用底層的硬件資源。

這里,采用OpenMP并行化編程標準和Intel oneAPI工具套件實現(xiàn)多核并行優(yōu)化。OpenMP是一套用于多核處理器并行編程的接口規(guī)范,利用OpenMP編程接口可以輕松地寫出高度并行化的程序。例如,利用OpenMP定義好的規(guī)范編程接口,可以對矩陣乘法程序的for循環(huán)進行并行化處理,把每個循環(huán)迭代里的任務(wù)拆分到不同的線程和核心上做并行化處理。ICX編譯器集成了OpenMP套件,可使用如下命令編譯:

在使用OpenMP編寫程序的時候,需要特別注意程序并行后的正確性。一個常見的問題是,對哪一層循環(huán)進行并行化處理才可以保證程序的正確性?例如,在針對k, i, j循環(huán)順序進行并行化的時候,需要對第二層循環(huán)體加上并行處理來保證程序的正確性。代碼1.5給出了對k, i, j循環(huán)順序進行并行化的參考代碼,它與代碼1.4的主要區(qū)別是在第二層的i循環(huán)上添加了OpenMP并行化處理的接口。其中,schedule(static)表明申請的線程會靜態(tài)分配給每個循環(huán),不會進行動態(tài)的線程資源調(diào)度;firstprivate表明會為每個線程初始化其循環(huán)中對應(yīng)k的值;shared表明A、B、C三個變量是多個線程共享的。

代碼1.5 采用了k, i, j循環(huán)順序和OpenMP并行化的矩陣乘法

在代碼1.5中,若選擇對最外層的k循環(huán)而不是第二層的i循環(huán)進行并行化,那么根據(jù)k, i, j循環(huán)順序的訪存模式,此時不同的線程會對矩陣C的同一位置進行并發(fā)寫入,引起數(shù)據(jù)競爭和沖突,從而不能保證矩陣乘法計算結(jié)果的正確性。值得注意的是,矩陣乘法中不同的循環(huán)順序會導(dǎo)致使用不同的并行化策略。例如,對同樣具有良好訪存模式的i, k, j循環(huán)順序進行并行化實現(xiàn)時,需要添加并行化處理的是最外層的i循環(huán)。為了方便對比,代碼1.6給出了基于i,k,j循環(huán)順序進行并行化處理的參考代碼。

代碼1.6 采用了i, k, j循環(huán)順序和OpenMP并行化的矩陣乘法

實際上,這兩種不同循環(huán)順序的并行化方式會帶來不小的性能差異。在k, i, j的循環(huán)體實現(xiàn)中,每輪k的迭代都需要重新申請新的線程來處理矩陣乘法子任務(wù)。從操作系統(tǒng)資源分配的角度來看,采用這種策略無疑是消耗比較大的。這里可以做一個簡單的計算,假如我們選擇分配16個線程來處理該矩陣乘法的任務(wù),在k, i, j循環(huán)之下,最外層的k循環(huán)總共有4096次迭代,而每輪k的迭代都需要申請16個線程來進行內(nèi)層循環(huán)的并行化處理,那么完成該矩陣乘法的所有循環(huán)迭代總共需要申請4096×16=65 536個線程來進行處理。反觀采用同樣緩存友好型的i, k, j循環(huán)順序,則只需要在最外層循環(huán)進行對應(yīng)線程的申請,即只需要申請16個線程就能完成矩陣乘法的處理,這樣整體消耗的線程數(shù)量要比采用k, i, j循環(huán)順序少得多。

除此之外,在i, k, j循環(huán)順序的并行化處理方式當中,各個線程之間可以并發(fā)地處理4096×4096=224次循環(huán)迭代。反觀k, i, j的循環(huán)并行化,每個線程之間只能并發(fā)地處理4096次循環(huán)迭代。由此可見,i, k, j循環(huán)順序并行化后的處理效率更高。

我們對兩種循環(huán)順序的并行化實現(xiàn)進行了性能測量,具體數(shù)據(jù)如表1.5所示。可以看出,采用i, k, j循環(huán)順序并行化后的性能比采用k, i, j循環(huán)順序并行化更好。同時,隨著并行線程數(shù)的增加,并行化性能也持續(xù)得到了提升。注意:在編寫并行化for循環(huán)程序的時候,盡量對最外層循環(huán)進行并行化,這樣往往可以獲得最佳的性能。

表1.5 不同循環(huán)順序并行化對運行時間的影響

對于OpenMP中所采用的并行線程數(shù),可以通過配置系統(tǒng)環(huán)境變量來實現(xiàn)。通常,可以通過設(shè)置OMP_NUM_THREADS系統(tǒng)環(huán)境變量來指定處理并行任務(wù)用到的線程數(shù)量。另外,也可以通過設(shè)置OMP_PLACES變量來表明要將對應(yīng)的線程分配到CPU的哪個核心上進行處理。例如,將OMP_PLACES設(shè)置為“{0}:16:1”,表明這16個線程要從CPU的0號核心開始放置,總共放置16個核心,且每個核心放置的間隔步長為1。這樣,OpenMP的運行環(huán)境就會把線程按照具體調(diào)度的策略分配到0~15號核心上。

在這個實驗中,我們選擇最多采用16個線程來對矩陣乘法進行處理。下面給出本例的OpenMP系統(tǒng)環(huán)境設(shè)置:

可以配合使用以下numactl命令,保證OpenMP程序綁定到CPU指定的核心上運行,同時可以限定OpenMP程序的內(nèi)存訪問節(jié)點:

接下來,我們繼續(xù)對并發(fā)性能較好的、采用i,k,j循環(huán)順序的代碼1.6進行優(yōu)化。

主站蜘蛛池模板: 东丽区| 太和县| 六盘水市| 久治县| 寿光市| 崇礼县| 安化县| 镇远县| 阿克苏市| 壤塘县| 武夷山市| 沿河| 沧州市| 荣成市| 武定县| 乡宁县| 临沭县| 凤冈县| 渝中区| 中西区| 中阳县| 澎湖县| 泸西县| 肇庆市| 松阳县| 枣强县| 两当县| 什邡市| 临朐县| 奈曼旗| 丹巴县| 长子县| 峨山| 隆昌县| 怀宁县| 治多县| 余庆县| 莆田市| 太白县| 濉溪县| 封开县|