2017q1 Homework1 (compute-pi)
===
contributed by <`vtim9907`>
### Reviewed by <`rayleigh0407`>
* 為了平滑化而引用信賴區間這點還不錯 , 但是直接說==95% 的信賴區間落在 ±1.96 個標準差內==有點危險 , 這個結果是建立在資料分佈為 ==常態分佈== 的情況下 , 可參考 [wiki Normal distribution](https://en.wikipedia.org/wiki/Normal_distribution#Cumulative_distribution_function) 或是 [wiki Confidence interval](https://en.wikipedia.org/wiki/Confidence_interval)
# 開發環境
- OS : Ubuntu 16.04.2 LTS
- Kernel Version : 4.8.0-36-generic
- Memory : 32 GB
- CPU : Intel® Core™ i5-6600 Processor
- cache :
- L1i cache : 4*32 KB
- L1d cache : 4*32 KB
- L2 cache : 4*256 KB
- L3 cache : 6144 KB
- L1 cache imformation ( sudo dmidecode -t cache ) :
```
Handle 0x001E, DMI type 7, 19 bytes
Cache Information
Socket Designation: L1 Cache
Configuration: Enabled, Not Socketed, Level 1
Operational Mode: Write Back
Location: Internal
Installed Size: 256 kB
Maximum Size: 256 kB
Supported SRAM Types:
Synchronous
Installed SRAM Type: Synchronous
Speed: Unknown
Error Correction Type: Parity
System Type: Unified
Associativity: 8-way Set-associative
```
# 基本實驗
## 25 rounds, N <= 21000
將原實驗結果視覺化呈現,先用 LibreOffice 畫看看 (25 round):
![](https://i.imgur.com/4NzH00P.png)
線實在有點粗,圖片也有點小,可能我還不太會用@@" 改用 Gnuplot 畫:
![](https://i.imgur.com/JsPmkuY.png)
## 10000 rounds, N <= 50000
覺得取樣的間隔有點太大,決定改成 N 增加 1000 就取樣一遍,並將 N 放大到 50000,一次跑 10000 rounds :
![](https://i.imgur.com/Gd1MnbM.png)
從這張圖就很明顯可以看出,除了 4 threads 的方法以外,其他方法的波動都比較小,穩定遞增,但是使用了 4 threads 的 OpenMP 卻不斷的震盪,奇怪的是這張圖的前半段,就是 N 還小於兩萬左右時,結果與上面的測試不太相符...,我覺得這應該是因為 10000 rounds 中,有幾 round 因為一些不確定因素的關係,時間花的比較久,所以拉高了整體所花的時間。
## 95% 信賴區間
為了解決上面測不太準的問題,我用取信賴區間的方式,取 95% 信賴區間內的數據當參考,以外的就忽略掉,這樣就可以避免某幾 round 沒跑好,導致整體數據的錯誤。
首先可以簡單從高中課本或是 [wiki](https://zh.wikipedia.org/wiki/%E6%A8%99%E6%BA%96%E5%B7%AE) 查到母體標準差的定義 :
![](https://i.imgur.com/wJC1U7y.png)
簡單化簡一下 :
![](https://i.imgur.com/y1ksymU.png)
而根據查 [Z 值的表](http://mail.tut.edu.tw/~th0046/resource/z%20value.pdf)可以知道,95% 的信賴區間落在 +-1.96 個標準差內,所以可以知道,直接從母體算出 95% 信賴區間的上下界公式為:
- 上界 : $\mu + 1.96 * \sigma$
- 下界 : $\mu - 1.96 * \sigma$
實做取信賴區間,我直接加了一個 function 進 `benchmark_clock_gettime.c`:
```clike=
double calc_ci (double sample_time[])
{
int j, count = 0;
double average = 0.0, total_time = 0.0, sigma, upper, lower, conf_interval = 0.0;
for (j = 0; j < SAMPLE_NUM; ++j) {
average += sample_time[j];
total_time += sample_time[j] * sample_time[j];
}
average /= SAMPLE_NUM;
sigma = sqrt(total_time / SAMPLE_NUM - average * average);
upper = average + 1.96 * sigma;
lower = average - 1.96 * sigma;
for (j = 0; j < SAMPLE_NUM; ++j) {
if (sample_time[j] > lower && sample_time[j] < upper) {
conf_interval += sample_time[j];
count++;
}
}
return conf_interval /= count;
}
```
為了不讓程式跑太久,我改成一次跑 500 rounds,全部跑 1000 次,從這 1000 次取 95% 信賴區間內的數據當參考,最後畫成圖:
![](https://i.imgur.com/Gx7a6dL.png)
> 這張圖我總共跑了五次,因為第一次跑還是有些微的波動,我怕是因為背景程式或是網頁的干擾,所以關掉了一些東西後重跑了四次,結果數據都很平滑,可見在測試效能時,還是要盡量排除不必要的不確定因素。
很明顯,這次的分析圖就相當平滑,也能看出當 N 越大時,`OpenMP with 4 threads` 還是比 `AVX SIMD + Loop unrolling` 快一點,是目前最快的優化版本。
## 計算誤差
參考了 [廖健富學長的筆記](https://hackpad.com/Hw1-Extcompute_pi-geXUeYjdv1I),而選擇使用 $Arccos(-1)$ 逆推出來的 $\pi$ 當作基準,來推算用上面幾個方法所算出來的 $\pi$ 的誤差。
簡單寫了 function 來產生 .csv 檔,然後用 Gnuplot 畫出來:
![](https://i.imgur.com/fOUMH9d.png)
由於一開始的誤差很大,所以畫成圖後,前半部會成垂直狀,很難看。
不過因為誤差會極度減小的範圍只有 N 還很小的時候,所以只要把 N 的起始值調高,數據應該就比較漂亮:
![](https://i.imgur.com/KuvrUC1.png)
結果我想錯了 @@" 其實誤差值是持續穩定下降,所以區間只要選的太大,出來的圖形就會趨近直角,所以只好把區間縮小一點在畫出來;不過大略可以看出,若 $N$ 趨近 $10^n$ ,算出來 $\pi$ 的精確度就大約有 n 位。
# Leibniz formula for π
## 簡單證明
首先我們知道
- $\frac{ d [ arctan(x)]}{dx} =\frac{ 1 }{1 + x^2}$ ------(1)
又知 $\frac{ 1 }{1 + x^2}$ 可以 power series 展開為
- $1 - x^2 + x^4 ...$
所以對等式 (1) 兩邊積分得到 :
- $arctan(x) = \int_{0}^x\frac{ 1 }{1 + x^2} = \int_{0}^x 1 - x^2 + x^4 ...$ ------(2)
然後因為 $arctan(1) = \frac{\pi}{4}$ ,帶進 (2) 得到
- $arctan(1) = \frac{\pi}{4} = \int_{0}^{1} 1 - x^2 + x^4... = 1 - \frac{1}{3} + \frac{1}{5} - \frac{1}{7} ...$
## 實做
根據前面證明結果
![](https://i.imgur.com/QQ25w8G.png)
可以簡化為:
![](https://i.imgur.com/a9naORQ.png)
有了上面的式子就很好實做。
實做方面我直接選擇用 OpenMP 使用 4 threads 去跑,然後同樣一次跑 500 rounds ,共跑 1000 次,然後取 95% 信賴區間內的結果當參考,用 Gnuplot 畫成圖:
![](https://i.imgur.com/BgbzRaf.png)
新的公式比之前的版本快滿多的,幾乎是 Baseline 的三倍速。
計算 Leibniz formula for π 的誤差,與前一版的誤差一起畫成圖形做比較:
![](https://i.imgur.com/S03BzFc.png)
看出其實兩者的精度差不多,只是分別從 $\pi$ 的上下逼近 $\pi$。
# Reference
- [z value](http://mail.tut.edu.tw/~th0046/resource/z%20value.pdf)
- [標準差](https://zh.wikipedia.org/wiki/%E6%A8%99%E6%BA%96%E5%B7%AE)
- [廖健富學長的筆記](https://hackpad.com/Hw1-Extcompute_pi-geXUeYjdv1I)
- [Leibniz formula for π ---proof](https://zh.wikipedia.org/wiki/%CE%A0%E7%9A%84%E8%8E%B1%E5%B8%83%E5%B0%BC%E8%8C%A8%E5%85%AC%E5%BC%8F)