Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在OpenCL内核中存储小型常量值数组的最佳实践?_Opencl_Gpu_Gpgpu - Fatal编程技术网

在OpenCL内核中存储小型常量值数组的最佳实践?

在OpenCL内核中存储小型常量值数组的最佳实践?,opencl,gpu,gpgpu,Opencl,Gpu,Gpgpu,我正在写一个OpenCL内核,它用5x5高斯滤波器卷积图像,并想知道存储滤波器常数的最佳实践是什么。在内核中,32x32工作组中的每个线程执行以下操作: 将像素加载到\u本地内存缓冲区 通过屏障(CLK\U LOCAL\U MEM\U FENCE)同步 然后对其对应的像素执行卷积 以下是本地图像数据和过滤器的缓冲区: __local float4 localRegion[32][32]; // image region w 2 pixel apron .... static const

我正在写一个OpenCL内核,它用5x5高斯滤波器卷积图像,并想知道存储滤波器常数的最佳实践是什么。在内核中,32x32工作组中的每个线程执行以下操作:

  • 将像素加载到
    \u本地
    内存缓冲区
  • 通过
    屏障(CLK\U LOCAL\U MEM\U FENCE)同步
  • 然后对其对应的像素执行卷积
  • 以下是本地图像数据和过滤器的缓冲区:

     __local float4 localRegion[32][32]; // image region w 2 pixel apron
     .... 
     static const float filter[5][5] = { // __constant vs __private ??
        {1/256.0,  4/256.0,  6/256.0,  4/256.0, 1/256.0},
        {4/256.0, 16/256.0, 24/256.0, 16/256.0, 4/256.0},
        {6/256.0, 24/256.0, 36/256.0, 24/256.0, 6/256.0},
        {4/256.0, 16/256.0, 24/256.0, 16/256.0, 4/256.0},
        {1/256.0,  4/256.0,  6/256.0,  4/256.0, 1/256.0}
      };
    
    哪些内存区域可以容纳
    过滤器
    ,哪一个最好,以及在每种情况下如何进行初始化?最好是
    \uuu private
    ,但我不确定您是否可以静态初始化private数组<代码>\uuu local
    没有意义,除非一些线程负责加载
    过滤器
    条目(我认为)?另外,根据,我不确定
    静态
    \u私有
    是否可以同时使用

    根据和,
    filter
    可以存储为
    \uu private
    ,但不清楚初始化是如何发生的

    但我不确定您是否可以静态初始化私有数组

    Opencl规范说“静态存储类说明符只能用于 非内核函数、程序范围中声明的全局变量和函数中的变量 在全局或常量地址空间中声明。“。最重要的是,编译器(至少是Amd)优化常量数学输出,并通过简单(常量/指令)内存访问进行交换。即便如此,当空间不足时,私有寄存器溢出到全局内存,内核开始访问全局内存。因此,当实际数据有时被转移到其他地方时,静态数据不能有一个有意义的描述

     float filter[5][5] = {  
        {cos(sin(cos(sin(cos(sin(1/256.0f)))))),  4/256.0f,  6/256.0f,  4/256.0f, 1/256.0f},
        {cos(sin(cos(sin(cos(sin(4/256.0f)))))), 16/256.0f, 24/256.0f, 16/256.0f, 4/256.0f},
        {sin(cos(sin(cos(sin(cos(6/256.0f)))))), 24/256.0f, 36/256.0f, 24/256.0f, 6/256.0f},
        {sin(cos(sin(cos(sin(cos(4/256.0f)))))), 16/256.0f, 24/256.0f, 16/256.0f, 4/256.0f},
        {sin(cos(sin(cos(sin(cos(1/256.0f)))))),  4/256.0f,  6/256.0f,  4/256.0f, 1/256.0f}
      };
    
    所需时间(r7_240gpu为0.78ms)与

    分析器的ISA输出没有任何正弦或余弦函数。在某些内存位置中只写入了一些数字。这是未启用任何优化的情况


    哪些内存区域可以容纳过滤器,哪一个是最好的

    取决于硬件,但通常有多种类型:

    // defined before kernel
    __constant float filter[5][5] = { 
        {1/256.0f,  4/256.0f,  6/256.0f,  4/256.0f, 1/256.0f},
        {4/256.0f, 16/256.0f, 24/256.0f, 16/256.0f, 4/256.0f},
        {6/256.0f, 24/256.0f, 36/256.0f, 24/256.0f, 6/256.0f},
        {4/256.0f, 16/256.0f, 24/256.0f, 16/256.0f, 4/256.0f},
        {1/256.0f,  4/256.0f,  6/256.0f,  4/256.0f, 1/256.0f}
      };
    
    对于r7_240 gpu,此命令同时执行。请注意,静态索引对于
    \uu常量
    内存访问更好(至少在amd gpu中),而对于相同的索引访问(组中的所有线程都访问相同的索引,就像在本例中一样(在嵌套循环中))。使用这些寻址模式时,恒定内存比全局内存快,但当使用不同的索引时,它与全局内存访问(甚至命中缓存)没有什么不同。“对于全局作用域常量数组,如果数组大小小于64 kB,则将其放置在硬件常量缓冲区中;否则,将使用全局内存”。(有Amd GCN架构相关,但Nvidia和Intel也可以预期类似的行为)

    Amd的opencl规范称“L1和L2可用于图像和相同的索引常量。”(适用于HD5800系列gpu),因此您也可以使用image2d_t输入获得类似的性能。对于GCN,L1和L2比恒定内存更快

    Nvidia的opencl最佳实践说:“读取紧密相连的纹理地址的p将达到最佳效果 纹理内存还设计用于流式读取,具有恒定的 延迟;也就是说,缓存命中会减少DRAM带宽需求,但不会减少读取延迟。 在某些寻址情况下,可以通过图像对象读取设备内存 是从全局或常量读取设备内存的有利替代方案 记忆。 并且还说“它们是缓存的,如果存在2D局部性,则可能表现出更高的带宽。” 在纹理中获取。”(再次使用image2d\t)

    如果其他地方需要专用内存,您甚至可以拆分筛选器,例如:

    // defined before kernel
    __constant float filter2[3][5] = {  
        {1/256.0f,  4/256.0f,  6/256.0f,  4/256.0f, 1/256.0f},
        {4/256.0f, 16/256.0f, 24/256.0f, 16/256.0f, 4/256.0f},
        {6/256.0f, 24/256.0f, 36/256.0f, 24/256.0f, 6/256.0f},
      };
    
       // no need to write __private, automatically private in function body
       float filter[2][5] = { 
            {4/256.0f, 16/256.0f, 24/256.0f, 16/256.0f, 4/256.0f},
            {1/256.0f,  4/256.0f,  6/256.0f,  4/256.0f, 1/256.0f}
        };
    
    这与上面两个示例具有相同的定时(至少对于r7_240)。所有示例均针对512x512大小的图像运行,其中512x512工作项和16x16本地工作项


    __除非某些线程负责加载筛选器条目,否则本地没有意义

    Amd GCN上的本地内存访问速度是常量内存(相同索引)访问速度的8倍,但在整个GPU上的容量是前者的5-20倍(但对于单个计算单元来说可能更小)。Nvidia的opencl最佳实践也是如此。但是HD5800系列amd gpu比本地内存具有更多的恒定内存带宽。GCN较新,所以本地内存似乎更好,除非它没有足够的空间

    GCN上的专用寄存器比本地内存快5-6倍,每个计算单元的容量是本地内存的8倍。所以,在GCN上的私有内存上有一些东西意味着最终的性能,除非资源消耗停止了足够多的波前来启动(减少延迟隐藏)

    Nvidia也有类似的说法:“一般来说,访问寄存器会在每条指令上消耗零个额外的时钟周期,但是 由于寄存器写后读取依赖关系和寄存器内存,可能会发生延迟 银行冲突。 写后读取依赖项的延迟大约为24个周期,但是 延迟在至少有192个活动线程的多处理器上完全隐藏 (即,6次扭曲)。 "


    还有一些鬼墙加载到本地内存中:

        Test gpu was r7_240 so it can work with only 16x16 local threads
        so 20x20 area is loaded from global memory.
        o: each work item's target pixel
        -: needed ghost wall because of filter going out of bounds
        x: ghost corner handled by single threads (yes,non optimized)
    
        xx----------------xx  
        xx----------------xx
        --oooooooooooooooo--
        --oooooooooooooooo--
        --oooooooooooooooo--
        --oooooooooooooooo--
        --oooooooooooooooo--
        --oooooooooooooooo--
        --oooooooooooooooo--
        --oooooooooooooooo--
        --oooooooooooooooo--
        --oooooooooooooooo--
        --oooooooooooooooo--
        --oooooooooooooooo--
        --oooooooooooooooo--
        --oooooooooooooooo--
        --oooooooooooooooo--
        --oooooooooooooooo--
        xx----------------xx  
        xx----------------xx
    

    此内核用于上层配置文件:

                __constant float filter2[3][5] = {  
                            {1/256.0f,  4/256.0f,  6/256.0f,  4/256.0f, 1/256.0f},
                            {4/256.0f, 16/256.0f, 24/256.0f, 16/256.0f, 4/256.0f},
                            {6/256.0f, 24/256.0f, 36/256.0f, 24/256.0f, 6/256.0f},
                          };
    
    
                __kernel void test1(__global uchar4 *b2,__global uchar4 *b, __global int * p)
                {
                        int j = get_local_id(0);
                        int g = get_group_id(0);
                        int gx=g%32;
                        int gy=g/32;
                        int lx=j%16;
                        int ly=j/16;
                        int x=gx*16+lx;
                        int y=gy*16+ly;
                        if(gx<2 || gx>29 || gy <2 || gy >29)
                        {
                            b2[((y * 512) + x)] = b[((y * 512) + x)];
                            return;
                        }
    
                        __local uchar4 localRegion[22][22]; 
                        localRegion[lx+2][ly+2]=b[((y * 512) + x)]; // interior
    
                        if(lx==0) // left edges
                        {   
                            localRegion[1][ly+2]=b[(( (y) * 512) + x-1)]; // x-1 edge
                            localRegion[0][ly+2]=b[(( (y) * 512) + x-2)]; // x-2 edge
                        }
                        if(lx==15) // right edges
                        {   
                            localRegion[18][ly+2]=b[(( (y) * 512) + x+1)]; // x+1 edge
                            localRegion[19][ly+2]=b[(( (y) * 512) + x+2)]; // x+2 edge
                        }
    
                        if(ly==0) // top edges
                        {   
                            localRegion[lx+2][1]=b[(( (y-1) * 512) + x)]; // y-1 edge
                            localRegion[lx+2][0]=b[(( (y-2) * 512) + x)]; // y-2 edge
                        }
    
                        if(ly==15) // bot edges
                        {   
                            localRegion[lx+2][18]=b[(( (y+1) * 512) + x)]; // y+1 edge
                            localRegion[lx+2][19]=b[(( (y+2) * 512) + x)]; // y+2 edge
                        }
    
                        if(lx==0 && ly==0) // upper-left square
                        {
                            localRegion[0][0]=b[(( (y-2) * 512) + x-2)];
                            localRegion[0][1]=b[(( (y-2) * 512) + x-1)];
                            localRegion[1][0]=b[(( (y-1) * 512) + x-2)];
                            localRegion[1][1]=b[(( (y-1) * 512) + x-1)];
                        }
                        if(lx==15 && ly==0) // upper-right square
                        {
                            localRegion[18][0]=b[(( (y-2) * 512) + x+1)];
                            localRegion[18][1]=b[(( (y-1) * 512) + x+1)];
                            localRegion[19][0]=b[(( (y-2) * 512) + x+2)];
                            localRegion[19][1]=b[(( (y-1) * 512) + x+2)];
                        }
                        if(lx==15 && ly==15) // lower-right square
                        {
                            localRegion[18][18]=b[(( (y+1) * 512) + x+1)];
                            localRegion[18][19]=b[(( (y+2) * 512) + x+1)];
                            localRegion[19][18]=b[(( (y+1) * 512) + x+2)];
                            localRegion[19][19]=b[(( (y+2) * 512) + x+2)];
                        }
                        if(lx==0 && ly==15) // lower-left square
                        {
                            localRegion[0][18]=b[(( (y+1) * 512) + x-2)];
                            localRegion[0][19]=b[(( (y+2) * 512) + x-2)];
                            localRegion[1][18]=b[(( (y+1) * 512) + x-1)];
                            localRegion[1][19]=b[(( (y+2) * 512) + x-1)];
                        }
    
                        barrier(CLK_LOCAL_MEM_FENCE);
    
    
    
                       float filter[2][5] = { 
                            {4/256.0f, 16/256.0f, 24/256.0f, 16/256.0f, 4/256.0f},
                            {1/256.0f,  4/256.0f,  6/256.0f,  4/256.0f, 1/256.0f}
                        };
    
    
                        float4 acc=0;
                        for(int row=-2;row<=0;row++)
                            for(int col=-2;col<=2;col++)
                        {
                            uchar4 tmp=localRegion[lx+col+2][ly+row+2];
                            float tmp2=filter2[row+2][col+2];
                            acc+=((float4)(tmp2,tmp2,tmp2,tmp2)*(float4)((int)tmp.s0,(int)tmp.s1,(int)tmp.s2,(int)tmp.s3));
                        }
                        for(int row=1;row<=2;row++)
                            for(int col=-2;col<=2;col++)
                        {
                            uchar4 tmp=localRegion[lx+col+2][ly+row+2];
                            float tmp2=filter[row-1][col+2];
                            acc+=((float4)(tmp2,tmp2,tmp2,tmp2)*(float4)((int)tmp.s0,(int)tmp.s1,(int)tmp.s2,(int)tmp.s3));
                        }
                        b2[((y * 512) + x)] = (uchar4)(acc.x,acc.y,acc.z,244);
                }
    
    \uuuu常量浮点过滤器2[3][5]={
    {1/256.0f,4/256.0f,6/256.0f,4/256.0f,1/256.0f},
    {4/256.0f、16/256.0f、24/256.0f、16/256.0f、4/256.0f},
    {6/256.0f、24/256.0f、36/256.0f、24/256.0f、6/256.0f},
    };
    __内核无效测试1(uuu全局uchar4*b2、uuu全局uchar4*b、uuu全局int*p)
    {
    int j=获取本地id(0);
    int g=获取组id(0);
    int gx=g%32;
    int-gy=g/32;
    int lx=j%16;
    int-ly=j/16;
    
                __constant float filter2[3][5] = {  
                            {1/256.0f,  4/256.0f,  6/256.0f,  4/256.0f, 1/256.0f},
                            {4/256.0f, 16/256.0f, 24/256.0f, 16/256.0f, 4/256.0f},
                            {6/256.0f, 24/256.0f, 36/256.0f, 24/256.0f, 6/256.0f},
                          };
    
    
                __kernel void test1(__global uchar4 *b2,__global uchar4 *b, __global int * p)
                {
                        int j = get_local_id(0);
                        int g = get_group_id(0);
                        int gx=g%32;
                        int gy=g/32;
                        int lx=j%16;
                        int ly=j/16;
                        int x=gx*16+lx;
                        int y=gy*16+ly;
                        if(gx<2 || gx>29 || gy <2 || gy >29)
                        {
                            b2[((y * 512) + x)] = b[((y * 512) + x)];
                            return;
                        }
    
                        __local uchar4 localRegion[22][22]; 
                        localRegion[lx+2][ly+2]=b[((y * 512) + x)]; // interior
    
                        if(lx==0) // left edges
                        {   
                            localRegion[1][ly+2]=b[(( (y) * 512) + x-1)]; // x-1 edge
                            localRegion[0][ly+2]=b[(( (y) * 512) + x-2)]; // x-2 edge
                        }
                        if(lx==15) // right edges
                        {   
                            localRegion[18][ly+2]=b[(( (y) * 512) + x+1)]; // x+1 edge
                            localRegion[19][ly+2]=b[(( (y) * 512) + x+2)]; // x+2 edge
                        }
    
                        if(ly==0) // top edges
                        {   
                            localRegion[lx+2][1]=b[(( (y-1) * 512) + x)]; // y-1 edge
                            localRegion[lx+2][0]=b[(( (y-2) * 512) + x)]; // y-2 edge
                        }
    
                        if(ly==15) // bot edges
                        {   
                            localRegion[lx+2][18]=b[(( (y+1) * 512) + x)]; // y+1 edge
                            localRegion[lx+2][19]=b[(( (y+2) * 512) + x)]; // y+2 edge
                        }
    
                        if(lx==0 && ly==0) // upper-left square
                        {
                            localRegion[0][0]=b[(( (y-2) * 512) + x-2)];
                            localRegion[0][1]=b[(( (y-2) * 512) + x-1)];
                            localRegion[1][0]=b[(( (y-1) * 512) + x-2)];
                            localRegion[1][1]=b[(( (y-1) * 512) + x-1)];
                        }
                        if(lx==15 && ly==0) // upper-right square
                        {
                            localRegion[18][0]=b[(( (y-2) * 512) + x+1)];
                            localRegion[18][1]=b[(( (y-1) * 512) + x+1)];
                            localRegion[19][0]=b[(( (y-2) * 512) + x+2)];
                            localRegion[19][1]=b[(( (y-1) * 512) + x+2)];
                        }
                        if(lx==15 && ly==15) // lower-right square
                        {
                            localRegion[18][18]=b[(( (y+1) * 512) + x+1)];
                            localRegion[18][19]=b[(( (y+2) * 512) + x+1)];
                            localRegion[19][18]=b[(( (y+1) * 512) + x+2)];
                            localRegion[19][19]=b[(( (y+2) * 512) + x+2)];
                        }
                        if(lx==0 && ly==15) // lower-left square
                        {
                            localRegion[0][18]=b[(( (y+1) * 512) + x-2)];
                            localRegion[0][19]=b[(( (y+2) * 512) + x-2)];
                            localRegion[1][18]=b[(( (y+1) * 512) + x-1)];
                            localRegion[1][19]=b[(( (y+2) * 512) + x-1)];
                        }
    
                        barrier(CLK_LOCAL_MEM_FENCE);
    
    
    
                       float filter[2][5] = { 
                            {4/256.0f, 16/256.0f, 24/256.0f, 16/256.0f, 4/256.0f},
                            {1/256.0f,  4/256.0f,  6/256.0f,  4/256.0f, 1/256.0f}
                        };
    
    
                        float4 acc=0;
                        for(int row=-2;row<=0;row++)
                            for(int col=-2;col<=2;col++)
                        {
                            uchar4 tmp=localRegion[lx+col+2][ly+row+2];
                            float tmp2=filter2[row+2][col+2];
                            acc+=((float4)(tmp2,tmp2,tmp2,tmp2)*(float4)((int)tmp.s0,(int)tmp.s1,(int)tmp.s2,(int)tmp.s3));
                        }
                        for(int row=1;row<=2;row++)
                            for(int col=-2;col<=2;col++)
                        {
                            uchar4 tmp=localRegion[lx+col+2][ly+row+2];
                            float tmp2=filter[row-1][col+2];
                            acc+=((float4)(tmp2,tmp2,tmp2,tmp2)*(float4)((int)tmp.s0,(int)tmp.s1,(int)tmp.s2,(int)tmp.s3));
                        }
                        b2[((y * 512) + x)] = (uchar4)(acc.x,acc.y,acc.z,244);
                }