Clang を使用して Nvidia GPU への OpenMP オフロードを必要とするプロジェクトに取り組んでいます。ここに記載されている手順に従って、Clang をインストールしてオフロードをサポートすることができました。
システム仕様
- OS - Ubuntu 16.04 LTS
- Clang - バージョン 4.00
- プロセッサ - Intel(R) Core(TM) i7 -4700MQ CPU
- Cuda -バージョン - 9.0
- Nvidia GPU - GeForce 740M (sm_capability - 35)
しかし問題は、サンプル プログラムを実行して OpenMP から Nvidia GPU をテストすると、ターゲット領域の一部が GPU で実行される傾向があり、同じターゲット領域がホストで実行を開始することです。
サンプル プログラムはこちらにあります。これは、2 つの行列を乗算するように記述された小さな C プログラムです。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>
/* Problem size. */
# define N 1920
void init_array(float* A, float* B)
{
int i, j;
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
{
A[i*N + j] = ((float) i*j) / N;
}
}
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
{
B[i*N + j] = ((float) i*(j+1)) / N;
}
}
}
void mm_kernel(float *A, float *B, float *E)
{
#pragma omp target data map(to:A) map(to:B) map(alloc:E)
{
#pragma omp target
#pragma omp teams distribute num_teams(4)
for (int i = 0; i < N; i++)
{
printf("Team %d Thread %d Number of threads %d \n", omp_get_team_num() ,omp_get_thread_num(),omp_get_num_threads());
#pragma omp parallel for
for (int j = 0; j < N; j++)
{
E[i*N + j] = 0.0;
for(int k = 0; k < N; k++)
{
E[i*N + j] = E[i*N + j] + A[i*N + k] * B[j*N+k];
}
}
}
}
}
int main(){
double t_start, t_end;
float* A;
float* B;
float* E;
A = (float*)malloc(N*N*sizeof(float));
B = (float*)malloc(N*N*sizeof(float));
E = (float*)malloc(N*N*sizeof(float));
init_array(A, B); //initialize Matrix A and B
t_start = omp_get_wtime();
mm_kernel(A,B,E);
t_end = omp_get_wtime();
printf("Time spent %lf\n",t_end-t_start );
free(A);
free(B);
free(E);
}
プログラムは以下を使用してコンパイルされました
clang -fopenmp -fopenmp-targets=nvptx64-nvidia-cuda 3mm.c -o 3mmgpu
ターゲット領域がホストとターゲット デバイスの両方で実行されていると主張する主な理由は、コマンド ラインからの出力によるものです。
最初のチーム 0 とチーム 1 は、各チームごとに 960 を示し、その後の反復では、各チームごとに 2 つのスレッドが得られます (私のプロセッサは、コアごとに 2 つのハードウェア レベルのスレッドを処理できる 4 コア プロセッサです)。
また、GPU で何かが実行されているかどうかを確認するために、nvprof でファット バイナリを実行してみました。
プロファイリング結果は以下の通り。
実際、対象地域で何が起こっているのか理解できません。ターゲット領域がホストとターゲット デバイスの両方で実行されている理由。