2014-03-01 18 views
2

我有一個C++程序與多個For循環;每個運行約500萬次迭代。有沒有我可以使用g ++的命令,使得生成的.exe將使用多個核心;即讓第一個For循環運行在第一個內核上,第二個For循環同時運行在第二個內核上?我試過了-O3和-O3 -ftree-vectorize,但是在這兩種情況下,我的CPU使用率仍然只有25%左右。讓g ++生成一個可以使用多個內核的程序?

編輯: 這是我的代碼,以防萬一。我基本上只是製作一個程序來測試我的電腦的速度功能。

#include <iostream> 
using namespace std; 
#include <math.h> 
int main() 
{ 

float *bob = new float[50102133]; 
float *jim = new float[50102133]; 
float *joe = new float[50102133]; 

int i,j,k,l; 
//cout << "Starting test..."; 
for (i=0;i<50102133;i++) 
    bob[i] = sin(i); 
for (j=0;j<50102133;j++) 
    bob[j] = sin(j*j); 
for (k=0;k<50102133;k++) 
    bob[k] = sin(sqrt(k)); 
for (l=0;l<50102133;l++) 
    bob[l] = cos(l*l); 
cout << "finished test."; 
cout << "the 100120 element is," << bob[1001200]; 

return 0; 
} 
+2

爲什麼不使用線程? –

+0

有點相關:http://stackoverflow.com/questions/9244481/how-to-get-100-cpu-usage-from-a-c-program – Mysticial

回答

0

C++ 11得到支持threading但C++編譯器不會/不能做自己的任何線程。

6

最明顯的選擇是使用OpenMP。假設你的循環是一個真的很容易並行執行多個迭代,你也許可以只加:循環

#pragma openmp parallel for 

...之前,並得到它的並行執行。編譯時還需要添加-fopenmp

根據循環的內容,這可能會導致接近線性的加速,從而使代碼速度有所下降。在後一種情況下(減速或最小加速),可能還有其他的事情可以用OpenMP來幫助加速,但是至少對代碼本身不瞭解,很難猜測要做什麼或者有什麼改進最大限度地能夠期待。

你得到的其他建議(「使用線程」)可能是合適的。 OpenMP基本上是一種將線程用於特定類型的並行代碼的自動化方法。對於你描述的情況(並行執行一個循環的多次迭代),OpenMP通常是首選 - 實現起來要簡單得多,並且除非你知道多線程和/或花費很多,否則可能會提供更好的性能努力並行化代碼。

編輯:

您的問題給的代碼可能不會從多個線程中受益。問題在於,在將結果寫入內存之前,它對每個數據項執行的計算量很小。即使是單個內核也可能足夠快地完成計算,以至於整體速度將受到內存帶寬的限制。爲了從多線程中獲得一些真正的好處,你可能想要編寫一些代碼,它可以執行更多的計算,而不僅僅是讀寫內存。之前只是

#pragma omp parallel for reduction(+:total) 

...:例如,如果我們崩潰的計算在一起,做所有的人都在一個單一的項目,再總結的結果:

double total = 0; 

for (int i = 0; i < size; i++) 
    total += sin(i) + sin(i*i) + sin(sqrt(i)) + cos(i*i); 

通過添加編譯for循環,我們很有可能看到執行速度的顯着提高。如果沒有OpenMP的,我得到這樣的時刻:

Real 16.0399 
User 15.9589 
Sys  0.0156001 

...但隨着#pragma和OpenMP啓用當我編譯,我得到一次這樣的:

Real 8.96051 
User 17.5033 
Sys  0.0468003 

所以,在我的(雙核)處理器,時間從16降至9秒 - 不太快兩倍,但非常接近。當然,你獲得的很多改進將取決於你有多少核心可用。例如,在我的另一臺電腦(帶有Intel i7 CPU)上,我獲得了更大的改進,因爲它擁有更多內核。

OpenMP的無:

Real 15.339 
User 15.3281 
Sys  0.015625 

...並使用OpenMP:

Real 3.09105 
User 23.7813 
Sys  0.171875 

爲了完整起見,這裏是我使用的最終代碼:

#include <math.h> 
#include <iostream> 

static const int size = 1024 * 1024 * 128; 
int main(){ 
    double total = 0; 

#pragma omp parallel for reduction(+:total) 
    for (int i = 0; i < size; i++) 
     total += sin(i) + sin(i*i) + sin(sqrt(i)) + cos(i*i); 
    std::cout << total << "\n"; 
} 
+0

謝謝!我嘗試了優化後的代碼,我能夠在30秒內運行約50億次優化(相比差不多2分鐘,而沒有使用-fopenmp),而原始的內存密集型程序每秒約500萬次迭代。 – user3368803

2

編譯器有沒有辦法來判斷循環內的代碼是否可以在多個內核上安全執行。如果你想使用所有的核心,使用線程。

+0

一些代碼示例可以如何完全做到這一點? –

0

正如其他人所指出的那樣,你可以手動使用線程來實現這一目標。你可以看看如libdispatch(又名GCD)或Intel's TBB等庫,以幫助你以最小的痛苦做到這一點。

您提到的-ftree-vectorize選項用於在CPU(如ARM的NEON或Intel的SSE)上定位SIMD矢量處理器單元。生成的代碼不是線程並行的,而是使用單個線程並行操作的。

上面發佈的代碼示例非常適合於SIMD系統的並行性,因爲每個循環的主體非常明顯與先前的迭代沒有依賴關係,並且循環中的操作是線性的。

至少在某些ARM Cortex A系列系統上,您可能需要接受略微降低的精度才能獲得全部優勢。

相關問題