2017-09-05 214 views
2

我打算執行矢量操作,並嘗試使用向量添加和乘法的小型虛擬程序。但是,由於我對共享內存的知識限制,代碼無法運行。互聯網上的所有資源都顯示出二維矩陣運算,我無法將其轉化爲矢量問題。考慮到我是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

共享內存是隻在一個工作組中看到的更快的內存。在內核之間,通過使用cl緩衝區的全局內存來訪問數據,所以共享內存只能被「分配」並在內核中使用。對於1D,您可能會使用共享內存進行縮減,保存中間值以避免重寫到全局內存。要使用'__local__'來訪問它。 – theoden

+0

你是什麼意思你的代碼不運行?它運行並給出錯誤的結果還是失敗?您應該檢查每個OpenCL調用以查看它們是否返回CL_SUCCESS。如果你能提供更多的信息,對我們來說是有益的。 –

+0

@parallelhighway我正在使用英特爾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運行你的內核,並且它們都無法編譯,Intel給出錯誤「在OpenCL中不支持可變長度的數組」,即使N = 16。你的主機代碼對我來說看起來不錯,但我使用'clEnqueueNDRangeKernel',所以我不熟悉你使用的API ... – kenba

+0

哦。我無法弄清楚這個代碼中出現了什麼問題,只是增加了兩個向量。你能發現我正在製造什麼錯誤或提供替代工作解決方案嗎? – Ijjz