# 2017q1 Homework1 (compute-pi)
contributed by<`zhanyangch`>
###### tags:`zhanyangch` `sysprog2017` `week1`
## Reviewed by `Sean1127`
1. 作業要求
>預期執行 $ make plot 後,可透過 gnuplot 產生前述多種實做的效能分析比較圖表
2. 要怎麼知道使用`clock_gettime()`得出的結果是正確的?`clock_gettime()`跟其他的 function 有什麼不同?
3. 時間測試圖中可以看到,當 $N = 10^6$ 左右時,時間震盪非常嚴重,有什麼可能的原因?要如何避免?
4. 梅欽類公式與原本的 baseline 版本(Leibniz),為什麼前者的誤差會比較小?
5. 使用梅欽類公式並沒有使執行速度再增加,可以繼續思考如何加速
6. git message 只有寫`add machin-like method`不夠清楚,因為他人跟本不知道什麼是 machin-like method、新增這個 method 的目的、作法
另外這次 commit 的修正應該不只有 add machin-like method,其他的更動也要寫出來比較好
## 執行環境
```
Architecture: x86_64
CPU 作業模式: 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 4
On-line CPU(s) list: 0-3
每核心執行緒數:2
每通訊端核心數:2
Socket(s): 1
NUMA 節點: 1
供應商識別號: GenuineIntel
CPU 家族: 6
型號: 42
Model name: Intel(R) Core(TM) i7-2640M CPU @ 2.80GHz
製程: 7
CPU MHz: 855.421
CPU max MHz: 3500.0000
CPU min MHz: 800.0000
BogoMIPS: 5587.06
虛擬: VT-x
L1d 快取: 32K
L1i 快取: 32K
L2 快取: 256K
L3 快取: 4096K
NUMA node0 CPU(s): 0-3
```
* 用 time 測量
```
$ make check
time ./time_test_baseline
N = 400000000 , pi = 3.141593
5.21user 0.00system 0:05.21elapsed 99%CPU (0avgtext+0avgdata 1872maxresident)k
0inputs+0outputs (0major+86minor)pagefaults 0swaps
time ./time_test_openmp_2
N = 400000000 , pi = 3.141593
5.42user 0.00system 0:02.72elapsed 199%CPU (0avgtext+0avgdata 1760maxresident)k
0inputs+0outputs (0major+87minor)pagefaults 0swaps
time ./time_test_openmp_4
N = 400000000 , pi = 3.141593
9.58user 0.00system 0:02.79elapsed 343%CPU (0avgtext+0avgdata 1828maxresident)k
0inputs+0outputs (0major+94minor)pagefaults 0swaps
time ./time_test_avx
N = 400000000 , pi = 3.141593
1.72user 0.00system 0:01.72elapsed 99%CPU (0avgtext+0avgdata 1792maxresident)k
0inputs+0outputs (0major+85minor)pagefaults 0swaps
time ./time_test_avxunroll
N = 400000000 , pi = 3.141593
1.84user 0.00system 0:01.84elapsed 99%CPU (0avgtext+0avgdata 1716maxresident)k
0inputs+0outputs (0major+87minor)pagefaults 0swaps
```
* 用 clock_gettime 測量 ,注意x軸為 log scale
```
$ make gencsv
```
![](https://i.imgur.com/SgyrUgd.png)
* 測試 N 的大小與誤差值,除了 AVX+Loop unrolling 之外的誤差皆相同
![](https://i.imgur.com/DBWE8Ak.png)
* AVX+Loop unrolling 的部份程式碼 , 當 N 不為 16的倍數時,迴圈的執行次數造成誤差
```
for (int i = 0; i <= N - 16; i += 16) {
ymm14 = _mm256_set1_pd(i * dt);
...
ymm9 = _mm256_add_pd(ymm9, ymm13);
}
```
* 修改 N 為 16 的倍數
![](https://i.imgur.com/URyWsqA.png)
## 梅欽類公式計算pi
[公式推導](https://en.wikipedia.org/wiki/Machin-like_formula)
* 先寫一個汎用的 arctan
```clike
double arctan(double x , size_t N,int threads)
{
double atan = 0.0;
double dz = x / N;
double z;
#pragma omp parallel num_threads(threads)
{
#pragma omp for private(z) reduction(+:atan)
for(size_t i=0; i<N ;i++) {
z =(double) x * i / N;
atan += dz / (1.0 + z * z );
}
}
return atan;
}
```
```clike
double compute_pi_machin(size_t N, int threads)
{
double pi = 4.0 * arctan((double)0.2, N, threads) - arctan((double)1.0 / 239, N, threads);
return pi * 4.0;
}
```
* 時間比較,梅欽類公式的部份因為要計算兩次積分,所以測試時使用 N/2 , 可以發現與原 OpenMP 版本的時間相差無幾
![](https://i.imgur.com/FkK6avk.png)
* 誤差比較,使用梅欽類公式會比 Baseline 更快收斂。
![](https://i.imgur.com/My4tso6.png)