質問

したがって、この質問は愚かに聞こえることはわかっていますが(はい、私はデュアルコアを使用しています)、2つの異なるライブラリ(Grand Central DispatchとOpenMP)を試しました。そして、クロック()を使用して、平行なら速度は同じです。(記録のために、彼らは両方とも独自の形式の並列を使用していました)。これらは別のスレッドで実行されていると報告されていますが、おそらく同じコアで実行されているのでしょうか?確認する方法はありますか?(どちらのライブラリも C 用です。下位層では不快です。) これは非常に奇妙です。何か案は?

役に立ちましたか?

解決

編集:OP コメントに応じて、Grand Central Dispatch の詳細を追加しました。

ここでの他の回答は一般的に役に立ちますが、あなたの質問に対する具体的な回答は、使用すべきではないということです。 clock() タイミングを比較するためです。 clock() スレッド全体で合計された CPU 時間を測定します。ジョブをコア間で分割すると、少なくとも同じ量の CPU 時間が使用されます (通常はスレッドのオーバーヘッドによりもう少し多くなります)。で Clock() を検索します これ ページで、「プロセスがマルチスレッドの場合、プロセスのすべての個々のスレッドによって消費される CPU 時間が追加されます。」を見つけます。

ジョブがスレッド間で分割されるため、全体的な待機時間が短くなるだけです。ウォールタイム(壁掛け時計の時間)を使用する必要があります。OpenMP はルーチンを提供します omp_get_wtime() それをするために。次のルーチンを例として取り上げます。

#include <omp.h>
#include <time.h>
#include <math.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
    int i, nthreads;
    clock_t clock_timer;
    double wall_timer;
    for (nthreads = 1; nthreads <=8; nthreads++) {
        clock_timer = clock();
        wall_timer = omp_get_wtime();
        #pragma omp parallel for private(i) num_threads(nthreads)
        for (i = 0; i < 100000000; i++) cos(i);
        printf("%d threads: time on clock() = %.3f, on wall = %.3f\n", \
            nthreads, \
            (double) (clock() - clock_timer) / CLOCKS_PER_SEC, \
            omp_get_wtime() - wall_timer);
    }
}

結果は次のとおりです。

1 threads: time on clock() = 0.258, on wall = 0.258
2 threads: time on clock() = 0.256, on wall = 0.129
3 threads: time on clock() = 0.255, on wall = 0.086
4 threads: time on clock() = 0.257, on wall = 0.065
5 threads: time on clock() = 0.255, on wall = 0.051
6 threads: time on clock() = 0.257, on wall = 0.044
7 threads: time on clock() = 0.255, on wall = 0.037
8 threads: time on clock() = 0.256, on wall = 0.033

ご覧のとおり、 clock() 時間はあまり変わりません。なしでは 0.254 になります。 pragma, したがって、1 つのスレッドで openMP を使用すると、openMP をまったく使用しない場合よりも少し遅くなりますが、スレッドごとに所要時間は減少します。

たとえば、計算の一部が並列ではないため、改善が必ずしも良好になるとは限りません (「 アムダールの法則)、または同じメモリをめぐって異なるスレッドが競合している場合。

編集:グランド セントラル ディスパッチの場合、 GCD リファレンス GCD が使用していると述べています gettimeofday 壁の時間のために。そこで、新しい Cocoa アプリを作成します。 applicationDidFinishLaunching 置いた:

struct timeval t1,t2;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int iterations = 1; iterations <= 8; iterations++) {
    int stride = 1e8/iterations;
    gettimeofday(&t1,0);
    dispatch_apply(iterations, queue, ^(size_t i) { 
        for (int j = 0; j < stride; j++) cos(j); 
    });
    gettimeofday(&t2,0);
    NSLog(@"%d iterations: on wall = %.3f\n",iterations, \
                t2.tv_sec+t2.tv_usec/1e6-(t1.tv_sec+t1.tv_usec/1e6));
}

コンソールに次の結果が表示されます。

2010-03-10 17:33:43.022 GCDClock[39741:a0f] 1 iterations: on wall = 0.254
2010-03-10 17:33:43.151 GCDClock[39741:a0f] 2 iterations: on wall = 0.127
2010-03-10 17:33:43.236 GCDClock[39741:a0f] 3 iterations: on wall = 0.085
2010-03-10 17:33:43.301 GCDClock[39741:a0f] 4 iterations: on wall = 0.064
2010-03-10 17:33:43.352 GCDClock[39741:a0f] 5 iterations: on wall = 0.051
2010-03-10 17:33:43.395 GCDClock[39741:a0f] 6 iterations: on wall = 0.043
2010-03-10 17:33:43.433 GCDClock[39741:a0f] 7 iterations: on wall = 0.038
2010-03-10 17:33:43.468 GCDClock[39741:a0f] 8 iterations: on wall = 0.034

