Nvidia ドライバーを使用して小さな OpenCL ベンチマークを実行しています。私のカーネルは 1024 個のヒューズ乗算加算を実行し、結果を配列に格納します。
#define FLOPS_MACRO_1(x) { (x) = (x) * 0.99f + 10.f; } // Multiply-add
#define FLOPS_MACRO_2(x) { FLOPS_MACRO_1(x) FLOPS_MACRO_1(x) }
#define FLOPS_MACRO_4(x) { FLOPS_MACRO_2(x) FLOPS_MACRO_2(x) }
#define FLOPS_MACRO_8(x) { FLOPS_MACRO_4(x) FLOPS_MACRO_4(x) }
// more recursive macros ...
#define FLOPS_MACRO_1024(x) { FLOPS_MACRO_512(x) FLOPS_MACRO_512(x) }
__kernel void ocl_Kernel_FLOPS(int iNbElts, __global float *pf)
{
for (unsigned i = get_global_id(0); i < iNbElts; i += get_global_size(0))
{
float f = (float) i;
FLOPS_MACRO_1024(f)
pf[i] = f;
}
}
しかし、生成された PTX を見ると、次のように表示されます。
.entry ocl_Kernel_FLOPS(
.param .u32 ocl_Kernel_FLOPS_param_0,
.param .u32 .ptr .global .align 4 ocl_Kernel_FLOPS_param_1
)
{
.reg .f32 %f<1026>; // 1026 float registers !
.reg .pred %p<3>;
.reg .s32 %r<19>;
ld.param.u32 %r1, [ocl_Kernel_FLOPS_param_0];
// some more code unrelated to the problem
// ...
BB1_1:
and.b32 %r13, %r18, 65535;
cvt.rn.f32.u32 %f1, %r13;
fma.rn.f32 %f2, %f1, 0f3F7D70A4, 0f41200000;
fma.rn.f32 %f3, %f2, 0f3F7D70A4, 0f41200000;
fma.rn.f32 %f4, %f3, 0f3F7D70A4, 0f41200000;
fma.rn.f32 %f5, %f4, 0f3F7D70A4, 0f41200000;
// etc
// ...
私が正しければ、PTX は1026個の float レジスタを使用して 1024 個の演算を実行し、2 つのレジスタのみを使用してすべての乗加算演算を実行できたとしても、レジスタを 2 回再利用することはありません。1026 は、(仕様によると) スレッドが持つことができるレジスタの最大数をはるかに超えているため、これはメモリの流出につながると思います。
それはコンパイラのバグですか、それとも完全に何かが欠けていますか?
Quadro K2000 GPU で nvcc バージョン 6.5 を使用しています。
編集
実際、私は仕様で何かを見逃していました:
「PTX は仮想レジスタをサポートしているため、コンパイラ フロントエンドが多数のレジスタ名を生成することは非常に一般的です。すべての名前の明示的な宣言を必要とするのではなく、PTX は、共通のプレフィックス文字列が追加された一連の変数を作成するための構文をサポートしています。整数サフィックス。たとえば、プログラムが %r0、%r1、...、%r99 という名前の .b32 変数を多数、たとえば 100 個使用しているとします。