如何在CUDA中打包(有效)?

时间:2016-09-14 10:43:00

标签: c++ parallel-processing cuda bit-packing

我有一个字节数组,其中每个字节都是0或1.现在我想将这些值打包成位,这样8个原始字节占用1个目标字节,原始字节0进入位0,字节1进入第1位等 到目前为止,我在内核中有以下内容:

const uint16_t tid = threadIdx.x;
__shared__ uint8_t packing[cBlockSize];

// ... Computation of the original bytes in packing[tid]
__syncthreads();

if ((tid & 4) == 0)
{
    packing[tid] |= packing[tid | 4] << 4;
}
if ((tid & 6) == 0)
{
    packing[tid] |= packing[tid | 2] << 2;
}
if ((tid & 7) == 0)
{
    pOutput[(tid + blockDim.x*blockIdx.x)>>3] = packing[tid] | (packing[tid | 1] << 1);
}

这是正确有效的吗?

2 个答案:

答案 0 :(得分:8)

__ballot()扭曲投票功能非常方便。 假设您可以将pOutput重新定义为uint32_t类型,并且您的块大小是warp大小的倍数(32):

unsigned int target = __ballot(packing[tid]);
if (tid % warpSize == 0) {
    pOutput[(tid + blockDim.x*blockIdx.x) / warpSize] = target;
}

严格地说,if条件甚至不是必需的,因为warp的所有线程都会将相同的数据写入同一个地址。所以高度优化的版本就是

pOutput[(tid + blockDim.x*blockIdx.x) / warpSize] = __ballot(packing[tid]);

答案 1 :(得分:1)

每个线程两位,使用uint2 *pOutput

int lane = tid % warpSize;
uint2 target;
target.x = __ballot(__shfl(packing[tid], lane / 2)                & (lane & 1) + 1));
target.y = __ballot(__shfl(packing[tid], lane / 2 + warpSize / 2) & (lane & 1) + 1));
pOutput[(tid + blockDim.x*blockIdx.x) / warpSize] = target;

您必须确定这是否仍然比传统解决方案更快。