OpenCL - 将字节拆分为8分量向量的最有效方法

时间:2016-03-23 18:37:33

标签: optimization opencl

我正在OpenCL中构建Ising模型的模拟,这意味着我的数据由一系列状态组成,这些状态可以是向上/ 1或向下/ -1。

为了节省存储器带宽,这些状态中的8个被编码为单个字节(up = 1,down = 0)。现在,在其中一个计算中,我需要一个整数向量,其值对应于原始状态,即1或-1。

例:
输入字节(OpenCL中的uchar):01010011
转换为:(int8)(-1,1,-1,1,-1,-1,1,1);

我确实有一个解决该问题的工作解决方案,但我想知道是否有更快捷,更有效的方式:

uchar c = spins[id];
int8 spin;
spin.s0 = (c >> 0) & 1;
spin.s1 = (c >> 1) & 1;
spin.s2 = (c >> 2) & 1;
spin.s3 = (c >> 3) & 1;
spin.s4 = (c >> 4) & 1;
spin.s5 = (c >> 5) & 1;
spin.s6 = (c >> 6) & 1;
spin.s7 = (c >> 7) & 1;
spin = spin * 2 - 1;

编辑:

在我的情况下似乎没有更快,但它至少更简洁:

__constant uchar8 bits = (uchar8)(0,1,2,3,4,5,6,7);

uchar c = spins[id];
int8 spin = convert_int8((uchar8)(c) >> bits & 1) * 2 - 1;

1 个答案:

答案 0 :(得分:1)

bool8似乎仍是一种保留类型。我认为它现在对用户开放了,我错了。

选项1)

不安全,(%100肯定)在所有硬件上工作,但您可以定义此联合

            typedef union hardwareBool8{
                char  v;
                bool bit_select[8];
            } vecb8;

然后在内核中:

            vecb8 t={5}; // initialize with any number from your uchar/char
            t.v=1; // or initialize with this
            t.bit_select[4]=0; // set or get to some integer
            int intVariable =t.bit_select[7]; // can be 1 or 0 or -1,you should try. If not -1 then you can negate
            int intVariable2=-t.bit_select[7];

这是在我的amd机器上编译,但我不确定任何其他硬件。 即使是字节序也可能是个问题。

选项2)

可能将相同的char广播到8个线程(或从8个线程访问相同的位置):

   char charVar= ... load from same address/index ;

然后在每个线程上处理不同的位索引:

  spin.s0 = (c >> 0) & 1; (on thread 0)

...

  spin.s7 = (c >> 7) & 1; (on thread 7)

应该给它一些性能但是只有单个自旋元素。许多最新的gpu架构支持在单个指令中向所有线程广播相同的数据。如果你的设备是一个CPU,每个工作组8个线程不应该慢很多,但如果它是gpu,那么每个连续8个线程选择1个字符是很棘手的。像

这样的东西
  charArrayIndex = globalThreadId / 8 
  c = charArray[charArrayIndex];

  // assuming spin is local memory array and shared by work group threads
  spin[globalThreadId % 8] = (c >> (globalThreadId % 8)) & 1; 

如果spin必须是私有变量,则可以使用相同的本地内存数组作为通信数组,将值复制到所有线程的私有变量。这是从(指令级别+线程级别)并行性到仅线程级并行性。

选项3)

您可以将位选择(所有8个)分配到核心的不同“单元”,如果操作在不同的单元中完成,那么这可能会有利于乱序执行。

spin.s2 = (c / 4) & 1;   // 1 division and 1 logical
spin.s0 = (c) & 1;       //  1 logical
spin.s1 = (c & 2)>0;   //  1 logical and 1 comparison