contributed by < refleex
>
要趕快追進度囉
課程助教
作業系統 : ubuntu 16.04 LTS (64-bit)
Architecture: x86_64
CPU 作業模式: 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 4
On-line CPU(s) list: 0-3
每核心執行緒數:2
每通訊端核心數:2
Socket(s): 1
NUMA 節點: 1
供應商識別號: GenuineIntel
CPU 家族: 6
型號: 60
Model name: Intel® Core™ i5-4210M CPU @ 2.60GHz
製程: 3
CPU MHz: 1694.671
CPU max MHz: 3200.0000
CPU min MHz: 800.0000
BogoMIPS: 5187.92
虛擬: VT-x
L1d 快取: 32K
L1i 快取: 32K
L2 快取: 256K
L3 快取: 3072K
NUMA node0 CPU(s): 0-3
可善用 POSIX Thread, OpenMP, software pipelining, 以及 loop unrolling 一類的技巧來加速程式運作
先去了解何謂平行化,並學習一些基本平行化的方式,例如 openMP,還有 pthread 的語法,並熟悉使用
先執行最初版本$ make
$ ./raytracing
# Rendering scene
Done!
Execution time of raytracing() : 2.666284 sec
接著為了能讓 gprof 偵測效能
$ make clean
$ make PROFILE=1
$ ./raytracing
# Rendering scene
Done!
Execution time of raytracing() : 5.567427 sec
用 gprof 來檢測效能 $ gprof -b raytracing gmon.out | less
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls s/call s/call name
26.46 0.55 0.55 56956357 0.00 0.00 subtract_vector
19.24 0.95 0.40 69646433 0.00 0.00 dot_product
9.86 1.16 0.21 13861875 0.00 0.00 rayRectangularIntersection
8.90 1.34 0.19 31410180 0.00 0.00 multiply_vector
6.73 1.48 0.14 17836094 0.00 0.00 add_vector
6.49 1.62 0.14 13861875 0.00 0.00 raySphereIntersection
4.81 1.72 0.10 10598450 0.00 0.00 normalize
4.33 1.81 0.09 4620625 0.00 0.00 ray_hit_object
3.37 1.88 0.07 17821809 0.00 0.00 cross_product
2.41 1.93 0.05 2110576 0.00 0.00 compute_specular_diffuse
1.92 1.97 0.04 1 0.04 2.08 raytracing
1.44 2.00 0.03 1048576 0.00 0.00 ray_color
0.96 2.02 0.02 2110576 0.00 0.00 localColor
0.96 2.04 0.02 1048576 0.00 0.00 rayConstruction
0.72 2.05 0.02 4221152 0.00 0.00 multiply_vectors
0.48 2.06 0.01 3838091 0.00 0.00 length
0.48 2.07 0.01 1204003 0.00 0.00 idx_stack_push
0.48 2.08 0.01 113297 0.00 0.00 fresnel
可以發現 subtract_vector()和 dot_product 被呼叫最多次
分別花費了 0.55 秒 和 0.4 秒
關於 inline 了解 inline 是作為"建議"編譯器將 inline 函式直接插入執行檔編譯,避免過多的函數呼叫,但編譯器不一定會採納
因此用 __attribute__((always_inline))
來強制將函式 inline
執行結果
# Rendering scene
Done!
Execution time of raytracing() : 2.478609 sec
先使用 openMP
要使用openmp前 須在編譯時加入 -fopenmp 這個 library
因此要更改 Makefile
CFLAGS = \
-std=gnu99 -Wall -O0 -g -fopenmp
LDFLAGS = \
-lm -fopenmp
在 subtract_vector()中加上 #pragma omp parallel for
void subtract_vector(const double *a, const double *b, double *out)
{
#pragma omp parallel for
for (int i = 0; i < 3; i++)
out[i] = a[i] - b[i];
}
再讓程式跑一次$ ./raytracing
# Rendering scene
Done!
Execution time of raytracing() : 5.449012 sec
好像沒快多少,檢查 gprof
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls s/call s/call name
22.99 0.54 0.54 69646433 0.00 0.00 dot_product
16.61 0.93 0.39 56956357 0.00 0.00 subtract_vector
13.20 1.24 0.31 17836094 0.00 0.00 add_vector
9.79 1.47 0.23 31410180 0.00 0.00 multiply_vector
9.58 1.70 0.23 13861875 0.00 0.00 rayRectangularIntersection
6.39 1.85 0.15 10598450 0.00 0.00 normalize
4.26 1.95 0.10 17821809 0.00 0.00 cross_product
3.83 2.04 0.09 4620625 0.00 0.00 ray_hit_object
3.19 2.11 0.08 13861875 0.00 0.00 raySphereIntersection
2.55 2.17 0.06 4221152 0.00 0.00 multiply_vectors
2.55 2.23 0.06 1048576 0.00 0.00 ray_color
1.70 2.27 0.04 1 0.04 2.35 raytracing
1.28 2.30 0.03 2110576 0.00 0.00 localColor
0.43 2.31 0.01 2520791 0.00 0.00 idx_stack_top
0.43 2.32 0.01 2110576 0.00 0.00 compute_specular_diffuse
0.43 2.33 0.01 1241598 0.00 0.00 reflection
0.43 2.34 0.01 1048576 0.00 0.00 idx_stack_init
0.43 2.35 0.01 37595 0.00 0.00 idx_stack_pop
subtract_vector()花費時間明顯降低,降至 0.39 秒
可是 dot_product() 時間卻增加了
若不使用 gprof ,原始執行時間
# Rendering scene
Done!
Execution time of raytracing() : 2.723372 sec
將 raytracing.c 中的 raytracing 函式的 for 迴圈平行化
# Rendering scene
Done!
Execution time of raytracing() : 1.393815 sec
明顯加速許多
可是看一下圖卻是錯的
更改了一下 openmp 的寫法,將一些參數 private 起來避
#pragma omp parallel for private(object_color,stk,d)
再跑一次圖就正確了
# Rendering scene
Done!
Execution time of raytracing() : 1.305993 sec