2011-12-08 63 views
7

我的應用場景是這樣的:我想評估在四核機器上可以達到的性能增益,以處理相同數量的數據。我有以下兩種配置:想在LINUX上分析多線程問題的想法

i)1-進程:沒有任何線程和處理來自1M..1G的數據的程序,而假定系統僅運行其4核的單核。 ii)4線程 - 進程:4線程(所有線程執行相同操作)但處理25%輸入數據的程序。

在我創建4線程的程序中,我使用了pthread的默認選項(即沒有任何特定的pthread_attr_t)。我相信與1-Process配置相比,4線程配置的性能增益應該接近400%(或者介於350%和400%之間)。

我異型在創建線程的花就像下面這樣的時候:

timer_start(&threadCreationTimer); 
pthread_create(&thread0, NULL, fun0, NULL); 
pthread_create(&thread1, NULL, fun1, NULL); 
pthread_create(&thread2, NULL, fun2, NULL); 
pthread_create(&thread3, NULL, fun3, NULL); 
threadCreationTime = timer_stop(&threadCreationTimer); 

pthread_join(&thread0, NULL); 
pthread_join(&thread1, NULL); 
pthread_join(&thread2, NULL); 
pthread_join(&thread3, NULL);  

由於在輸入數據的大小在每個線程的內存需求也可能增加而增加的,那麼加載所有數據提前是絕對不可行的選擇。因此,爲了確保不增加每個線程的內存需求,每個線程以小塊讀取數據,處理它並讀取下一個塊來處理它等等。因此,由線程運行我的函數的代碼的結構是這樣的:

timer_start(&threadTimer[i]); 
while(!dataFinished[i]) 
{ 
    threadTime[i] += timer_stop(&threadTimer[i]); 
    data_source(); 
    timer_start(&threadTimer[i]); 
    process(); 
} 
threadTime[i] += timer_stop(&threadTimer[i]); 

變量dataFinished[i]被處理標記true當它接收和處理所有需要的數據。 Process()知道何時做:-)

在主函數,我計算由4螺紋構造如以下所花費的時間:

execTime4Thread = max(threadTime[0], threadTime[1], threadTime[2], threadTime[3]) + threadCreationTime

和性能增益是通過簡單地

gain = execTime1process/execTime4Thread * 100

版本計算: 在周圍1M小數據大小4M,性能增益通常是良好的(350%至400%之間)。然而,隨着輸入尺寸的增加,性能增益的趨勢呈指數級下降。它一直在下降,直到一些數據大小高達50M左右,然後穩定在200%左右。一旦達到這一點,即使是1GB的數據也幾乎保持穩定。

我的問題是,任何人都可以提出這種行爲的主要原因(即,在開始時性能下降,但以後保持穩定)?

並建議如何解決這個問題?

爲了您的信息,我還調查了threadCreationTimethreadTime針對每個線程的行爲,以瞭解發生了什麼。對於1M數據,這些變量的值很小,但隨着數據大小的增加,這兩個變量指數增加(但threadCreationTime應保持幾乎相同,無論數據大小如何,並且threadTime應以與正在處理的數據相對應的速率增加)。在持續增加到50M左右之後,threadCreationTime變得穩定,並且threadTime(就像性能下降變得穩定)和threadCreationTime以對應於要處理的數據增加的恆定速率增加(這被認爲是可理解的)。

你認爲增加每個線程,進程優先級的東西或(使用pthread_attr_init)可以幫助其他參數類型調度的自定義值的堆棧大小?

PS:(即最小的OS運行沒有GUI和網絡的東西),同時運行在Linux下的程序失敗,並根安全模式的結果獲得。

+0

你的CPU的型號是什麼? – Tudor

+4

線程間最有可能交叉污染緩存。你有沒有嘗試改變數據塊的大小?您還應該在測量中加載數據,因爲它可能是瓶頸,即2個內核可能會使內存總線飽和。 (另外,如果你還沒有這樣做,你應該把你的定時器放在不同的高速緩存行上。) – Mats

+0

@Mats:處理器是Intel(R)Core(TM)2 Quad CPU Q9950 @ 2.83GHz。 不,我沒有驗證數據塊的大小。好的,我會嘗試更改數據塊的大小。 但是,我不明白你的意思是什麼緩存線。如何把定時器緩存? – Junaid

回答

2

由於增加了輸入數據的大小也可能會增加在 每個線程的內存要求,那麼提前加載所有數據 絕對不是一個可行的選擇。因此,爲了確保不會增加每個線程的內存需求,每個線程都會以小塊讀取 數據,並對其進行處理,並讀取下一個塊進行處理,如 等。

單就這一點而言,會導致速度下降嚴重

如果有足夠的存儲器,讀出一個大塊輸入數據總是比小塊讀取數據,尤其是從每個線程更快。分塊(緩存效果)所帶來的任何I/O優勢在分解時都會消失。即使分配一大塊內存也要比分配很多次的小塊便宜得多。

作爲一個全面的檢查,你可以運行htop,以確保至少所有的內核正在運行期間見頂。否則,您的瓶頸可能會超出您的多線程代碼。

內螺紋,

  • 線程上下文切換由於多個線程可能會導致次優的加速
  • 如其他人所說,一個冷緩存由於不讀內存中連續引起延遲

但重新讀你的OP,我懷疑減速與你的數據輸入/內存分配有關。你究竟在哪裏讀取你的數據?某種插座?你確定你需要在你的線程中多次分配內存嗎?

工作線程中的某些算法可能不是最理想的/昂貴的。

0

你的線程是從創建開始的嗎?如果是的話,那麼會發生以下情況:

,而你的父母線程創建線程,已創建的線程將開始運行。當你點擊timerStop(ThreadCreation timer)時,這四個已經運行了 一段時間。所以threadCreationTime重疊threadTime[i]

因爲它現在,你不知道你在測量。這不會解決你的問題,因爲顯然你有問題,因爲threadTime不會線性增加,但至少你不會增加重疊時間。

有你可以使用perf tool(如果可用)在你的發行版的詳細信息。 例如:

perf stat -e cache-misses <your_prog> 

,看到有兩個線程版本,三線版本等會發生什麼......

+0

即使我不考慮'threadCreationTime'並且只考慮'threadTime [i]'(現在已經按照上面關於緩存行的建議拆分成單獨的變量),這個問題仍然存在。遵循這一建議後,結果有所改善,但現在瓶頸已經轉移。也就是說,在1M數據上性能增益很好。但在2M上它會下降,然後在1G時保持不變。 我也會嘗試你的建議,看看緩存未命中。你認爲valgrind可以提供幫助嗎?我也想嘗試英特爾vTune分析器。 – Junaid

+0

@Junaid:cache-missses只是一個例子,有很多值得關注的東西。 – shodanex