【发布时间】:2019-02-22 16:36:33
【问题描述】:
我对 SIMD 很好奇,想知道它是否可以处理这个用例。
假设我有一个由 2048 个整数组成的数组,例如 [0x018A, 0x004B, 0x01C0, 0x0234, 0x0098, 0x0343, 0x0222, 0x0301, 0x0398, 0x0087, 0x0167, 0x0389, 0x03F2, 0x0034, 0x0345, ...]
注意它们都是如何以 0x00、0x01、0x02 或 0x03 开头的。我想把它们分成4个数组:
- 一个代表所有以 0x00 开头的整数
- 一个代表所有以 0x01 开头的整数
- 一个代表所有以 0x02 开头的整数
- 一个代表所有以 0x03 开头的整数
我想我会有这样的代码:
int main() {
uint16_t in[2048] = ...;
// 4 arrays, one for each category
uint16_t out[4][2048];
// Pointers to the next available slot in each of the arrays
uint16_t *nextOut[4] = { out[0], out[1], out[2], out[3] };
for (uint16_t *nextIn = in; nextIn < 2048; nextIn += 4) {
(*** magic simd instructions here ***)
// Equivalent non-simd code:
uint16_t categories[4];
for (int i = 0; i < 4; i++) {
categories[i] = nextIn[i] & 0xFF00;
}
for (int i = 0; i < 4; i++) {
uint16_t category = categories[i];
*nextOut[category] = nextIn[i];
nextOut[category]++;
}
}
// Now I have my categoried arrays!
}
我想我的第一个内循环不需要 SIMD,它可以只是一个(x & 0xFF00FF00FF00FF00) 指令,但我想知道我们是否可以将第二个内循环变成一个 SIMD 指令。
对于我正在执行的“分类”操作,是否有任何类型的 SIMD 指令?
“插入”说明似乎有些希望,但我有点太幼稚了,无法理解 https://software.intel.com/en-us/node/695331 的描述。
如果没有,有什么可以接近的吗?
谢谢!
【问题讨论】:
-
分散的商店 - 为此您需要 AVX-512。它可能也不会超级高效。
-
感谢领导,这非常有趣!经过一番阅读,看起来分散的商店可以将一堆数字存储到一堆对应的指针中。我如何从这些数字(0x00-0x03)映射到指针?还有,为什么不高效?
-
因为分散存储仍然会成为缓存未命中的瓶颈,或者如果不是像常规存储一样仍然限制为每个时钟 1 个元素。分散指令还解码为很多微指令(不仅仅是收集负载),因此它们会消耗前端吞吐量。您还必须检测冲突(当向量中的多个元素将进入同一个桶时,您需要将它们写入顺序地址,而不是相互踩踏,并且您必须将每个桶的位置计数器增加正确的数量.)
-
因此,与一次执行 1 个元素相比,SIMD 版本需要做的额外工作很多。也许通过高效的
vpconflictd(例如在 KNL 但不是 Skylake-avx512)你可以领先。这类似于直方图问题(您正在递增每个桶计数器的数组),但更难,因为您实际上仍然必须保留每个元素。 -
感谢您提供所有这些信息,非常感谢!我也想知道这种冲突情况,听起来 vpconflictd 是我们能得到的最接近的。我会做一些关于直方图问题的阅读,谢谢你的领导!
标签: c arrays x86 simd bucket-sort