モデルに適合するために小さな行列 (50 ~ 100 x 1000 要素) に対していくつかの MKL 呼び出しを実行するルーチンがあり、それをさまざまなモデルに対して呼び出します。擬似コード:
double doModelFit(int model, ...) {
...
while( !done ) {
cblas_dgemm(...);
cblas_dgemm(...);
...
dgesv(...);
...
}
return result;
}
int main(int argc, char **argv) {
...
c_start = 1; c_stop = nmodel;
for(int c=c_start; c<c_stop; c++) {
...
result = doModelFit(c, ...);
...
}
}
上記のバージョン 1 を呼び出します。モデルは独立しているため、次のように OpenMP スレッドを使用してモデル フィッティングを並列化できます (バージョン 2)。
int main(int argc, char **argv) {
...
int numthreads=omp_max_num_threads();
int c;
#pragma omp parallel for private(c)
for(int t=0; t<numthreads; t++) {
// assuming nmodel divisible by numthreads...
c_start = t*nmodel/numthreads+1;
c_end = (t+1)*nmodel/numthreads;
for(c=c_start; c<c_stop; c++) {
...
result = doModelFit(c, ...);
...
}
}
}
ホスト マシンでバージョン 1 を実行すると、約 11 秒かかり、VTune はほとんどの時間をアイドル状態に費やして並列化が不十分であると報告します。ホスト マシンでのバージョン 2 の実行には約 5 秒かかり、VTune は優れた並列化を報告します (ほぼ 100% の時間が 8 つの CPU の使用に費やされます)。ここで、Phi カードでネイティブ モード (-mmic を使用) で実行するコードをコンパイルすると、mic0 のコマンド プロンプトで実行すると、バージョン 1 と 2 の両方で約 30 秒かかります。VTune を使用してプロファイリングすると、次のようになります。
- バージョン 1 には同じ約 30 秒かかり、ホットスポット分析では、ほとんどの時間が __kmp_wait_sleep と __kmp_static_yield に費やされていることが示されています。7710 秒の CPU 時間のうち、5804 秒がスピン時間に費やされます。
- バージョン 2 は fooooorrrreevvvver かかります... VTune で数分実行した後、それを強制終了します。ホットスポット分析は、25254 秒の CPU 時間のうち、21585 秒が [vmlinux] で費やされていることを示しています。
ここで何が起こっているのか、なぜこんなにパフォーマンスが悪いのか、誰かが光を当てることができますか? OMP_NUM_THREADS のデフォルトを使用し、KMP_AFFINITY=compact,granularity=fine を設定しています (Intel の推奨に従って)。私は MKL と OpenMP を初めて使用するので、初歩的な間違いを犯していると確信しています。
ありがとう、アンドリュー