我正在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;
答案 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