[英]OpenMP critical performance better than atomic
我正在嘗試來自https://github.com/joeladams/patternlets/blob/master/patternlets/openMP/14.mutualExclusion-critical2/critical2.c的代碼來證明 Critical 更耗時,但我不斷得到關鍵的執行時間比 Atomic 快的結果。 有誰知道它是怎么發生的?
// simulate many deposits using atomic
startTime = omp_get_wtime();
#pragma omp parallel for
for (i = 0; i < REPS; i++) {
#pragma omp atomic
balance += 1.0;
}
stopTime = omp_get_wtime();
atomicTime = stopTime - startTime;
print("atomic", REPS, balance, atomicTime, atomicTime/REPS);
// simulate the same number of deposits using critical
balance = 0.0;
startTime = omp_get_wtime();
#pragma omp parallel for
for (i = 0; i < REPS; i++) {
#pragma omp critical
{
balance += 1.0;
}
}
stopTime = omp_get_wtime();
criticalTime = stopTime - startTime;
print("critical", REPS, balance, criticalTime, criticalTime/REPS);
我的結果是:
After 1000000 $1 deposits using 'atomic':
- balance = 1000000.00,
- total time = 0.421999931335,
- average time per deposit = 0.000000422000
After 1000000 $1 deposits using 'critical':
- balance = 0.00,
- total time = 0.265000104904,
- average time per deposit = 0.000000265000
謝謝!
發布答案,因為這種情況確實/可以確實存在。 (很大程度上取決於您使用的線程數)
考慮 OP 計算的三種情況(以 10 7 個增量更新balance
,從值 0 開始)到時間並進行比較 - 一種沒有任何形式的並行化(或不使用 openmp 指令),一種具有使用omp critical
更新balance
,以及使用omp atomic
進行更新:
#include <omp.h>
#include <iostream>
int main()
{ const int REPS = 1e+7;
double balance = 0.0;
std::cout << "Running without any explicit parallelization from openmp:" << std::endl;
auto startTime = omp_get_wtime();
for (int i = 0; i < REPS; i++) {
balance += 1.0;
}
auto stopTime = omp_get_wtime();
std::cout << "Balance: " << balance << ", Total time taken: " << stopTime - startTime << std::endl;
// Reset balance:
balance = 0.0;
std::cout << "Running with omp critical:" << std::endl;
startTime = omp_get_wtime();
#pragma omp parallel for
for (int i = 0; i < REPS; i++) {
#pragma omp critical
balance += 1.0;
}
stopTime = omp_get_wtime();
std::cout << "Balance: " << balance << ", Total time taken: " << stopTime - startTime << std::endl;
// Reset balance:
balance = 0.0;
std::cout << "Running with omp atomic:" << std::endl;
startTime = omp_get_wtime();
#pragma omp parallel for
for (int i = 0; i < REPS; i++) {
#pragma omp atomic
balance += 1.0;
}
stopTime = omp_get_wtime();
std::cout << "Balance: " << balance << ", Total time taken: " << stopTime - startTime << std::endl;
}
這是我機器上的兩次運行:
對於單計算,其中omp atomic
是適用的,預計比跑得更快omp critical
是的,但是,它是可能的,相反,它有時會略微更費時。 例如,它不適用於我上面的第二次運行。 我假設這可能是“應該更快的東西似乎有點慢”的一種情況,當您沒有指定線程數(極少數情況)時。 考慮到現代計算機的核心數量很少,因此每次(如提到的 OP)都不太可能獲得相同的結果(原子時間 > 臨界時間)以獲得更多線程數,或者僅使用現代計算機的默認值. (線程數通常由內核數給出,由於超線程,線程數可能是兩倍或更多)
事實上,為了讓我也復制這樣的運行,我試了幾次。 (我想展示兩種情況都可能的運行,同時使用默認線程數,或不指定線程數)
在我談論這種行為每次都可能發生的情況之前,我想提一下,我合並第一種情況(沒有 openmp 指令)的原因是為了表明它會比使用omp critical
或omp atomic
的情況更快,鑒於我們正在運行的代碼段是順序的。 通過使用critical
/ atomic
,我們只是通過鎖定和解鎖引入了額外的開銷。 (與您在使用 pthread 時比較沒有和有互斥鎖的情況時所期望的相同)
現在,如果我要復制 OP 面臨的情況(原子所用時間的重復行為大於關鍵),我會將我的線程數設置為盡可能低,同時仍然牢記不要使其成為單線程:(即2)
omp_set_num_threads(2);
現在,可以觀察到omp atomic
塊所花費的時間總是大於omp critical
塊所花費的時間。 例如,使用此修改運行兩次:(並非罕見的情況)
為了使原子變體在這兩種情況下始終比臨界等價物運行得更快,可以使用帶有適當參數的減少子句:(即,如果我們正在執行加法,則使用“+”運算符,然后是我們要執行的變量在這里聚集)
#pragma omp parallel for reduction(+:balance)
進行此更改后運行兩次(對於兩種情況和三種情況),同時將線程數保持為 2:
最后, omp atomic
現在比critical
等價物運行得更快,很像一般預期。
另一組兩個運行此更改,但不設置線程數:
omp atomic
不僅性能優於omp critical
,而且它現在(總是)比不使用 omp 指令的 case(第一)運行得更快。 (成功的並行化)
我想增加浮點數與增加整數是不同的。 這取決於CPU體系結構。 當我用整數測試時,可以。
看到我的結果:原子比臨界快兩倍以上,但是與不使用原子和臨界相比,它仍然慢得多,即使結果不正確。
因此,如果可能的話,請盡量避免使用鎖,嚴重的,原子的。
測試結果:
無原子,嚴重:6666667、0.000113381
原子的:10000000,0.399095
嚴重:10000000,0.999381
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.