gpt4 book ai didi

OpenCL通过引用不同的地址空间传递

转载 作者:行者123 更新时间:2023-12-01 01:12:21 29 4
gpt4 key购买 nike

短篇小说:

我有通过输出变量的引用传递的功能

void acum( float2 dW, float4 dFE, float2 *W, float4 *FE )

如果满足某些条件,则假定变量 *W、*FE、dW、dFE 递增。
我想让这个函数通用 - 输出变量可以是本地的或全局的。
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 中的宏不是很熟悉)。

另一种可能性可能是:
  • 使用返回结构的函数{Wnew, FEnew}
  • 或 (float8)(Wnew,FEnew,0,0) 但我不喜欢它,因为它使代码更加困惑。
  • 当然,我也不想在所有地方都复制“acum”的主体(比如手动内联它:))

  • 背景(无需阅读):

    我正在尝试使用 OpenCL 对一些热力学采样进行编程。因为统计权重 W = exp(-E/kT) 很容易在低温下溢出浮点数 (2^64),所以我制作了一个组合数据类型 W = float2(W_digits, W_exponent) 并定义了操作这些数字“acum”的函数。

    我尽量减少全局内存操作的数量,所以我让 work_items 超过 Vsurf 而不是 FEout,因为我预计 Vsurf 中只有几个点会具有相当大的统计权重,因此每个工作项的 FEout 累积只会被调用几次。虽然迭代 FEout 需要 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 但我认为它与问题无关

    最佳答案

    好的,这里发生了什么,来自 OpenCL 手册页:

    http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/global.html

    “如果对象的类型由地址空间名称限定,则在指定的地址名称中分配对象;否则,在通用地址空间中分配对象”

    ...

    “程序中函数的参数或函数的局部变量的通用地址空间名称是__private。所有函数参数都应在__private地址空间中。”

    因此,您的 acum(... ) 函数参数位于 __private 地址空间中。

    所以编译器正确地说

    acum( ..&Wout[idOut], &FEout[idOut] )

    当函数 args 必须在私有(private)地址空间中时,在全局地址空间中使用 &Wout 和 &FEout 调用。

    解决方案是全局和私有(private)之间的转换。

    创建两个私有(private)临时变量来接收结果。

    用这些变量调用 acum( ... )。

    在调用 acum( .. ) 之后,将临时私有(private)值分配给全局值

    代码看起来有点乱

    记住在 GPU 上你有很多地址空间,你不能通过强制转换来神奇地在它们之间跳转。您必须通过分配在地址空间之间显式移动数据。

    关于OpenCL通过引用不同的地址空间传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14651558/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com