最適化#1:ベクトル__localを作成します。
これで私の最初のパスは、パフォーマンスのまともな改善を得ました。私は、各ベクトル[k]が合計D回読み取られていることに気づいたので、それを__localにコピーしました。これは、Dがこれを可能にするのに十分小さいためにのみ可能です。上記のようなカーネルは、5870と6970gpusの両方で0.08のひどいALU:フェッチ比に苦しんでいます。遅いgpusでさえメモリアクセスを待っています。この変更に伴い
#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プロファイラは、新たなALUを示している:5870と6970のGPUのための0.20の比率を取得。同じカードで平均時間が1513 - > 1034、および1261 - > 861に変更されました。ローエンドのgpusはフェッチではなくALUでバインドされるようになりました。 (4:1より大きい)
オペレーション#2:作業グループ全体を使用して各結果[y]を計算する。
あなたはこのIDをもっと大きくする必要があります(100k +)。考え方は、ワークグループを使用して一度に結果の単一要素を計算することによって、最良のメモリアクセスパターンを得ることです。私はls(ローカルサイズ)をここでは64に定義しました。なぜなら、それは私のハードウェアだけでなく、ほとんどのベンダーにとっても機能するからです。その定義を変更しない限り、ホスト側から使用するワークグループのサイズは64でなければなりません。これは、__localとして合計[ls] storageを作成するために定義する必要があります。また、可変サイズの__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);
}
}
EDIT:APPプロファイラ= AMD APP KernelAnalyzer
出典
2012-02-23 16:24:42
mfa
あなたは確信しているが、あなたは、y * Dの計算は、コンパイラによってk個のループの外に持ち上げられていること、ありませんか?そして、共通の部分式(y * D)+ kは各反復で一度だけ計算されるのですか? –
これはNVIDIA GPUで偶然に実行していますか? – talonmies
@talonmies、私は確信することはできません。計算は自分のコンピュータではローカルに行われません。基本的にはOpenCLである必要があります。 – trolle3000