2017-09-05 13 views
2

私はベクトル操作を行い、ベクトル加算と乗算を使って小さなダミープログラムを試していました。しかし、共有メモリに関する知識が限られているため、コードは実行されません。インターネット上のすべての情報源は、私のベクトル問題に変換できない2Dマトリックス操作を示しています。私がOpenCLで初心者であるという事実を考慮して、どこが間違っているのかを説明してください。コードは以下の通りである:OpenCLの共有メモリ

ホスト・コード:

std::vector<cl::Platform> platforms; 
std::vector<cl::Device> devices; 
cl::Context context; 
cl::CommandQueue queue; 
cl::Program program; 
cl::Kernel kernel; 

cl::Platform::get(&platforms); 

deviceUsed = 0; 

cl_context_properties properties[] = 
{ CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[0])(),0 }; 

context = cl::Context(CL_DEVICE_TYPE_ALL, properties); 
devices = context.getInfo<CL_CONTEXT_DEVICES>(); 

queue = cl::CommandQueue(context, devices[deviceUsed]); 
cl::Program::Sources source(1, std::make_pair(kernel_source.c_str(), kernel_source.size())); 
program = cl::Program(context, source); 
program.build(devices); 

std::vector <float> a; 
std::vector <float> b; 
std::vector <float> sum; 
std::vector <float> prod; 

int globalSize = 128; 
int localSize = 16; 

a.resize(globalSize); 
b.resize(globalSize); 
sum.resize(globalSize); 
prod.resize(globalSize); 

for (int i = 0; i < globalSize ; i++) 
{ 
    a[i] = 1.0f * i; 
    b[i] = 5.0f * i; 
} 
cl::Buffer buffer_A; 
cl::Buffer buffer_B; 
cl::Buffer buffer_sum; 
cl::Buffer buffer_prod; 

buffer_A = cl::Buffer (context, CL_MEM_READ_WRITE, sizeof(float) * globalSize); 
buffer_B = cl::Buffer (context, CL_MEM_READ_WRITE, sizeof(float) * globalSize); 

queue.enqueueWriteBuffer(buffer_A, CL_TRUE, 0, sizeof(float) * globalSize , &a[0]); 
queue.enqueueWriteBuffer(buffer_B, CL_TRUE, 0, sizeof(float) * globalSize , &b[0]); 

buffer_sum = cl::Buffer(context, CL_MEM_WRITE_ONLY, sizeof(float) * globalSize); 
buffer_prod = cl::Buffer(context, CL_MEM_WRITE_ONLY, sizeof(float) * globalSize); 

kernel.setArg(0, buffer_A); 
kernel.setArg(1, buffer_B); 
kernel.setArg(2, buffer_sum); 
kernel.setArg(3, buffer_prod); 

queue.enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(globalSize/localSize), cl::NDRange(N), NULL); 
queue.finish(); 
queue.enqueueReadBuffer(buffer_sum, CL_TRUE, 0, sizeof(float) * globalSize, &sum[0]); 
queue.enqueueReadBuffer(buffer_prod, CL_TRUE, 0, sizeof(float) * globalSize, &prod[0]); 

カーネル:私はあなたのカーネルがコンパイルされませんので、あなたのコードが実行されないと思われる

#define STRINGI(ker) #ker 
std::string kernel_source = STRINGI(

__kernel void KernelAddMul(__global float* a, __global float* b, __global float* sum, __global float* prod) 
{ 
    unsigned int j = get_local_id(0); 
    int N = get_local_size(0); 
    unsigned int i = N * get_global_id(0) + j; 

    float locSum[N]; 
    float locProd[N]; 

    __local float Asub[N]; 
    __local float Bsub[N]; 

    for(int k = 0; k < N; k++){ 

     Asub[k] = a[i]; 
     Bsub[k] = b[i]; 
     barrier(CLK_LOCAL_MEM_FENCE); 

     locSum[k] = Asub[k] + Bsub[k]; 
     locProd[k] = Asub[k] * Bsub[k]; 
     barrier(CLK_LOCAL_MEM_FENCE); 

     sum[i] = locSum[k]; 
     prod[i] = locProd[k]; 
    } 

} 

); 
+1

共有メモリは、1つのワークグループ内でしか見られない、より高速なメモリです。カーネル間では、clバッファを使用してグローバルメモリを介してデータにアクセスするため、共有メモリはカーネル内でのみ「割り当て」および使用することができます。 1Dの場合は、おそらく共有メモリを使用して削減し、中間値を保存してグローバルメモリに書き直さないようにします。それにアクセスするには '__local__'を使います。 – theoden

+0

コードが実行されないとはどういう意味ですか?それは実行され、間違った結果を与えるか、それとも失敗するか?それぞれのOpenCL呼び出しをチェックして、CL_SUCCESSを戻すかどうかを確認する必要があります。より多くの情報を提供できるのであれば、私たちには有益です。 –

+0

@parallelhighway Intel SDKを使用していて、コードがコンパイルされています。しかし、私がsumとprodの値をカーネルから返すと、すべての0が表示されます。私は何かが些細なことを逃していると思う。ローカルコードとグローバルメモリが通信するホストコードまたはカーネルコードのenqueueNDRangeKernelステートメントの引数に問題がある可能性があります。コードを一度見てください。ありがとう:) – Ijjz

答えて

2

次の行が無効である:

int N = get_local_size(0); 

float locSum[N]; 
float locProd[N]; 

__local float Asub[N]; 
__local float Bsub[N]; 

Nが一定でなければならない、あなたは動的get_local_size(0)を使って、配列のサイズをすることはできません。

カーネルをコンパイルするには、スタンドアロンコンパイラを使用することを強くお勧めします。 CodeXLは、Intel SDK for OpenCLのように非常に優れています。 アプリケーションでカーネルをデバッグしようとするよりも優れています。

+0

私はインテルSDKを使用しており、コードがコンパイルされます。しかし、私がsumとprodの値をカーネルから返すと、すべての0が表示されます。値N = 16をハードコーディングしても、結果は同じです。私は何かが些細なことを逃していると思う。ローカルコードとグローバルメモリが通信するホストコードまたはカーネルコードのenqueueNDRangeKernelステートメントの引数に問題がある可能性があります。コードを一度見てください。ありがとう:) – Ijjz

+0

@Ejaz私は、CodeXLとIntel SDKの両方を使ってカーネルを実行しましたが、どちらもコンパイルに失敗しました.N = 16の場合でも、 "可変長配列はOpenCLでサポートされていません"というエラーが出ました。あなたのホストコードは私にはうまく見えますが、私は 'clEnqueueNDRangeKernel'を使用していますので、あなたのAPIに慣れていません。 – kenba

+0

ああ。私は2つのベクトルを追加するだけで、このコードで何がうまくいかないのか分かりません。私が間違いを犯していることに気づくことができますか、あるいは代替の解決策を提供できますか? – Ijjz