短片:
我有输出变量的引用传递函数
void acum( float2 dW, float4 dFE, float2 *W, float4 *FE )
如果满足某些编码,则假设增量变量* W,* FE,dW,dFE。 我想使这个函数通用 - 输出varibales可以是本地的也可以是全局的。
acum( dW, dFE, &W , &FE ); // __local acum
acum( W, FE, &Wout[idOut], &FEout[idOut] ); // __global acum
当我尝试编译它时,我收到了错误
error: illegal implicit conversion between two pointers with different address spaces
有可能以某种方式使它成为???我在想是否可以使用宏而不是函数(但我对C中的宏不是很熟悉)。
另一种可能性可能是:
Backbround(无需阅读):
我正在尝试使用OpenCL对程序进行一些热力学采样。因为统计权重W = exp(-E / kT)很容易溢出浮动(2 ^ 64)低温,我做了一个组合数据类型W = float2(W_digits,W_exponent),我定义了函数来操纵这些数字“acum”。
我尽量减少全局内存操作的次数,所以我让work_items超过Vsurf而不是FEout,因为我预计Vsurf中只有几个点会有相当大的统计权重,所以FEout的累积只会被调用几次每个工作项目。虽然在FEout上的iteratin需要sizeof(FEout)* sizeof(Vsurf)内存操作。 整个代码在这里(任何重新命令如何使它更有效率是受欢迎的):
// ===== function :: FF_vdW - Lenard-Jones Van Der Waals forcefield
float4 FF_vdW ( float3 R ){
const float C6 = 1.0;
const float C12 = 1.0;
float ir2 = 1.0/ dot( R, R );
float ir6 = ir2*ir2*ir2;
float ir12 = ir6*ir6;
float E6 = C6*ir6;
float E12 = C12*ir12;
return (float4)(
( 6*E6 - 12*E12 ) * ir2 * R
, E12 - E6
);}
// ===== function :: FF_spring - harmonic forcefield
float4 FF_spring( float3 R){
const float3 k = (float3)( 1.0, 1.0, 1.0 );
float3 F = k*R;
return (float4)( F,
0.5*dot(F,R)
);}
// ===== function :: EtoW - compute statistical weight
float2 EtoW( float EkT ){
float Wexp = floor( EkT);
return (float2)( exp(EkT - Wexp)
, Wexp
); }
// ===== procedure : addExpInplace -- acumulate F,E with statistical weight dW
void acum( float2 dW, float4 dFE, float2 *W, float4 *FE )
{
float dExp = dW.y - (*W).y; // log(dW)-log(W)
if(dExp>-22){ // e^22 = 2^32 , single_float = 2^+64
float fac = exp(dExp);
if (dExp<0){ // log(dW)<log(W)
dW.x *= fac;
(*FE) += dFE*dW.x;
(*W ).x += dW.x;
}else{ // log(dW)>log(W)
(*FE) = dFE + fac*(*FE);
(*W ).x = dW.x + fac*(*W).x;
(*W ).y = dW.y;
}
}
}
// ===== __kernel :: sampler
__kernel void sampler(
__global float * Vsurf, // in : surface potential (including vdW) // may be faster to precomputed endpoints positions like float8
__global float4 * FEout, // out : Fx,Fy,Fy, E
__global float2 * Wout, // out : W_digits, W_exponent
int3 nV ,
float3 dV ,
int3 nOut ,
int3 iOut0 , // shift of Fout in respect to Vsurf
int3 nCopy , // number of copies of
int3 nSample , // dimension of sampling in each dimension around R0 +nSample,-nSample
float3 RXe0 , // postion Xe relative to Tip
float EcutSurf ,
float EcutTip ,
float logWcut , // accumulate only when log(W) > logWcut
float kT // maximal energy which should be sampled
) {
int id = get_global_id(0); // loop over potential grid points
int idx = id/nV.x;
int3 iV = (int3)( idx/nV.y
, idx%nV.y
, id %nV.x );
float V = Vsurf[id];
float3 RXe = dV*iV;
if (V<EcutSurf){
// loop over tip position
for (int iz=0;iz<nOut.z;iz++ ){
for (int iy=0;iy<nOut.y;iy++ ){
for (int ix=0;ix<nOut.x;ix++ ){
int3 iTip = (int3)( iz, iy, ix );
float3 Rtip = dV*iTip;
float4 FE = 0;
float2 W = 0;
// loop over images of potential
for (int ix=0;ix<nCopy.x;ix++ ){
for (int iy=0;iy<nCopy.y;iy++ ){
float3 dR = RXe - Rtip;
float4 dFE = FF_vdW( dR );
dFE += FF_spring( dR - RXe0 );
dFE.w += V;
if( dFE.w < EcutTip ){
float2 dW = EtoW( - FE.w / kT );
acum( dW, dFE, &W , &FE ); // __local acum
}
}
}
if( W.y > logWcut ){ // accumulate force
int idOut = iOut0.x + iOut0.y*nOut.x + iOut0.z*nOut.x*nOut.y;
acum( W, FE, &Wout[idOut], &FEout[idOut] ); // __global acum
}
}}}}
}
我在ubuntu 12.04 64bit上使用pyOpenCL但我认为它与问题没有关系
答案 0 :(得分:4)
好的,在这里发生了什么,来自OpenCL手册页:
http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/global.html
“如果对象的类型由地址空间名称限定,则该对象将在指定的地址名称中分配;否则,该对象将在通用地址空间中分配”
...
“程序中函数的参数的通用地址空间名称,或函数的局部变量是__private。所有函数参数都应在__private地址空间中。”
所以你的acum(...)函数args位于__private地址空间。
所以编译器正确地说
acum(..&amp; Wout [idOut],&amp; FEout [idOut])
当函数args必须在私有地址空间中时,在全局addrress空间中调用&amp; Wout和&amp; FEout。
解决方案是全球和私人之间的转换。
创建两个私有临时变量来接收结果。
用这些变量调用acum(...)。
在调用acum(..)
之后,将临时私有值分配给全局值代码看起来有点凌乱
请记住,在GPU上你有很多地址空间,你不能通过施法来神奇地在它们之间跳跃。您必须通过赋值在地址空间之间显式移动数据。