スレッド化されたインテル ® MKL をマルチスレッド・アプリケーションで使用する

インテル® oneMKL

この記事は、インテル® デベロッパー・ゾーンに掲載されている「Using Threaded Intel® MKL in Multi-Thread Application」(http://software.intel.com/en-us/articles/using-threaded-intel-mkl-in-multi-thread-application) の日本語参考訳です。


はじめに

インテル® マス・カーネル・ライブラリー (インテル® MKL) は、OpenMP* によるスレッド化で広範囲に並列化されています。そのため、スレッド化されたインテル® MKL ライブラリーにリンクすると、マルチコアシステムで自動的にプログラムが並列化されます。デフォルトでは、インテル® MKL は、OpenMP* によりスレッド数を設定し、スレッドを管理しています。しかし、ほかの手法 (例えば Linux* の Pthreads* など) でプログラムがスレッド化されている場合は、複数のスレッドを過度に使用しないように、シーケンシャル・ライブラリーを使うか、MKL_NUM_THREADS または OMP_NUM_THREADS =1 を設定して、インテル® MKL によるスレッド化を無効にすることを推奨します。あらゆる手法でアプリケーションの並列化を進めるにしたがって、いくつかの疑問が生じるでしょう。例えば、マルチスレッド・アプリケーションでインテル® MKL によるスレッド化を利用することはできるのか? ユーザースレッドとインテル® MKL スレッドは同時に実行できるのか?   また、どのようにしたらインテル® MKL スレッドを特定のコアにバインドできるのか? などです。フォーラムにも、U404745 How to set affinity while using MKL (インテル® MKL を使用する際のアフィニティーの設定) や U38468 Problem with calling MKL gemm with pthread (Pthreads* でインテル® MKL の gemm を呼び出す際の問題) といった投稿があります。手短に言えば、インテル® MKL スレッドをマルチスレッド・アプリケーションで使用し、必要に応じてユーザーがインテル® MKL スレッド・アフィニティーを制御することは可能です。

この記事では、これらの疑問を取り上げます。すでにスレッド化されたアプリケーションで、スレッド化されたインテル® MKL を呼び出すケースに注目し、サンプルを例にインテル® MKL スレッドをプロセッサーにバインドする方法を説明します。

Q1:すでにマルチスレッド化されているアプリケーションで インテル® MKL スレッドを使用することはできますか?

多数の行列演算を実行する マルチスレッド・アプリケーションで、個別のスレッドにより各行列の演算を行うとします。(出典: フォーラム 475357)

テストシステムは、2 プロセッサー、プロセッサーごとに 4 コア、コアごとに 2 スレッド (インテル® ハイパースレッディング・テクノロジーが有効で、合計 8 物理コア、16 論理コア) と仮定します。行列乗算を同時に実行するスレッドを 2 つ生成し、それぞれで 4 つのインテル® MKL スレッドを開始することは可能でしょうか?

はい、マルチスレッド・アプリケーションでインテル® MKL スレッドを使用することは可能です (関連情報 [1] を参照)。次に簡単な例を示します。

#define NUM_PTHREADS 2
#define NUM_OMP_THREADS 4

mklTest(){
    mkl_set_num_threads_local(NUM_OMP_THREADS);
    mklcall();
}

// threadFunction;
void *threadfunc(void *pArg){
    mklTest()
}

int main(void){
    // Pthreads* を 2 つ生成する
    pthread_create(&tThreads[i], NULL, threadfunc, &idThreads[i]);
}

詳細は、添付の PDF ファイル (英語) を参照してください。

Q2: どのようにしたらインテル® MKL スレッドを特定のコアに明示的にバインドできますか?

2.1 グローバルにインテル® MKL スレッド・アフィニティーを設定する

複雑な状況では、スレッドを特定のプロセッサー・コアに明示的にバインドしなければいけないことがあるでしょう。インテル® MKL は、インテル® コンパイラーの OpenMP* ランタイム・ライブラリーをベースにしているため、OpenMP* スレッドを物理処理ユニットにバインドして、コンパイラーの OpenMP* と同じ方法でインテル® MKL スレッド・アフィニティーを制御することができます。一般に、2 つの方法があります。

詳細は、添付の PDF ファイル (英語) の 2-1 節を参照してください。

2.2 Pthreads* でインテル® MKL スレッド・アフィニティーを設定する

前述の方法は、グローバル・アフィニティーに基づいています。しかし、Pthreads* 内でスレッド・アフィニティーの制御が必要になることもあります。インテル® MKL スレッドには、Pthreads* プログラムの並列領域内かどうかが分かりません。そのため、インテル® MKL スレッド・アフィニティーを考慮して、生成する各 POSIX* スレッドのバインドするコード位置で set_affinity を追加し、OpenMP* ランタイム・ライブラリーから POSIX* スレッドを見えるようにし、AFFINITY 設定に応じてバインドされるようにします。

コード例と詳細は、添付の PDF ファイル (英語) の 2-2 節を参照してください。

2.3 Pthreads* で KMP アフィニティー関数を用いてインテル® MKL スレッド・アフィニティーを設定する

インテル® MKL スレッドを特定のプロセッサーにバインドするには、KMP アフィニティー関数を使用します。

omp_set_num_threads(NUM_OMP_THREADS);
    #pragma omp parallel default(shared)
    {
        // スレッド数を取得する
        int ompTid = omp_get_thread_num();

        // omp マスクを作成する
        kmp_affinity_mask_t new_omp_mask;
        kmp_create_affinity_mask(&new_omp_mask);

        // omp スレッドを偶数コアにバインドする
        kmp_set_affinity_mask_proc(ompTid*2+ thread_id* runprocs, &new_omp_mask);

        if (kmp_set_affinity(&new_omp_mask) != 0)
            printf("thread_id=%d Error: kmp_set_affinity(%d, &new_omp_mask)\n", thread_id, ompTid);

        printf("thread_id=%d, omp_tid=%d, new_mask=%08X \n", thread_id,ompTid, *(unsigned int*)(&new_omp_mask) );
    }

2.4 Pthreads* のアフィニティーを設定した場合のインテル® MKL スレッドの動作

Pthreads* スレッドでインテル® MKL スレッドを特定のプロセッサーにバインドする場合、最初に Pthreads* をバインドしてからインテル® MKL スレッドをバインドします。しかし、前述のとおり、インテル® MKL スレッドはインテルの OpenMP* ライブラリーによって管理されています。インテル® MKL スレッドには、Pthreads* の並列領域内かどうか、そしてどの Pthreads* が呼び出しているかが分かりません。ここでよくある問題は、インテル® MKL スレッドが Pthreads* のアフィニティーに従わないことです。そのため、例えば pthread_setaffinity_np() を使用して、Pthread 1 を CPU 0-7 に、Pthread 2 を CPU 8-15 にバインドします。

詳細は、添付の PDF ファイル (英語) の 2-4 節を参照してください。

まとめ

スレッド・アフィニティーは、スレッドを CPU コアにバインドします。マシンのトポロジーにより、スレッド・アフィニティーはプログラムの実行速度に大きな影響を与えます。インテル® MKL は OpenMP* によってスレッド化されているため、インテル® MKL スレッドは OpenMP* の手法によって制御することができます。高レベルのマルチスレッド・プログラムには、スレッド化されたインテル® MKL の使用を推奨しませんが、適切なアフィニティー設定を用いて十分注意して使用することはできます。この記事では、Pthreads* で KMP 環境変数と OS アフィニティー関数 sched_setaffinity を利用してグローバルにアフィニティーを設定するケース、Pthreads* 内部で OS アフィニティー関数と kmp_set_affinity 関数を利用するケース、pthread_getaffinity_np で Pthreads* のアフィニティーを設定する際のインテル® MKL スレッドの動作について説明しました。基本的な概念が得られたかと思います。

  1. Pthreads* と OpenMP* スレッドが同時に実行する場合、一般に最近の OS スケジューラーは上手く振る舞うことができるでしょう。ほとんどの場合、各 Pthreads* のタスクが均等であれば、スレッド・アフィニティーは必要ありません (ただし、必ずそうであるとは限りません)。

  2. OpenMP* スレッドと Pthreads* は互いを認識しませんが、ほとんどの場合スレッドの動作には影響しません (ただし、必ずそうであるとは限りません)。そのため、環境変数や OS アフィニティー関数によってグローバルにアフィニティーを設定することができます。

  3. OpenMP* スレッドと Pthreads* は互いを認識しませんが、バインドする位置に set_affinity 関数を追加することで OpenMP* スレッドのアフィニティーを制御できます。ここでは、OpenMP* スレッドと Pthreads* の関連付けを示すため、Pthreads* の番号を渡しました。

  4. マルチスレッドはランダムに実行されるため、アウト・オブ・オーダー実行によりいくつかの問題が生じます。例えば、OpenMP* スレッドは現在実行中の Pthreads* を予測できないため、インテル® MKL スレッドは Pthreads* のアフィニティーに従いません。

関連情報

  1. Using Intel® MKL with Threaded Applications (インテル® MKL とスレッド化アプリケーションの使用) (http://software.intel.com/en-us/articles/intel-math-kernel-library-intel-mkl-using-intel-mkl-with-threaded-applications)
  2. マルチスレッド・アプリケーションからインテル® MKL ルーチンを呼び出す場合の推奨設定
  3. Setting thread affinity on SMT or HT enabled systems for better performance (SMT または HT 対応システムで優れたパフォーマンスを得るためのスレッド・アフィニティーの設定) (http://software.intel.com/en-us/articles/setting-thread-affinity-on-smt-or-ht-enabled-systems)
  4. インテル® マス・カーネル・ライブラリー・リファレンス・マニュアル (http://software.intel.com/en-us/articles/intel-math-kernel-library-documentation)
  5. How to set affinity while using MKL (インテル® MKL を使用する場合のアフィニティーの設定) (http://software.intel.com/en-us/forums/topic/404745)
  6. Problem with calling MKL gemm with pthread (Pthreads* でインテル® MKL の gemm を呼び出す場合の問題) (http://software.intel.com/en-us/forums/topic/384681)
  7. How to set affinity of threads spawned by MKL? (インテル® MKL によってスポーンされたスレッドのアフィニティーの設定) (http://software.intel.com/en-us/forums/topic/296195)
添付ファイル サイズ
mkl-affinity.pdf
http://software.intel.com/sites/default/files/managed/9d/e9/mkl-affinity.pdf” type=”application/pdf
214.96KB

コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。

タイトルとURLをコピーしました