Quexint
dot_product
可全部寫在同一行,應該會快不少。inline
或用 CPU 指令集加速。作業系統: Ubuntu 16.04 LTS (64 bit)
CPU:2-core Intel® Core™ i5-5257U CPU @ 2.70GHz
Memory:16G
Cache:
使用 lscpu
和 sudo lshw
可看到硬體資訊
$ git clone https://github.com/sysprog21/raytracing
$ cd raytracing
$ make
$ ./raytracing
結果
#Rendering scene
Done!
Execution time of raytracing() : 2.568730 sec
comment
execution time of raytracing 2.568730 sec 如何來? HankLo
打開-pg編譯,可以使程式生成gprof數據併分析。
$ make clean
$ make PROFILE=1
$ ./raytracing
結果時間從原本的2.568730s 提升到 5.65922s秒,因為將程式生成gprof數據要花費時間。
# Rendering scene
Done!
Execution time of raytracing() : 5.659222 sec
gprof分析數據,如何程式提升效能。
$gprof ./raytracing | less
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls s/call s/call name
26.16 0.57 0.57 69646433 0.00 0.00 dot_product
20.20 1.01 0.44 56956357 0.00 0.00 subtract_vector
10.33 1.24 0.23 31410180 0.00 0.00 multiply_vector
7.80 1.41 0.17 17836094 0.00 0.00 add_vector
6.88 1.56 0.15 10598450 0.00 0.00 normalize
6.43 1.70 0.14 13861875 0.00 0.00 rayRectangularIntersection
6.43 1.84 0.14 13861875 0.00 0.00 raySphereIntersection
5.51 1.96 0.12 17821809 0.00 0.00 cross_product
4.13 2.05 0.09 4620625 0.00 0.00 ray_hit_object
1.84 2.09 0.04 1048576 0.00 0.00 ray_color
1.38 2.12 0.03 2110576 0.00 0.00 compute_specular_diffuse
1.15 2.14 0.03 4221152 0.00 0.00 multiply_vectors
0.92 2.16 0.02 3838091 0.00 0.00 length
0.46 2.17 0.01 1241598 0.00 0.00 protect_color_overflow
0.46 2.18 0.01 1 0.01 2.18 raytracing
0.00 2.18 0.00 2558386 0.00 0.00 idx_stack_empty
前三項dot_product、subtract_vector、multiply_vector所花時間最劇,佔了總體時間46%。可能針對這三個數學式子作改善,提昇效能。
static inline
double dot_product(const double *v1, const double *v2)
{
double dp = 0.0;
for (int i = 0; i < 3; i++)
dp += v1[i] * v2[i];
return dp;
}
原始dot_product是用迴圈來計算dot_product,而使用迴圈會有branch的情況發生。這地方可以不需要用loop,可直接將其展開,減少程式執行序。
static inline
double dot_product(const double *v1, const double *v2)
{
double dp = 0.0;
dp += v1[0] * v2[0];
dp += v1[1] * v2[1];
dp += v1[2] * v2[2];
return dp;
}
結果,時間從5.659222降為5.285118,快了0.374秒。
# Rendering scene
Done!
Execution time of raytracing() : 5.285118 sec
使用gprof檢查。
$gprof ./raytracing | less
dot_product時間從0.57s降為0.10s。
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls s/call s/call name
31.97 0.54 0.54 56956357 0.00 0.00 subtract_vector
11.84 0.74 0.20 31410180 0.00 0.00 multiply_vector
10.66 0.92 0.18 13861875 0.00 0.00 rayRectangularIntersection
9.77 1.09 0.17 17836094 0.00 0.00 add_vector
6.51 1.20 0.11 4620625 0.00 0.00 ray_hit_object
5.92 1.30 0.10 69646433 0.00 0.00 dot_product
5.33 1.39 0.09 17821809 0.00 0.00 cross_product
3.55 1.45 0.06 13861875 0.00 0.00 raySphereIntersection
3.55 1.51 0.06 10598450 0.00 0.00 normalize
1.78 1.54 0.03 2110576 0.00 0.00 localColor
1.78 1.57 0.03 1048576 0.00 0.00 rayConstruction
1.78 1.60 0.03 1048576 0.00 0.00 ray_color
1.78 1.63 0.03 1 0.03 1.69 raytracing
1.48 1.65 0.03 3838091 0.00 0.00 length
subtract_vector跟dot_product用一樣的方法,建議將迴圈拿掉,減少branch發生,減少程序運算數目。
void subtract_vector(const double *a, const double *b, double *out)
{
for (int i = 0; i < 3; i++)
out[i] = a[i] - b[i];
}
改寫subtract_vector。
void subtract_vector(const double *a, const double *b, double *out)
{
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
}
結果,時間從5.285118s降為5.045020s,快了0.240秒。
# Rendering scene
Done!
Execution time of raytracing() : 5.045020 sec
使用gprof檢查。結果subtract_vector從0.54s降為0.14,但dot_product從0.10升到0.15
comment
dot秒數為合上升?嘗試將檔案清楚後在make PROFILE=1後得到的數據又不一樣。HankLo
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls s/call s/call name
15.16 0.20 0.20 17836094 0.00 0.00 add_vector
14.78 0.40 0.20 31410180 0.00 0.00 multiply_vector
11.37 0.55 0.15 69646433 0.00 0.00 dot_product
10.61 0.69 0.14 56956357 0.00 0.00 subtract_vector
9.85 0.82 0.13 13861875 0.00 0.00 rayRectangularIntersection
7.20 0.91 0.10 17821809 0.00 0.00 cross_product
6.82 1.00 0.09 4620625 0.00 0.00 ray_hit_object
4.55 1.06 0.06 1048576 0.00 0.00 ray_color
3.79 1.11 0.05 13861875 0.00 0.00 raySphereIntersection
3.79 1.16 0.05 10598450 0.00 0.00 normalize
3.03 1.20 0.04 4221152 0.00 0.00 multiply_vectors
3.03 1.24 0.04 2110576 0.00 0.00 compute_specular_diffuse
gprof可以量測程式執行時間,因為是量測,會有誤差是可接受的行為。gprof還是能幫助使用者找出改善效能的地方,這是它實用的地方。HankLo
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls s/call s/call name
15.37 0.22 0.22 31410180 0.00 0.00 multiply_vector
12.15 0.39 0.17 56956357 0.00 0.00 subtract_vector
11.08 0.54 0.16 13861875 0.00 0.00 rayRectangularIntersection
10.72 0.69 0.15 17836094 0.00 0.00 add_vector
8.93 0.82 0.13 69646433 0.00 0.00 dot_product
6.43 0.91 0.09 10598450 0.00 0.00 normalize
6.43 1.00 0.09 4620625 0.00 0.00 ray_hit_object
5.72 1.08 0.08 1048576 0.00 0.00 ray_color
5.72 1.16 0.08 17821809 0.00 0.00 cross_product
5.36 1.23 0.08 13861875 0.00 0.00 raySphereIntersection
2.86 1.27 0.04 4221152 0.00 0.00 multiply_vectors