OpenMp作為單機多核心共享內存並行編程的開發工具,具有編碼簡潔等,容易上手等特點。
關於OpenMP的入門,博主飲水思源(見參考資料)有了深入淺出,循序漸進的分析。做並行開發,做性能分析是永遠逃避不開的話題,性能問題的研究一切基於系統的計時。本人參考飲水思源的代碼在雙核與四核機器的操作過程中,發現clock()針對並行運行時間計時不准的問題,運行結果顯示並行方式和串行的時間基本相近,使得並行方式在時間計數上並未有明顯優勢。本文就其運行時間統計做相關分析,通過改進的方式,對時間進行了判斷,首先在For循環中加入打印語句判斷是否多核執行;然后判斷系統確實是多核執行后,在For循環中加入等待函數sleep,運行程序並人工計時,這時的時間在雙核機器並行比串行要快近兩倍,四核機器並行時間比串行快近四倍。所以可知clock()不適合做並行程序的計時工具,需要找到相關的替代。
for (int i=0;i<10;i++) { std::cout<<"currend id: "<<omp_get_thread_num()<<std::endl; sleep(1); test(); }
1、For循環的串行
新建SFor.cpp文件,內容為
1 #include <iostream> 2 #include <time.h> 3 #include <stdio.h> 4 #include <omp.h> 5 void test() 6 { 7 int a = 0; 8 for (int i=0;i<100000000;i++) 9 a++; 10 } 11 int main() 12 { 13 struct timespec time1 = {0, 0}; 14 struct timespec time2 = {0, 0}; 15 clock_gettime(CLOCK_REALTIME, &time1); 16 std::cout<<"sec num: "<<time1.tv_sec<<"; nsec num: "<<time1.tv_nsec<<std::endl; 17 //clock_t t1 = clock(); 18 for (int i=0;i<10;i++) 19 { 20 //std::cout<<"currend id: "<<omp_get_thread_num()<<std::endl; 21 test(); 22 } 23 //clock_t t2 = clock(); 24 //std::cout<<"time: "<<t2-t1<<std::endl; 25 clock_gettime(CLOCK_REALTIME, &time2); 26 std::cout<<"sec num: "<<time2.tv_sec<<"; nsec num: "<<time2.tv_nsec<<std::endl; 27 std::cout<<"time: "<<(time2.tv_sec-time1.tv_sec)*1000+(time2.tv_nsec-time1.tv_nsec)/1000000<<"ms"<<std::endl; 28 }
CentOS6.5 的GCC版本默認4.4.7,原生支持OpenMP編譯
[root@localhost MPDemo]# gcc --version
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)
通過編譯命令編譯源文件為:
g++ -fopenmp SFor.cpp -o sfor.out
[root@localhost MPDemo]# g++ -fopenmp PFor.cpp -o pfor.out
[root@localhost MPDemo]# ./sfor.out
sec num: 1386991744; nsec num: 676508350
sec num: 1386991748; nsec num: 245595277
time: 3570ms
2、For循環的並行
新建PFor.cpp文件,內容為
1 #include <iostream> 2 #include <time.h> 3 #include <stdio.h> 4 #include <omp.h> 5 void test() 6 { 7 int a = 0; 8 for (int i=0;i<100000000;i++) 9 a++; 10 } 11 int main() 12 { 13 int coreNum = omp_get_num_procs();//獲得處理器個數 14 std::cout<<"cpu numbers: "<<coreNum<<std::endl; 15 struct timespec time1 = {0, 0}; 16 struct timespec time2 = {0, 0}; 17 clock_gettime(CLOCK_REALTIME, &time1); 18 std::cout<<"sec num: "<<time1.tv_sec<<"; nsec num: "<<time1.tv_nsec<<std::endl; 19 //clock_t t1 = clock(); 20 #pragma omp parallel for 21 for (int i=0;i<10;i++) 22 { 23 //std::cout<<"currend id: "<<omp_get_thread_num()<<std::endl; 24 test(); 25 } 26 //clock_t t2 = clock(); 27 //std::cout<<"time: "<<t2-t1<<std::endl; 28 clock_gettime(CLOCK_REALTIME, &time2); 29 std::cout<<"sec num: "<<time2.tv_sec<<"; nsec num: "<<time2.tv_nsec<<std::endl; 30 std::cout<<"time: "<<(time2.tv_sec-time1.tv_sec)*1000+(time2.tv_nsec-time1.tv_nsec)/1000000<<"ms"<<std::endl; 31 }
g++ -fopenmp PFor.cpp -o pfor.out
[root@localhost MPDemo]# ./pfor.out
cpu numbers: 2
sec num: 1386991842; nsec num: 452768086
sec num: 1386991844; nsec num: 527629070
time: 2074
3、分析總結
clock_gettime能獲得納秒級的精度,1秒=10^9納秒。clock_gettime包含多種計時方式。
a、CLOCK_REALTIME:系統實時時間,隨系統實時時間改變而改變
b、CLOCK_MONOTONIC,從系統啟動這一刻起開始計時,不受系統時間被用戶改變的影響
c、CLOCK_PROCESS_CPUTIME_ID,本進程到當前代碼系統CPU花費的時間
d、CLOCK_THREAD_CPUTIME_ID,本線程到當前代碼系統CPU花費的時間
本文默認采用CLOCK_REALTIME,即可實現並行程序的准確計時。示例代碼如下:
1 struct timespec time1 = {0, 0}; 2 clock_gettime(CLOCK_REALTIME, &time1); 3 std::cout<<"sec num: "<<time1.tv_sec<<"; nsec num: "<<time1.tv_nsec<<std::endl;
參考資料
參考比較好的入門資源:博主飲水思源的openMP的一點使用經驗