or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Syncing
xxxxxxxxxx
2017q1 Homework1 (raytracing)
contributed by <
Hong
>tags:
sysprog2017
raytracing
gprof
gnuplot
king1224
Reviewed by
Cayonliow
開發環境
未優化版本
預期目標
在不使用編譯器最佳化的情況下,藉由 gprof 的幫助找出程式耗時的部份,針對重點地方優化運算,以改善整體效能,期望能得到與編譯器最佳化等值的效果
優化版本 1 - 減少迴圈 branch 判斷
觀察 math-toolkit.h 中的 function,可以發現大部分只是簡短的一個 for-loop,而這些 loop 都只做三次,因此對這些 loop 做 loop-unrolling 也不會導致過大的程式內容。
原始版本
展開版本
少了一些迴圈的條件判斷,執行時間居然快了接近 1 秒,已經離目標邁進一步了!
優化版本 2 - inline function 與 #define 的比較
經過第一個版本的優化以後,以 gprof 協助看出程式中最耗能的部份,可以看到 dot_product 這個函式呼叫了將近七千萬次。
讓我們看一下 math-toolkit.h 中的函式,雖然在第一行有 static inline,但到底是否要放成 inline function 是由編譯器來決定的,這邊我們關閉了編譯器最佳化,因此所有 function都不會變成 inline function。
我們可以對這個函式加上 attribute,來強制一個函式為 inline。
將所有 math-toolkit.h 中的 inline function 都補上強制 inline 的程式碼,執行效率如下:
inline function 是在編譯時期把整個 function copy paste 到 function call 的地方,而巨集( #define )也可以達到一樣的效果,但這兩個方法真的是完全一樣的嗎?
在 math-toolkit.h 中有一些函式是只做基本運算的( 沒有 assign value ),如 dot_product 和 length,可以改成 #define 的寫法:
很神奇的是,#define 的方法比 inline function 還快了0.1秒,是什麼導致這0.1秒的差異?
巨集( #define A B) 是完全將程式碼中的 A 直接以 B 貼上覆蓋,inline 則是將 function 中的程式碼放到呼叫他的地方,但直接完全貼上會出現很恐怖的後果,像是 return 就不可能原封不動的貼上來,而 function 定義的變數名稱與 caller 傳入的參數名稱不一定完全相同,必定先做一些處理才能 inline,從 inline 與 #define 的不同 中可以看到,若是以下的程式碼,#define 會執行兩次 getValue(),而 inline function 只會執行一次:
不論是 inline 或是 #define,這裡又比前一個版本快了 2.4 秒,而已經對於原始版本優化了大約 62%。
優化版本 3 - OpenMP
在多核心的時代,若想要加快執行速度,可以將任務分散給各個處理器,而 OpenMP 這個函式庫可以幫助我們簡單的寫出平行運算的程式碼。
OpenMP 語法的樣子基本上都是以這個形式開頭:
這邊對於 raytracing.c 中的一個 for-loop 進行平行化:
其中 num_threads() 可以選擇要讓 OpenMP 創建幾個 threads,針對2的次方的數字測試後發現 16 個 threads 以上差異就不大了,我認為是因為一個 core 可以處理兩個 threads,多一些些 threads 可以讓各個 CPU 在排程上得到更大的使用率,但就算創建大量的 thread,多出來的還是得停在那邊等系統排程。
各個版本執行時間分析圖
想嘗試的事
觀察 math-toolkit.h 中的 normalize 發現 v[0], v[1], v[2] 的乘法除法皆為分別運算,想到先前學過的方法,位元運算會比乘法除法還快,因此我想是否能將 v[0], v[1], v[2] shift後相加成一個數,隨後只做一次乘法,再利用 shift & mask 取回各自的值。
參考資料
Hw1 作業區
raytracing 題目 與 video
程式碼
force inline