2016-04-30 3 views
4

Is OpenMP (parallel for) in g++ 4.7 not very efficient? 2.5x at 5x CPUには、私のプログラムのパフォーマンスが11秒から13秒の間で変化することが判明しました(ほとんど常に12秒以上、時には13.4分s)をデフォルトの#pragma omp parallel forで使用し、OpenMPのスピードアップは、4コア8スレッドXeonの場合、5x CPUの場合には2.5x(g++-4.7 -O3 -fopenmp)でわずか2.5倍です。OpenMP:ハイパースレッディングコアを使用しない

schedule(static) num_threads(4)を試してみましたが、自分のプログラムが約320%のCPUで常に11.5秒から11.7秒(常に12秒以下)で完了することに気付きました。例えば、一貫して動作し、ハイパースレッディング付きの珍しい外れ値よりも0.5秒遅い)。

ハイパースレッディングを検出する単純なOpenMPの方法はありますか?num_threads()を実際のCPUコア数に減らしてください。

(同様の質問、Poor performance due to hyper-threading with OpenMP: how to bind threads to coresがありますが、私のテストでは、私は8〜4スレッドから単なる減少が何とかすでに++ワット/ gでその仕事をしていることを発見 - Debianの7喘鳴およびXeon E3-1240v3 4.7この非常に疑問は単にコアの数にnum_threads()を減らすことです。)

+3

いいえ、これを完全に自動化する簡単な方法はありません。しかし、http://stackoverflow.com/q/2901694/620382 + 'omp_set_num_threads'があります。また、可能ならば、各システムのスレッド構成を手動で制御することをお勧めします。 – Zulan

+0

なぜこの質問が下落したのですか? – cnst

答えて

2

あなたは[x86 archと仮定して] Linuxで実行していた場合、/proc/cpuinfoを見ることができます。 2つのフィールドcpu coressiblingsがあります。最初は[実際の]コアの数であり、後者はハイパースレッドの数です。 (例えば、私のシステムでは、4つのコアハイパースレッドマシンでそれぞれ4と8です)。

Linuxはこれと[Zulanのコメントのリンク]を検出できるため、この情報はx86 cpuid命令からも入手できます。

いずれかの方法では、このための環境変数があります:ランチャー/ラッパースクリプトと組み合わせて使用​​する方が簡単かもしれOMP_NUM_THREADS

一つあなたが考慮することを望むかもしれない事があるというスレッドの一定数を超えましたメモリバスを飽和させることができ、スレッド(またはコア)の増加がパフォーマンスを向上させず、実際にはパフォーマンスを低下させる可能性があります。この質問から

Atomically increment two integers with CAS二つの部分にあるCppCon 2015からのビデオ通話へのリンクがあります: https://www.youtube.com/watch?v=lVBvHbJsg5Yhttps://www.youtube.com/watch?v=1obZeHnAwz4

彼らはIMO、約1.5時間ごとだが、それだけの価値。

スピーカー[マルチスレッド/マルチコアの最適化をたくさん行っている]は、経験からメモリバス/システムが約4スレッド後に飽和する傾向があると述べています。

0

ハイパースレッディングはIntelの実装simultaneous multithreading (SMT)です。現在のAMDプロセッサはSMTを実装していません(Bulldozerのマイクロアーキテクチャファミリには、AMDがクラスタベースのマルチスレッディングと呼ぶものがありますが、ZenのマイクロアーキテクチャはSMTを持つと考えられています)。 OpenMPにはSMTを検出するための組み込みサポートはありません。

ハイパースレッディングを検出する一般的な機能を使用するには、異なる世代のプロセッサをサポートし、プロセッサがAMDではなくIntelプロセッサであることを確認する必要があります。これにはライブラリを使用するのが最善です。

しかし、hereと記載されているように、多くの最新のIntelプロセッサで動作するOpenMPを使用して関数を作成できます。

次のコードは、現代のIntelプロセッサ(私が試したすべてのIntelプロセッサで動作しています)上の物理コアの数を数えます。これを動作させるには、スレッドをバインドする必要があります。 GCCでは export OMP_PROC_BIND=trueを使用できます。それ以外の場合はbind with code(これは私が行うことです)です。

このメソッドがVirtualBoxで信頼できるかどうかはわかりません。 VirtualBoxを4つのコア/ 8論理プロセッサーCPUに搭載し、Windowsをホストとし、Linuxの場合、VMのコア数を4に設定すると、このコードは2つのコアを報告し、/ proc/cpuinfoは2つのコアが実際に論理プロセッサであることを示します。

#include <stdio.h> 

//cpuid function defined in instrset_detect.cpp by Agner Fog (2014 GNU General Public License) 
//http://www.agner.org/optimize/vectorclass.zip 

// Define interface to cpuid instruction. 
// input: eax = functionnumber, ecx = 0 
// output: eax = output[0], ebx = output[1], ecx = output[2], edx = output[3] 
static inline void cpuid (int output[4], int functionnumber) { 
#if defined (_MSC_VER) || defined (__INTEL_COMPILER)  // Microsoft or Intel compiler, intrin.h included 

    __cpuidex(output, functionnumber, 0);     // intrinsic function for CPUID 

#elif defined(__GNUC__) || defined(__clang__)    // use inline assembly, Gnu/AT&T syntax 

    int a, b, c, d; 
    __asm("cpuid" : "=a"(a),"=b"(b),"=c"(c),"=d"(d) : "a"(functionnumber),"c"(0) :); 
    output[0] = a; 
    output[1] = b; 
    output[2] = c; 
    output[3] = d; 

#else              // unknown platform. try inline assembly with masm/intel syntax 

    __asm { 
    mov eax, functionnumber 
     xor ecx, ecx 
     cpuid; 
    mov esi, output 
     mov [esi], eax 
     mov [esi+4], ebx 
     mov [esi+8], ecx 
     mov [esi+12], edx 
     } 

    #endif 
} 

int getNumCores(void) { 
    //Assuming an Intel processor with CPUID leaf 11 
    int cores = 0; 
    #pragma omp parallel reduction(+:cores) 
    { 
    int regs[4]; 
    cpuid(regs,11); 
    if(!(regs[3]&1)) cores++; 
    } 
    return cores; 
} 

int main(void) { 
    printf("cores %d\n", getNumCores()); 
} 
関連する問題