# 2016q3 Homework2 (raytracing)
contributed by <`aweimeow`>
###### tags: `sysprog21` `aweimeow`
### 作業環境
* OS: Ubuntu 14.04.4 LTS
* CPU: Intel(R) Core(TM) i5-4210M CPU @ 2.60GHz
* Memory: 8G
* Cache:
* L1d cache: 32KB
* L1i cache: 32KB
* L2 cache: 256KB
* L3 cache: 3072KB
### 前置準備
```
$ sudo apt-get update
$ sudo apt-get install graphviz
$ sudo apt-get install imagemagick
```
### 未修改的版本
```
# Rendering scene
Done!
Execution time of raytracing() : 2.909354 sec
```
附上輸出的圖:

### 找到可以著手修改增進速度的地方
先加上 `PROFILE=1`
```
# Rendering scene
Done!
Execution time of raytracing() : 5.193626 sec
```
只取前面幾個來看:
```
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls s/call s/call name
28.59 0.90 0.90 69646433 0.00 0.00 dot_product
14.29 1.35 0.45 56956357 0.00 0.00 subtract_vector
9.05 1.64 0.29 31410180 0.00 0.00 multiply_vector
8.89 1.92 0.28 13861875 0.00 0.00 rayRectangularIntersection
6.67 2.13 0.21 13861875 0.00 0.00 raySphereIntersection
6.67 2.34 0.21 10598450 0.00 0.00 normalize
6.35 2.54 0.20 17836094 0.00 0.00 add_vector
4.76 2.69 0.15 4620625 0.00 0.00 ray_hit_object
3.34 2.79 0.11 17821809 0.00 0.00 cross_product
2.86 2.88 0.09 1048576 0.00 0.00 ray_color
2.54 2.96 0.08 2110576 0.00 0.00 compute_specular_diffuse
1.27 3.00 0.04 4221152 0.00 0.00 multiply_vectors
1.27 3.04 0.04 1048576 0.00 0.00 rayConstruction
1.27 3.08 0.04 1 0.04 3.15 raytracing
0.64 3.10 0.02 2110576 0.00 0.00 localColor
0.32 3.11 0.01 3838091 0.00 0.00 length
```
也使用第一個作業學到的 `perf` 來觀察:
```
Performance counter stats for './raytracing' (5 runs):
954,195 cache-misses # 49.638 % of all cache refs
2,062,377 cache-references
33,500,782,366 instructions # 2.04 insns per cycle
16,585,243,176 cycles
5.220092593 seconds time elapsed ( +- 0.23% )
```
### 著手修改程式碼
#### dot_product
Loop unrolling,把程式碼當中的迴圈展開,加速程式的執行速度
```c
static inline
double dot_product(const double *v1, const double *v2)
{
double dp = 0.0;
dp += v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]
return dp;
}
```
結果:
```
# Rendering scene
Done!
Execution time of raytracing() : 4.807088 sec
```
與上一次相比,`5.193626` - `4.807088` = `0.386538 秒`,這個是論結果來看,我們很明確的發現速度提昇了,
那麼 gprof 呢?把兩次放在一起比較,秒速下降了約 .39 秒,代表這樣子是真的能加速的
```
time seconds seconds calls s/call s/call name
28.59 0.90 0.90 69646433 0.00 0.00 dot_product
17.72 1.09 0.51 69646433 0.00 0.00 dot_product
```
#### subtract_vector
一樣是以 loop unrolling 來修改:
```
# Rendering scene
Done!
Execution time of raytracing() : 4.579059 sec
```
gprof 之後也能夠發現執行的秒速從 0.45 下降到 0.33 秒
```
time seconds seconds calls s/call s/call name
14.29 1.35 0.45 56956357 0.00 0.00 subtract_vector
12.41 1.10 0.33 56956357 0.00 0.00 subtract_vector
```
#### 省略一堆的 Loop Unrolling,總結全部展開的結果
```
% cumulative self self total
time seconds seconds calls s/call s/call name
21.70 0.49 0.49 69646433 0.00 0.00 dot_product
13.73 0.80 0.31 13861875 0.00 0.00 rayRectangularIntersection
11.51 1.06 0.26 13861875 0.00 0.00 raySphereIntersection
9.74 1.28 0.22 10598450 0.00 0.00 normalize
8.41 1.47 0.19 56956357 0.00 0.00 subtract_vector
7.08 1.63 0.16 31410180 0.00 0.00 multiply_vector
6.64 1.78 0.15 17821809 0.00 0.00 cross_product
4.43 1.88 0.10 17836094 0.00 0.00 add_vector
```
#### OpenMP
在這邊參考[其他同學](https://hackmd.io/s/r1vckLB6#%E5%AF%A6%E5%81%9Apthread-%E8%B7%9F-openmp)的作法,以及[此篇](https://computing.llnl.gov/tutorials/openMP/samples/C/omp_hello.c)的說明,對於怎麼寫有一些大概的概念。
首先要先思考哪些變數在各個 Thread 是必須獨立的:
* idx_stack stk: 看起來是要存放東西的 Stack,每個 Thread 應該都要有自己的
* d: 這個參數有傳入 `rayConstruction`, `ray_color`,所以應該不是固定的值
* object_color:
先 import
```c
#import <omp.h>
```
然後在 for 迴圈前面宣告
```c
#pragma omp parallel for num_threads(THREAD_NUM) private(stk, d, object_color)
```
並且修改 MakeFile:
```makefile
CFLAGS = \
-std=gnu99 -Wall -O0 -g -fopenmp
LDFLAGS = \
-lm -fopenmp
```
要記得加上 `fopenmp` 這個 Tag,[我參考的那位同學](https://hackmd.io/s/r1vckLB6#%E5%AF%A6%E5%81%9Apthread-%E8%B7%9F-openmp)寫的:
> 最後要記得 #include<omp.h> , 以及在編譯選項中加上 -fopenp
這邊有打錯字 :P
##### 然後再來是結果
在沒有 OpenMP 的加持時:
```
# Rendering scene
Done!
Execution time of raytracing() : 4.038518 sec
```
再來是有 OpenMP 的加持(Thread = 4):
```
# Rendering scene
Done!
Execution time of raytracing() : 8.254940 sec
```
:::info
咦,怎麼時間還增加了呢?不過我們有 gprof 可以用。
:::
發現執行時間原本從 1.95 下降到 1.92。
好像不是很理想,我不確定是不是因為 Thread 給太少了?
所以接下來試試看 16 個 Thread
```
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
16.31 0.15 0.15 988837 0.00 0.00 raySphereIntersection
11.96 0.26 0.11 4444684 0.00 0.00 dot_product
9.79 0.35 0.09 372860 0.00 0.00 ray_hit_object
9.24 0.44 0.09 3957736 0.00 0.00 subtract_vector
8.70 0.52 0.08 1062330 0.00 0.00 cross_product
8.70 0.60 0.08 912758 0.00 0.00 rayRectangularIntersection
7.61 0.67 0.07 673090 0.00 0.00 normalize
5.44 0.72 0.05 61496 0.00 0.01 ray_color
4.35 0.76 0.04 2129702 0.00 0.00 multiply_vector
4.35 0.80 0.04 1099567 0.00 0.00 add_vector
3.26 0.83 0.03 282499 0.00 0.00 length
2.18 0.85 0.02 69869 0.00 0.00 rayConstruction
2.18 0.87 0.02 1 20.01 920.55 raytracing
1.63 0.88 0.02 226005 0.00 0.00 multiply_vectors
1.09 0.89 0.01 159710 0.00 0.00 compute_specular_diffuse
1.09 0.90 0.01 155301 0.00 0.00 localColor
1.09 0.91 0.01 91039 0.00 0.00 refraction
1.09 0.92 0.01 89899 0.00 0.00 protect_color_overflow
0.00 0.92 0.00 188053 0.00 0.00 idx_stack_empty
0.00 0.92 0.00 153272 0.00 0.00 idx_stack_top
0.00 0.92 0.00 82018 0.00 0.00 reflection
0.00 0.92 0.00 80465 0.00 0.00 idx_stack_push
0.00 0.92 0.00 69209 0.00 0.00 idx_stack_init
0.00 0.92 0.00 9361 0.00 0.00 fresnel
0.00 0.92 0.00 3378 0.00 0.00 idx_stack_pop
0.00 0.92 0.00 3 0.00 0.00 append_rectangular
0.00 0.92 0.00 3 0.00 0.00 append_sphere
0.00 0.92 0.00 2 0.00 0.00 append_light
0.00 0.92 0.00 1 0.00 0.00 calculateBasisVectors
0.00 0.92 0.00 1 0.00 0.00 delete_light_list
0.00 0.92 0.00 1 0.00 0.00 delete_rectangular_list
0.00 0.92 0.00 1 0.00 0.00 delete_sphere_list
0.00 0.92 0.00 1 0.00 0.00 diff_in_second
0.00 0.92 0.00 1 0.00 0.00 write_to_ppm
```
可以看到在最後是 0.92 秒,時間確實下降了,接下來比較一下Thread的數量與執行時間的差異(以 4 為基底取次方作為數量):
| Thread Number | Execute Time (sec) |
|---------------|--------------------|
|No OpenMP |2.234710 |
|4 |1.203826 |
|16 |0.907454 |
|64 |0.960009 |
|256 |0.938343 |
|1024 |1.029779 |
|4096 |1.053434 |