contributed by <HaoTse
>
shelly4132
$ sudo apt-get update
$ sudo apt-get install graphviz
$ sudo apt-get install imagemagick
-pg
的參數,編譯器會在各函數中加入mcount函數$ gprof -b raytracing gmon.out | less
由於輸出訊息多,
$ less
使我們可以使用上下鍵看訊息。鄭皓澤
首先不開啟gprof,得到結果如下
# Rendering scene
Done!
Execution time of raytracing() : 3.338670 sec
接著使用$ make PROFILE=1
重新編譯
注意得先做
$ make clean
# Rendering scene
Done!
Execution time of raytracing() : 6.912961 sec
兩者對照可以看出gprof對速度的影響。
$ gprof -b raytracing gmon.out | less
% cumulative self self total
time seconds seconds calls s/call s/call name
21.79 0.54 0.54 69646433 0.00 0.00 dot_product
20.58 1.05 0.51 56956357 0.00 0.00 subtract_vector
12.91 1.37 0.32 31410180 0.00 0.00 multiply_vector
9.68 1.61 0.24 13861875 0.00 0.00 raySphereIntersection
8.47 1.82 0.21 13861875 0.00 0.00 rayRectangularIntersection
6.86 1.99 0.17 10598450 0.00 0.00 normalize
4.44 2.10 0.11 17836094 0.00 0.00 add_vector
4.03 2.20 0.10 17821809 0.00 0.00 cross_product
2.42 2.26 0.06 4620625 0.00 0.00 ray_hit_object
2.02 2.31 0.05 1048576 0.00 0.00 ray_color
1.61 2.35 0.04 4221152 0.00 0.00 multiply_vectors
1.21 2.38 0.03 2520791 0.00 0.00 idx_stack_top
1.01 2.41 0.03 1048576 0.00 0.00 rayConstruction
0.81 2.43 0.02 2110576 0.00 0.00 localColor
0.81 2.45 0.02 1241598 0.00 0.00 refraction
0.40 2.46 0.01 2110576 0.00 0.00 compute_specular_diffuse
0.40 2.47 0.01 1241598 0.00 0.00 reflection
0.40 2.48 0.01 1 0.01 0.01 delete_sphere_list
0.20 2.48 0.01 1 0.01 0.01 calculateBasisVectors
0.00 2.48 0.00 3838091 0.00 0.00 length
0.00 2.48 0.00 2558386 0.00 0.00 idx_stack_empty
0.00 2.48 0.00 1241598 0.00 0.00 protect_color_overflow
0.00 2.48 0.00 1204003 0.00 0.00 idx_stack_push
0.00 2.48 0.00 1048576 0.00 0.00 idx_stack_init
0.00 2.48 0.00 113297 0.00 0.00 fresnel
0.00 2.48 0.00 37595 0.00 0.00 idx_stack_pop
0.00 2.48 0.00 3 0.00 0.00 append_rectangular
0.00 2.48 0.00 3 0.00 0.00 append_sphere
0.00 2.48 0.00 2 0.00 0.00 append_light
0.00 2.48 0.00 1 0.00 0.00 delete_light_list
0.00 2.48 0.00 1 0.00 0.00 delete_rectangular_list
0.00 2.48 0.00 1 0.00 0.00 diff_in_second
0.00 2.48 0.00 1 0.00 2.47 raytracing
0.00 2.48 0.00 1 0.00 0.00 write_to_ppm
前三名dot_product、subtract_vector、multiply_vector都在math-toolkit.h這個檔案中,因此我們首先著手對它做優化。
開啟math-toolkit.h後,最明顯的部份就是static inline,可是這次我們要求不使用編譯器最佳化,因此使用__attribute__((always_inline))
強制開啟inline。
先將前面提到的3個最花時間的function加上force inline。
# Rendering scene
Done!
Execution time of raytracing() : 4.771009 sec
執行時間從 6.912961sec下降至 4.771009sec。
% cumulative self self total
time seconds seconds calls s/call s/call name
32.06 1.00 1.00 13861875 0.00 0.00 rayRectangularIntersection
22.77 1.71 0.71 13861875 0.00 0.00 raySphereIntersection
8.66 1.98 0.27 10598450 0.00 0.00 normalize
7.70 2.22 0.24 2110576 0.00 0.00 compute_specular_diffuse
6.41 2.42 0.20 17836094 0.00 0.00 add_vector
5.45 2.59 0.17 17821809 0.00 0.00 cross_product
3.85 2.71 0.12 4620625 0.00 0.00 ray_hit_object
3.53 2.82 0.11 2110576 0.00 0.00 localColor
2.89 2.91 0.09 1048576 0.00 0.00 ray_color
2.24 2.98 0.07 1048576 0.00 0.00 rayConstruction
1.28 3.02 0.04 1241598 0.00 0.00 reflection
0.96 3.05 0.03 4221152 0.00 0.00 multiply_vectors
0.96 3.08 0.03 1241598 0.00 0.00 refraction
0.64 3.10 0.02 3838091 0.00 0.00 length
0.32 3.11 0.01 1 0.01 0.01 delete_sphere_list
0.32 3.12 0.01 1 0.01 3.11 raytracing
前面最耗時的3個function也從前3名消失了。
將所有的inline funciotn作force inline後,花費時間明顯下降,結果如下
# Rendering scene
Done!
Execution time of raytracing() : 3.916428 sec
在math-toolkit.h中有許多function都有for loop,因此決定再套入loop unrolling方法降低速度。
修改後得到結果如下
# Rendering scene
Done!
Execution time of raytracing() : 2.934387 sec
執行時間從 3.916428sec降至 2.934387sec。
在raytracing.c的raytracing()中有一段程式碼如下
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
double r = 0, g = 0, b = 0;
/* MSAA */
for (int s = 0; s < SAMPLES; s++) {
idx_stack_init(&stk);
rayConstruction(d, u, v, w,
i * factor + s / factor,
j * factor + s % factor,
view,
width * factor, height * factor);
if (ray_color(view->vrp, 0.0, d, &stk, rectangulars, spheres,
lights, object_color,
MAX_REFLECTION_BOUNCES)) {
r += object_color[0];
g += object_color[1];
b += object_color[2];
} else {
r += background_color[0];
g += background_color[1];
b += background_color[2];
}
pixels[((i + (j * width)) * 3) + 0] = r * 255 / SAMPLES;
pixels[((i + (j * width)) * 3) + 1] = g * 255 / SAMPLES;
pixels[((i + (j * width)) * 3) + 2] = b * 255 / SAMPLES;
}
}
}
可以看出各個pixel可以獨立運算,因此想使用多執行緒的方式來試著改善程式效能,在同學的筆記中看到OpenMP這套工具,先嘗試使用看看。
CFLAGS = \
-std=gnu99 -Wall -O0 -g -fopenmp
LDFLAGS = \
-lm -lgomp
#pragma omp parallel for
# Rendering scene
Done!
Execution time of raytracing() : 2.306696 sec
原先為 2.934387sec,發現下降並不明顯。
#pragma omp parallel for num_threads(64)
將thread數量指定至64條。
不過$ make check
後發現結果fail,參考同學的筆記之後發現要改為
#pragma omp parallel for num_threads(64) \
private(stk) private(d) \
private(object_color)
因為變數 stk、d 以及 object_color 必須要透過 private clause 宣告為執行緒私有的,否則預設之下在 #pragma omp 前的變數都是 shared,會導致計算結果錯誤。成功輸出結果如下
# Rendering scene
Done!
Execution time of raytracing() : 1.606055 sec
時間下降更多了。
在-Ofast
且不開啟-pg
的情況下,結果如下
# Rendering scene
Done!
Execution time of raytracing() : 0.389374 sec
目標為超越電腦。
HaoTse
sysprog21
raytracing
gprof
OpenMP