2016q3 Homework2 (raytracing)
contributed by <LanKuDot
>
環境
- OS: Ubuntu 15.04 64bit
- CPU: Genuine Intel® CPU U7300 @ 1.30GHz × 2
- GPU: Mobile Intel® GM45 Express Chipset
- RAM: 4 GB
程式碼
Gprof
make PROFILE=1
:多加 -pg
flag,讓 compiler 安插額外程式碼輸出執行時期的資料讓 gprof
分析,執行完會產生 gmon.out
,以追蹤程式的執行行為 (動態分析)
gprof ./raytracing
: 讓 gprof 分析資料,gprof 會取用產生的資料檔。會列出呼叫次數、執行時間比、call graph 等資訊。配合 less
服用,用分頁顯示大量資料。
static inline
static
:對 definition 有效,限制 function 或 global variable 只會在所在檔案中被 access
lnline
:告訴編譯器將 function 直接展開成 definition 的程式,可透過加上 __attribute__((always_line))
強制 gcc 在最佳化沒有開啟時 inline。
核心
Function raytracing
- 傳入場景必要的物件:長方面 (牆)、球體、光源、背景色、攝影機位置及視角、攝影機畫面 (輸出圖片) 的長寬
- 先計算以攝影機平面為基準的 vector space 的 basis vector,將結果存在 vector
u
, v
, w
。
- function
calculateBasisVector
:
w
:攝影機面的 normal (vpn, view-plane normal)
u
:w x 攝影機面的 up vector (vup)
v
:w x u 找到最後一個 vector
SAMPLES
:為了反鋸齒 (MSAA,多重採樣反鋸齒法),設定成取樣四個 pixel 作為該 pixel 的顏色
- 從攝影機畫面的每個 pixel 射出光源
- function
rayConstruction
:建立光源出發點,會存在 d
。
- 設定 view plane 的大小為 [-0.0175:0.0175][-0.0175:0.0175] (座標);消失點的位置在 z = 0.05 的地方 (view plane space)
- 計算該 pixel 在 view plane space 上的座標
w
(z):座標為消失點 z 座標
u
(x):為 xMin + xUnit * i
v
(y):為 yMin + yUnit * j
- 將得到的座標轉換到 world space 上:
- 計算光源在旅行的過程中會變成什麼顏色
- 判定如果發出去的光沒有碰到任何東西,則加上背景顏色,如果有則加上旅行之後的顏色。(這裡的顏色 scale 為 [0.0:1.0])
- 將 4 個取樣點的顏色值做平均,map 到 [0:255],然後存到
pixel
中
輸出
- ppm:
P6 Width Height MaxColorValue ColorValue
ColorValue
:以 (row, column) 填值
優化
Baseline
- 執行時間:11.650552 sec
- 時間大多卡在
dot_product
跟 substract_vector
Loop Unrolling
- 由於 for loop 有 branch 的判斷,會減慢執行速度。而在
math_toolkit.h
中的 vector 運算最多為三維,可以輕鬆展開
- 執行時間:6.881327 sec (效能提昇 41%)
- 可以看到做 loop unrolling 之後的函式總執行時間下降很多
使用 pthread 做平行化處理
- 閱讀材料
- 我認為 pthread 可以用在
- 重複執行的動作,像是 for loop
- 可以分開的工作
- 如果沒有 critical section 會比較好處理,否則要注意共用資源的使用問題
- 觀察 raytracing 可以做平行化的地方
- 整張圖的運算切割:row 分, column 分或 block 分。缺點是老師在影片中講到的,每一個 pixel 的呼叫熱度不一樣,所以如果切出來熱度過於集中在某個 block,平行化的效果不高。
- 模糊化處理:每個 sample 做完運算後,再取平均。
- RGB:RGB 的計算結果是不互相干擾的,可以個別平行加。缺點
ray_color
計算完顏色一次輸出 RGB,如果每個 thread 只取其中一個值會太浪費。
整張圖運算切割
- 基本想法:以 row 為單位切割運算區間,將
raytracing
的核心迴圈移到 raytracing_thread
函式,在 raytracing
只負責 create thread。
- 因為
pthread_create
只允許 pass 一個參數,所以將所需資訊打包成一個資料結構
-
問題:運行時間雖然減少,但是輸出的圖總是少一塊

- 原因是因為 passing 的參數是 shared memory,而在我的資料結構中
fromHeight
,toHeight
會因為迴圈而改變,所以在 thread 取用之前,就可能被更改了
- 驗證
- 解法:如果是 thread 間有差異的資料,用 array 存並 pass 對應的 element 到 thread 中。稍微修改一些地方:
- 所以我必須要為每一個 thread 準備一份他所需要的資料,不過對於同樣的資料可以用 pointer 指向同一個地方。修改過後的資料結構
- 執行時間:
- 3.664291 sec (4 threads)
- 3.602248 sec (8 threads)
- 3.608806 sec (16 threads)
- 推測就是因為計算較多的地方都集中在某個區塊,所以執行時間無法再有更好的改善
- 透過
$ cat /proc/sys/kernel/threads-max
可以知道每一個 process 的最多 thread 數,我的是 30669