其他取得π值的方法:
(1)黎曼ζ函數 ζ(2)=π2/6;
(2)沃利斯乘積
(3)高斯積分
(4)…
一開始完全不知道程式要怎麼產生想要的資料,所以觀察了一下Makefile,發現比起phonebook,又多一些看不懂的東西。
原來Makefile也可以用迴圈,而seq 100 5000 20000
代表起始值100,等差5000,20000代表結束,其將作benchmark_clock_gettime的argv[1],printf與benchmark_clock_gettime將匯入result_clock_gettime.csv。
在benchmark_clock_gettime.c
中,每種方式都執行了25次,並且將其紀錄於表格中,如果將表格以.txt
開啟,或是觀察printf
輸出格式,可以發現到格式其實是以逗號分隔:
因此在做圖時,script需要set datafile separator ","
,gnuplot才能區分每一行。
花了很久時間才寫好script
圖片:
我發現每次執行都有落差(尤其是OpenMP(4)),可能時間短得不明顯又很少次,所以我把25次改為10000次
這次有了比較一致的答案:
效率上AVX+LR > AVX >>> OMP(2) > OMP(4) >>> Baseline
接著,Loop數不變,將N放大
在N比較小的情況下,OpenMP(4)有機會比Baseline效率還低,OpenMP(4)整體來說似乎不太穩定。
OpenMP(2)在9e5~1e6間也出現了明顯的升高,但在另一張圖沒有出現,對此沒有結論。
…
平行化需要注意到的問題,就是變數的存取,不同執行緒對共享變數做修改/讀取,可能會產生不可預期的結果,OpenMP提供了很多方法來讓我們決定變數要怎麼運作。
參考OpenMP變數的平行化歸納以下幾個常用的:
private:每個執行緒有各自的變數(但不會初始化值!)。
firstprivate:同private,但變數值為執行緒前的變數值。
lastprivate:同private,但原變數值會改為執行緒結束時的值。
atomic:防止多個執行緒修改。
reduction:每個執行緒有各自的變數(值為單位元素),最後在合併。
在raytracing時有使用過,但不是很理想。
在這裡充分的運用,ymm0~2為係數,ymm3作為運算,ymm4儲存運算結果
利用到更多的avx暫存器,可以減少迴圈的數量,一個迴圈處理16個double,每個都多了原本的ymm2、ymm3、ymm4,等於一個迴圈中用了5+3+3+3=14個暫存器。
作業說明中有提到CPU time是每條執行緒的時間加總,為了觀察到這個結果,我把每一種方法個別執行
可以發現到user time與real time的關係,與執行緒的數量密切相關
Makefile 語法簡介
使用gnuplot科學作圖
Visual C++ OpenMP doc
OpenMP變數的平行化
clock_gettime
knowing the current time