# 2017q1 Homework1(raytracing)
contributed by<`yanang`>
###### tags: `yanang`
>進度落後請加緊腳步!
>[name=課程助教][color=red]
### Reviewed by stanleytazi
+ 可以 Loop unrolling 記得還有其他的 math toolkit,可以對那些做更改再做比較
+ 這邊捨去 double dp 的目的是什麼呢? 不捨去的效能會比較差嗎?
+ 看不太懂 Pthread 那邊由 malloc 改成 array 宣告的差別
+ git commit 可以再多加一些描述來符合 "**Use the body to explain what and why vs. how**"
## 初步測試
* $ ./raytracing
```
# Rendering scene
Done!
Execution time of raytracing() : 2.817711 sec
```
* $ convert out.ppm out.png

* $ make clean 後重新 $ make PROFILE=1
```
# Rendering scene
Done!
Execution time of raytracing() : 5.906013 sec
```
* $ grof ./raytracing | less
```
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls s/call s/call name
24.71 0.60 0.60 56956357 0.00 0.00 subtract_vector
21.00 1.11 0.51 69646433 0.00 0.00 dot_product
9.47 1.34 0.23 31410180 0.00 0.00 multiply_vector
8.24 1.54 0.20 17836094 0.00 0.00 add_vector
7.41 1.72 0.18 13861875 0.00 0.00 rayRectangularIntersection
5.76 1.86 0.14 13861875 0.00 0.00 raySphereIntersection
4.94 1.98 0.12 10598450 0.00 0.00 normalize
```
## loop unrolling
* 針對 dot_product() 將 loop 展開,同時捨去 double dp 。
```c=
double dot_product(const double *v1, const double *v2)
{
return (v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]);
}
```
* $ ./rayracing
```
# Rendering scene
Done!
Execution time of raytracing() : 2.384672 sec sec
```
## POSIX Thread
* 參閱了 [去年的共筆](https://embedded2016.hackpad.com/ep/pad/static/f5CCUGMQ4Kp) 當中 POSIX Thread 這段,將 raytracing() 做 thread 以達到將一張圖切分成數份去做繪製。
* 稍微有點忘記 pthread 的用法,跟 data 的傳輸。
參考 [POSIX執行緒](https://zh.wikipedia.org/wiki/POSIX%E7%BA%BF%E7%A8%8B) 和 [pthread_data](http://stackoverflow.com/questions/1352749/multiple-arguments-to-function-called-by-pthread-create)
```c=
typedef struct __PARAMETER{
uint8_t *pixels;
rectangular_node rectangulars;
sphere_node spheres;
light_node lights;
const viewpoint *view;
int width_start;
int width;
int height_start;
int height;
} para;
```
* 因為 pthread 資料庫不是 Linux 系統默認的資料庫,連接時需要使用靜態庫 libpthread.a
```c=
CC ?= gcc
CFLAGS = \
-std=gnu99 -Wall -O0 -g
LDFLAGS = \
-lm -lpthread
```
* 一開始只使用一個 struct para *ptr 去處理所有資料,忘了 pointer 特性,所以畫出來的圖總是缺角,原先一直以為某一小段寫錯了,最後才想起。
```c=
para *ptr = malloc(sizeof(para));
ptr->pixels = pixels;
ptr->rectangulars = rectangulars;
...
pthread_create(&pid0, NULL, raytracing, (void *)ptr);
```

* 後改用宣告為矩陣
```c=
para ptr[4];
ptr[0].pixels = pixels;
ptr[0].rectangulars = rectangulars;
...
pthread_create(&pid0, NULL, raytracing, (void *)&ptr[0]);
```
* raytracing() 運算當中的 width 和 height 指的是邊界(512),而非輸入的最大 width 和 height ,未修改結果

* 修改後測試 (回復正常的圖)

* $ ./rayracing
```
# Rendering scene
Done!
Execution time of raytracing() : 0.963422 sec
```
* 總比較圖:

## -O0 -Ofast
* 記得在 [作業解說](https://www.youtube.com/watch?v=m1RmfOfSwno) 裡有提到,若要得到最佳效能能使用 -Ofast ,所以想說再新增 thread 後再使用一次。
* 完全未修改的程式碼使用 -Ofast
```
# Rendering scene
Done!
Execution time of raytracing() : 0.806448 sec
```
* 增加 loop unrolling 後使用 -Ofast
```
# Rendering scene
Done!
Execution time of raytracing() : 0.654491 sec
```
* 增加 thread 後使用 -Ofast
```
# Rendering scene
Done!
Execution time of raytracing() : 0.272825 sec
```