github contributed by <Diana Ho
>
d0651
sys
以 make PROFILE=1
重新編譯程式碼
以 gprof 指出效能瓶頸,改寫檔案 math-toolkit.h
在內的函式實做
Ubuntu 14.04 LTS
$ sudo apt-get install graphviz
畫示意圖$ sudo apt-get install imagemagick
轉換格式$ gcc –pg test.c –o test
:$./test
:$ gprof -b a.out gmon.out | less
:$ tar zxvf cflow-1.1.tar.gz
$./configure
$ make CFLAGS=-pg LDFLAGS=-pg
產生 cflow,但是沒有 –pg編譯時make PROFILE=1
產生raytracing執行檔
讓程式重新編譯並加上參數-pg
編譯器在每一個 function 加上 mcount
執行時執行 ./raytracing
讓 gprof 啟動並分析數據,執行產生 gmon.out
$ gprof -b raytracing gmon.out | less
得到 raytracing 中各函數的詳細資訊,執行並紀錄,所以跑起來會比原程式慢的許多
與perf top比較:
每隔一段 period 會去做採樣(Sample),最後統計出大概的數據
$ ./raytracing
# Rendering scene
Done!
Execution time of raytracing() : 2.923739 sec
$ make check
# Rendering scene
Done!
Execution time of raytracing() : 3.038861 sec
Verified OK
$ make PROFILE=1
之前必須 $ make clean
$ make PROFILE=1
cc -std=gnu99 -Wall -O0 -g -c -o objects.o objects.c
cc -std=gnu99 -Wall -O0 -g -c -o raytracing.o raytracing.c
cc -std=gnu99 -Wall -O0 -g -c -o main.o main.c
cc -o raytracing objects.o raytracing.o main.o -lm
$ ./raytracing
# Rendering scene
Done!
Execution time of raytracing() : 5.704226 sec
clike= $ gprof raytracing gmon.out
shows how much time was spent executing directly in each function
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls s/call s/call name
27.35 0.88 0.88 69646433 0.00 0.00 dot_product
17.09 1.43 0.55 56956357 0.00 0.00 subtract_vector
9.94 1.75 0.32 31410180 0.00 0.00 multiply_vector
9.01 2.04 0.29 10598450 0.00 0.00 normalize
8.70 2.32 0.28 13861875 0.00 0.00 rayRectangularIntersection
7.15 2.55 0.23 17836094 0.00 0.00 add_vector
4.04 2.68 0.13 17821809 0.00 0.00 cross_product
3.26 2.79 0.11 13861875 0.00 0.00 raySphereIntersection
2.80 2.88 0.09 4620625 0.00 0.00 ray_hit_object
2.49 2.96 0.08 1048576 0.00 0.00 ray_color
1.55 3.01 0.05 1048576 0.00 0.00 rayConstruction
1.24 3.05 0.04 1 0.04 3.22 raytracing
0.93 3.08 0.03 4221152 0.00 0.00 multiply_vectors
0.93 3.11 0.03 2110576 0.00 0.00 compute_specular_diffuse
0.78 3.13 0.03 2110576 0.00 0.00 localColor
0.62 3.15 0.02 2520791 0.00 0.00 idx_stack_top
0.62 3.17 0.02 1241598 0.00 0.00 refraction
0.62 3.19 0.02 1204003 0.00 0.00 idx_stack_push
0.31 3.20 0.01 3838091 0.00 0.00 length
0.31 3.21 0.01 2558386 0.00 0.00 idx_stack_empty
0.31 3.22 0.01 1241598 0.00 0.00 reflection
執行時間較多的 function,在 math-toolkit.h 裡,以他們為目標優先優化
shows which functions called which others, and how much time each function used when its subroutine calls are included
Call graph
granularity: each sample hit covers 2 byte(s) for 0.31% of 3.22 seconds
index % time self children called name
0.04 3.18 1/1 main [2]
[1] 100.0 0.04 3.18 1 raytracing [1]
0.08 2.94 1048576/1048576 ray_color [3]
0.05 0.11 1048576/1048576 rayConstruction [14]
0.00 0.00 1/1 calculateBasisVectors [25]
0.00 0.00 1048576/1048576 idx_stack_init [27]
-----------------------------------------------
<spontaneous>
[2] 100.0 0.00 3.22 main [2]
0.04 3.18 1/1 raytracing [1]
0.00 0.00 3/3 append_sphere [29]
0.00 0.00 3/3 append_rectangular [28]
0.00 0.00 2/2 append_light [30]
0.00 0.00 1/1 write_to_ppm [35]
0.00 0.00 1/1 delete_rectangular_list [32]
0.00 0.00 1/1 delete_sphere_list [33]
0.00 0.00 1/1 delete_light_list [31]
0.00 0.00 1/1 diff_in_second [34]
-----------------------------------------------
dot_product()
、subtract_vector()
、multiply_vector()
等進行效能的改善。$ make
來產生 raytracting 執行檔的時間久。使用 loop unrolling 將 for 迴圈中的表示式直接展開時,我們可以省下 counter 計算時間 和 branch predict 的 fail 的時間
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;
}
$ ./raytracing
# Rendering scene
Done!
Execution time of raytracing() : 4.397736 sec
$ gprof -b raytracing gmon.out | head -n 20
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls s/call s/call name
28.00 0.68 0.68 69646433 0.00 0.00 dot_product
10.29 0.93 0.25 56956357 0.00 0.00 subtract_vector
9.06 1.15 0.22 13861875 0.00 0.00 raySphereIntersection
9.06 1.37 0.22 13861875 0.00 0.00 rayRectangularIntersection
8.24 1.57 0.20 10598450 0.00 0.00 normalize
7.00 1.74 0.17 17836094 0.00 0.00 add_vector
6.59 1.90 0.16 17821809 0.00 0.00 cross_product
6.59 2.06 0.16 31410180 0.00 0.00 multiply_vector
3.71 2.15 0.09 4620625 0.00 0.00 ray_hit_object
2.26 2.21 0.06 1048576 0.00 0.00 ray_color
1.65 2.25 0.04 4221152 0.00 0.00 multiply_vectors
1.65 2.29 0.04 2110576 0.00 0.00 compute_specular_diffuse
1.24 2.32 0.03 2110576 0.00 0.00 localColor
0.82 2.34 0.02 1241598 0.00 0.00 protect_color_overflow
0.82 2.36 0.02 1241598 0.00 0.00 refraction
因爲在 Makefile 中擁有 -O0 的指令(關閉最佳化),所以 inline 不會被執行
inline 在編譯器中不一定會展開,因此修改函式就可以強制展開:static inline __attribute__((always_inline))
static
:對 definition 有效,限制 function 或 global variable 只會在所在檔案中被 accesslnline
:告訴編譯器將 function 直接展開成 definition 的程式,可透過加上 __attribute__((always_line))
強制 gcc 在最佳化沒有開啟時 inline。Inline function觀念
內嵌函數(inline function)筆記
Inline function in C
Inline function、Marco
Macro 是在 Compiler 進行編譯之前就被替換,而 Inline 是會被 Compiler 看到的,且在展開時系統會自動做安全檢查或型態的轉換
Macro巨集
跟 Inline 有點像,都是對該段代碼進行直接替換
用法: 在 math-toolkit.h 中直接使用
$ ./raytracing
# Rendering scene
Done!
Execution time of raytracing() : 2.473517 sec
OpenMP(Open Multi-Processing)是一套支持跨平台、共享記憶體方式的多執行緒平行運算的API
#include <omp.h>
#pragma omp parallel for
-fopenmp
#pragma omp parallel for schedule(guided,1) collapse(2) num_threads(64) private(stk), private(d),private(object_color)
$ ./raytracing
可以執行)
$ ./raytracing
# Rendering scene
Done!
Execution time of raytracing() : 0.025289 sec
$ ./raytracing
# Rendering scene
程式記憶體區段錯誤 (core dumped)
$ make check
# Rendering scene
Done!
Execution time of raytracing() : 0.019904 sec
二元碼檔 baseline.ppm 與 out.ppm 不同
Fail
Verified OK
$ ./raytracing
# Rendering scene
Done!
Execution time of raytracing() : 1.039256 sec
$ make check
# Rendering scene
Done!
Execution time of raytracing() : 1.044793 sec
Verified OK
POSIX線程(pthread)入門
POSIX Threads Programming
Introduction to Parallel progamming
多核心程式的好處:
PThread:
PThread 定義了一套 C 語言的型態定義、函數和常數。Pthread API 中有 100 個函式呼叫,全都以 pthread\_
開頭,並可以分為 4 類
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
產生一個 Thread 並執行附帶的 Function
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
暫停目前執行 pthread_join 的 Thread,等到目標 Thread 執行完畢之後目前執行 pthread_join 的 Thread 才會繼續執行