0

Intel Xeon Phi は、「IMCI」命令セット
を使用して提供します。私はそれを使用して、次のように「c = a*b」を実行しました。

float* x = (float*) _mm_malloc(N*sizeof(float), ALIGNMENT) ;
float* y = (float*) _mm_malloc(N*sizeof(float), ALIGNMENT) ;
float z[N];
_Cilk_for(size_t i = 0; i < N; i+=16)
{
    __m512 x_1Vec = _mm512_load_ps(x+i);
    __m512 y_1Vec = _mm512_load_ps(y+i);

    __m512 ans = _mm512_mul_ps(x_1Vec, y_1Vec);
    _mm512_store_pd(z+i,ans);

}

そして、パフォーマンスをテストします。N SIZE が 1048576 の場合、
0.083317 秒のコストが必要です。パフォーマンスを自動ベクトル化と比較したい
ので、他のバージョン コードは次のようになります。

_Cilk_for(size_t i = 0; i < N; i++)
    z[i] = x[i] * y[i];

このバージョンのコストは 0.025475 秒 (0.002285 以下の場合もありますが、理由はわかりません)
_Cilk_for を #pragma omp parallel for に変更すると、パフォーマンスが低下します。

では、このような答えなら、なぜ組み込み関数を使用する必要があるのでしょうか?
私はどこかで間違いを犯しましたか?
コードを最適化するための良い提案を誰かに教えてもらえますか?

4

2 に答える 2

3

さまざまな間違いがあるため、測定値はあまり意味がありません。

  • このコードは、16 個の float を 8 個の double として格納しています。である_mm512_store_pd必要があります_mm512_store_ps
  • コードは、アドレス z+i のアラインされていない場所で _mm512_store_... を使用しているため、セグメンテーション フォールトが発生する可能性があります。__declspec(align(64))これを修正するために使用します。
  • 配列 x と y は初期化されていません。これは、パフォーマンスに影響を与える可能性のある非正規値の乱数を導入するリスクがあります。(これが Intel Xeon Phi の問題かどうかはわかりません)。
  • z が使用されているという証拠はないため、オプティマイザーは計算を削除する可能性があります。ここではそうではないと思いますが、このような些細なベンチマークではリスクがあります。また、スタックに大きな配列を割り当てると、スタック オーバーフローの危険性があります。
  • 例を 1 回実行するだけでは、ベンチマークとしてはおそらく不十分です。時間は、おそらく_Cilk_for. 120 個の Cilk ワーカー (60 個の 4 ウェイ スレッド コアのデフォルト) を想定すると、ワーカーあたり約 1048576/120/16 = ~546 回の反復しかありません。1 GHz を超えるクロック レートでは、それほど時間はかかりません。実際、ループ内の作業は非常に小さいため、一部のワーカーは作業を盗む機会を得られない可能性が高いです。これが、_Cilk_for が OpenMP よりも優れている理由を説明している可能性があります。OpenMP では、並列領域を終了するには、すべてのスレッドが fork/join に参加する必要があります。

テストがすべての間違いを修正するように書かれている場合、それは本質的に大きな配列で z[:] = x[:]*y[:] を計算することになります。インテル(R) Xeon Phi(TM) のワイド・ベクトル・ユニットにより、これは ALU 速度ではなく、メモリー/キャッシュ帯域幅のテストになります。

組み込み関数は、並列/simd ループとして表現できないもの、通常は高度な順列を必要とするものに役立ちます。たとえば、組み込み関数を使用して MIC で 16 要素のプレフィックスサム演算を実行しました (私の記憶が正しければ 6 命令だけです)。

于 2014-05-23T19:57:43.540 に答える
0

以下の私の答えは、Intel Xeon と Intel Xeon Phi に等しく当てはまります。

  1. Intrinsics-bases ソリューションは、アセンブリ コーディングと同様に最も「強力」です。
    • しかし、マイナス面として、組み込みベースのソリューションは通常 (ほとんど) 移植性がなく、「生産性」指向のアプローチではなく、確立された「レガシー」ソフトウェア コードベースには適用できないことがよくあります。
    • さらに、多くの場合、プログラマーは低レベルで、さらにはマイクロアーキテクチャの専門家である必要があります。
  2. ただし、組み込み/アセンブリコーディングに代わるアプローチがあります。彼らです:
    • A) 自動ベクトル化 (コンパイラーがいくつかのパターンを認識し、ベクトルコードを自動的に生成する場合)
    • B) 「明示的」またはユーザーガイドによるベクトル化 (プログラマーが何をベクトル化するか、どのような条件でベクトル化するかなどに関してコンパイラーに何らかのガイダンスを提供する場合。明示的なベクトル化は通常、キーワードまたはプラグマの使用を意味します)
    • C) VEC クラスまたは他の種類の組み込みラッパー ライブラリ、さらには非常に特殊なコンパイラを使用する。実際、2.C は多くの場合、生産性とレガシー コードのインクリメンタル アップデートの点で組み込みコーディングと同じくらい悪いです)。

2 番目のコード スニペットでは、Intel Compiler の最近のすべてのバージョンと GCC4.9 でサポートされている Cilk Plus と OpenMP4.0 の「フレームワーク」を使用すると、現在達成可能な「明示的な」ベクトル化を使用しているようです。( Cilk_for はもともとマルチスレッド化を目的として発明されたので、明示的なベクトル化を使用しているようだと言いましたが、最新バージョンのインテル® コンパイラーでは、cilk_for を使用すると、ループが自動的に並列化およびベクトル化される可能性があります)

于 2014-05-22T14:23:05.020 に答える