Opencl - 减少工作项的数量

时间:2015-01-31 13:58:05

标签: c opencl

我正在尝试为多线程计算crc32。我正在尝试使用OpenCL。 GPU代码是:

__kernel void crc32_Sarwate( __global int* lenghtIn, 
                         __global unsigned char *In, 
                         __global int *OutCrc32,
                            int size ) {
int i, j, len;

i = get_global_id( 0 ); 
if( i >= size )
    return;
len = j = 0;
while( j != i )
    len += lenghtIn[ j++ ];
OutCrc32[ i ] = crc32( In + len, lenghtIn[ i ] ); }

我收到了这个结果(时间),重复一千次:
4使用工作项目:29.82
8使用工作项目:29.9
16使用工作项目:35.16
32使用工作项目:35.93
64使用工作项:38.69
128使用工作项目:52.83
256个使用工作项:152.08
for 512 using work-item:333.63

我有350 MHz的intel HD Graphics和3个工作组,256个工作项 每个工作组。 我假设通过增加工作项128到256的数量发生时间略有增加,但时间增加了两倍。为什么? (对不起我的英语非常糟糕)。

1 个答案:

答案 0 :(得分:0)

while( j != i )
    len += lenghtIn[ j++ ];

部分运行get_global_id(0)次。

当它为128时,要完成的最新工作项是进行128次循环迭代。

当它是256时,它正在进行256次迭代,所以它应该从内存的角度增加%100,但仅限于最后一个工作项。当我们整合所有工人的总内存访问号码时,

 1 item from 0 to 0 ---> 1 access
 2 item from 0 to 0 and 0 to 1  ---> 3 access
 4 item from 0 to 0 and 0 to 1 and 0 to 2 and 0 to 3---> 10 access
 8 items: SUM(1 to 8) => 36 accesses  
 16 items: SUM(1 to 16) => 136 accesses (even more than + %200)
 32 items: => 528 (~ %400)
 64 items: => 2080 ( ~%400)
 128 items: => 8256 (~%400) (cache of your igpu starts failing here)
 256 items: => 32896 (~400%) (now caching is saturated and you start )
                              ( seeing %400 per doubling of work items)

 512 => uses second compute unit too! But %400 work is done 
  so it is not only %200 time consuming.

所以每次按%100增加工作项时,都会增加总内存 访问%400。但缓存有一定程度的帮助。当你越过它时,内存访问会严重增加。另外,执行开销(驱动程序,......)变得不重要。

您正在访问非并行内存。您需要先将其缓存,但可能无法在该硬件中进行缓存,因此您应该在工作项之间平均分配作业,并使内核之间的内存访问连续(vectorize)。这应该会带来更多的表现。

目前,每个向量单位都执行:

unit        :   v0 v1 v2 v3 v4 ... v7
read address:   0  0  0  0  0      0
                -  1  1  1  1      1
                -  -  2  2  2      2
                -  -  -  3  3      3
                -  -  -  -  4      4
                     ....  
                -  -  -  -  - ...  7

在8个流核心上以8个步骤完成。

在最后一步,只有一个工作项实际上在计算某些东西。这应该是这样的:

一些优化

unit        :   v0 v1 v2 v3  no need other work items
read address:   0  0  0  0  \
                1  1  1  1   \
                2  2  2  2    \
                3  3  3  3    / this is 5th work item's work
                4  4  4  4   /
                5  5  5  0   \
                6  6  0  1    \ this is 0 to 3 as 4th work
                7  0  1  2    /
 first item<--  0  1  2  3   /

仅在4个流核心中以8个步骤完成,并且正在为第一个核心执行相同的工作 半部分(可能更快)。

进一步优化建议

我认为在获得crc32()部分之前,在另一个内核上使用前缀扫描(sum)算法会更好。 (这个例子可能只有3个步骤,而不是8个,而且效率更高)

使用预先计算的

while( j != i )
        len += lenghtIn[ j++ ];

应该使crc32免受当前算法复杂度(O(n²))的影响。