これは私が上記で得ていたものとほぼ同じです。

これは非常に不自然な例です。実際、最適化を -O0 に維持する必要があります。そうしないと、コンパイラは計算をまったく保持せず、ループをまったく実行しないことを認識します。また、私がとっている整数は、 cos of は 2 つの例で異なりますが、結果にはあまり影響しません。を参照してください。 STRIDE のマンページにある dispatch_apply それを適切に行う方法とその理由について iterations 概ね~に匹敵する num_threads この場合。

編集:ジェイコブの答えには次のものが含まれていることに注意してください

並列化されたループ内のopmget_thread_num()関数を使用して、どのコアで作業しているかを印刷します...これにより、両方のコアで実行されていることを確認できます。

これは正しくありません (編集により部分的に修正されました)。使用する omp_get_thread_num() これは確かにコードがマルチスレッドであることを確認する良い方法ですが、「どのコアで動作しているか」は表示されず、どのスレッドが表示されるかだけが表示されます。たとえば、次のコード:

#include <omp.h>
#include <stdio.h>

int main() {
    int i;
    #pragma omp parallel for private(i) num_threads(50)
    for (i = 0; i < 50; i++) printf("%d\n", omp_get_thread_num());
}

スレッド 0 ~ 49 を使用していることが出力されますが、コアが 8 つしかないため、どのコアで動作しているかは表示されません。アクティビティモニターを見ることによって(OPはGCDに言及しているため、Mac上にある必要があります) Window/CPU Usage)、コア間でジョブが切り替わっていることがわかります。つまり、core != threadです。

他のヒント

ほとんどの場合、あなたの実行時間は、あなたが並列化され、それらのループに拘束されていません。

私の提案は、あなたがほとんどの時間を取っているかを見るためにあなたのコードをプロファイリングということです。ほとんどのエンジニアは、あなたが何をすべきことを教えてくれます。このの前にの事を最適化するために抜本的な何もしています。

これは、任意の詳細がなくて推測するのは難しいです。たぶん、あなたのアプリケーションでもCPUバインドされていません。あなたのコードが実行中に、あなたは、CPUの負荷を見ましたか?それは、少なくとも1つのコア上で100%をヒットでしたか?

あなたの質問には、アプリケーションの性質、アプリケーションのどの部分を改善しようとしているのか、プロファイリング結果(ある場合)など、非常に重要な詳細がいくつか欠けています。

ただし、パフォーマンス向上の取り組みに取り組む際には、いくつかの重要な点を覚えておく必要があります。

  • 取り組みは常に実証済みのコード領域に集中する必要があります。 プロファイリングによる, 、非効率的になる
  • CPU バウンド コードを並列化すると、 ほとんどは決してない (シングルコアマシン上で) パフォーマンスが向上します。不必要なコンテキストの切り替えで貴重な時間を失い、利益を得ることになります。 何もない. 。とても簡単にできます パフォーマンスの悪化 こうすることで。
  • マルチコア マシン上で CPU バウンド コードを並列化している場合でも、並列実行の保証はまったくないことに注意してください。

これらの点に反していないことを確認してください。これは、経験に基づいた推測 (追加の詳細を除く) で、まさにそれが実行していることになるためです。

あなたがループ内に大量のメモリを使用している場合、それはより速くされてからそれを防ぐかもしれません。また、手動でスレッドを処理するために、pthreadのライブラリに見ることができる。

私が使用するのは、 omp_get_thread_num() 並列化ループ内の関数で、どのコアで動作しているかを出力します 指定しない場合 num_threads. 。たとえば、

printf("Computing bla %d on core %d/%d ...\n",i+1,omp_get_thread_num()+1,omp_get_max_threads());

上記は、このプラグマ#pragma omp並列で機能します(なし)共有(a、b、c)

こうすることで、スレッドが 2 つだけ作成されるため、両方のコアで実行されていることを確認できます。

ところで、コンパイル時に OpenMP は有効になっていますか?Visual Studio では、これを有効にする必要があります。 プロパティページ, C++ -> Language そしてセット OpenMP SupportYes

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top