最適化 #1: ベクトルを __local にする。
これでの私の最初のパスは、パフォーマンスがかなり改善されました。各 vector[k] が合計 D 回読み取られることに気付いたので、__local にコピーしました。これが可能なのは、D が十分に小さいためです。上記のカーネルは、5870 と 6970 gpu の両方で 0.08 というひどい ALU:fetch 比率に悩まされています。低速の gpu でさえ、メモリ アクセスを待機しています。
#define D 1000
__kernel void element_mult(
__global float *result,
__global const float *vector,
__global const float *matrix,
__global const float *matrix2,
const float factor)
{
int y = get_global_id(0);
float sum = 0;
__local float vectCopy[D];
int ls = get_local_size(0);
int lid = get_local_id(0);
for(int i=0;i<D;i+=ls){
vectCopy[i+lid] = vector[i+lid];
}
mem_fence(CLK_LOCAL_MEM_FENCE);
for(int k = 0; k < D; k++)
{
sum += vectCopy[k] * matrix[(y*D) + k] * matrix2[(y*D) + k ];
}
result[y] = sum * factor;
}
この変更により、APP プロファイラーは、5870 および 6970 gpu の新しい ALU:fetch 比率 0.20 を示しています。同じカードで平均時間が 1513 から 1034、1261 から 861 に変更されました。ローエンドの GPU は、フェッチではなく ALU によってバインドされるようになりました。(4:1 以上の比率)
最適化 #2: ワーク グループ全体を使用して各結果 [y] を計算します。
これを行う必要があります id D ははるかに大きかった (100k+)。アイデアは、ワーク グループを使用して一度に結果の 1 つの要素を計算することにより、最適なメモリ アクセス パターンを取得することです。ここでは ls (ローカル サイズ) を 64 に定義しました。これは、ほとんどのベンダーと同様に、私のハードウェアでも機能するためです。ホスト側から使用するワークグループ サイズは、その定義を変更しない限り 64 にする必要があります。sum[ls] ストレージを __local として作成するように定義する必要があり、可変サイズの __local 変数をカーネルに渡すのは好きではありません。
結果: 5870 ALU:fetch=0.59:1, avg=708. 6970 ALU:フェッチ=0.72、平均=590。APP プロファイラーによると、これは元のリストの約 2 倍の速さです。
#define D 1000
#define ls 64
__kernel void element_mult(
__global float *result,
__global const float *vector,
__global const float *matrix,
__global const float *matrix2,
const float factor)
{
__local float vectCopy[D];
int lid = get_local_id(0);
for(int i=0;i<D;i+=ls){
vectCopy[i+lid] = vector[i+lid];
}
mem_fence(CLK_LOCAL_MEM_FENCE);
int ng = get_num_groups(0);
int gid = get_group_id(0);
int y, k;
__local float sum[ls];
for(y = gid; y < D; y+=ng){
for(k = lid; k < D; k+=ls)
{
sum[lid] += vectCopy[k] * matrix[(y*D) + k] * matrix2[(y*D) + k ];
}
if(lid==0){
result[y] = sum[0];
for(k=1;k<ls;k++){
result[y] += sum[k];
}
result[y] *= factor;
}
mem_fence(CLK_LOCAL_MEM_FENCE);
}
}
編集: APP プロファイラー = AMD APP KernelAnalyzer