与 SIMD 内在函数进行比较和交换
Posted
技术标签:
【中文标题】与 SIMD 内在函数进行比较和交换【英文标题】:Compare and swap with SIMD intrinsics 【发布时间】:2015-08-27 12:29:45 【问题描述】:如果发生某种情况,是否可以在 SIMD 指令中进行比较并交换值。换句话说,我有 4 个整数:
(100 5) (1 42)
我想收到:
(5 100) (1 42)
即我想成对比较(第一个值与第二个值,第三个与第四个值),如果左操作数更大 - 交换值。是否可以只使用 1 个 SIMD?
P.S.:这是我第一次尝试 SIMD,可能我使用了错误的术语 - 如果我错了,请纠正我。
【问题讨论】:
您正在研究 SIMD(或其他 wtv)的“明显方法”有什么问题? 是的,对不起,我忘了说我在做什么是为了学习。我正在尝试实现不同的排序算法并尽可能加快速度。 在不知道要谈论哪一组 SIMD(例如 SSE/AVX 或其他东西)的情况下,他们很难谈论 SIMD? 我不知道 - 有没有办法用 Visual Studio 进行检查?我知道我有 Intel Core i7 4930K - 它似乎支持 AVX,但我不知道是哪个版本。 @nikitablack AVX(1)(所以,不是 2)因为它是常春藤 【参考方案1】:对于支持 AVX2 的系统,有一个使用最小/最大并与 imm
混合的解决方案(它有 1 个周期延迟,而变量 1 有 2 个周期)。
以下代码有 3 个周期的延迟,并且在 HSW+ 上的吞吐量应该少于 2 个周期
__m128i tmp = _mm_shuffle_epi32(in, _MM_SHUFFLE(2,3,0,1));
__m128i min = _mm_min_epi32(in, tmp);
__m128i max = _mm_max_epi32(in, tmp);
// __m128i res = _mm_blend_epi32(min, max, 0xA); // AVX2 only
__m128i res = _mm_blend_epi16(min, max, 0xCC); // SSE4.1
我已经在我的 HSW 系统上对其进行了测试(处理 20000 对 100K 次),它的性能比 stgatilov
的代码高约 26%
CMP + VARIABLE BLEND 1.18sec
MIN/MAX + BLEND_32 0.87sec // AVX2 only code
MIN/MAX + BLEND_PS 0.86sec // SSE
MIN/MAX + PLEND_16 0.88sec // Preferred for SSE
更新:根据stgatilov
'下面的评论。所有 MIN/MAX 实现几乎都具有相同的性能(很可能只是卡在内存中)
【讨论】:
是的,使用 min/max 提供了一个更简单的解决方案。我认为这个解决方案可以适应 SSE4.1。只需使用_mm_blend_epi16
或_mm_blend_ps
而不是_mm_blend_epi32
(可能会造成一些延迟/吞吐量损失)。
@Elalfer 谢谢。你能解释一下循环延迟是什么意思吗?什么是HSW+?
@nikitablack 指令延迟 - 执行一条指令需要多少个周期,HSW+ - 是 Haswell 微架构及更高版本(Broadwell,Skylake) .您可以找到有关指令延迟和吞吐量的更多信息@software.intel.com/sites/landingpage/IntrinsicsGuide【参考方案2】:
您似乎想在单个 XMM 寄存器中对成对的 32 位整数进行排序。当然没有现成的指令,但您可以使用 SSE4.1 的一些指令来完成(注意:代码未测试):
//input = [100, 5, 1, 42]
__m128i swapped = _mm_shuffle_epi32(input, _MM_SHUFFLE(2,3,0,1)); // [5, 100, 42, 1]
__m128i comp = _mm_cmplt_epi32(input, swapped); // [0, -1, -1, 0]
comp = _mm_xor_si128(comp, _mm_set_epi32(-1, 0, -1, 0)); // [0, 0, -1, -1]
input = _mm_blendv_epi8(swapped, input, comp); // [5, 100, 1, 42]
在 Ivy Bridge 上似乎是 7 微指令,需要 2 个 CPU 周期(吞吐量)。
如果需要,它可以轻松移植到 AVX2。
【讨论】:
@nikitablack:转到英特尔内部指南并一一检查每个命令。这并不难理解。 BTW xor 指令可以用另一个 shuffle 替换。 谢谢,已经这样做了。你能提示一下如何用洗牌替换 xor - 我自己想不出来。我怎么知道要洗牌的元素? @nikitablack:比较结果会产生四个 32 位掩码。但是,第一个和第二个结果必须是互补的:(a (除非 a == b,在这种情况下任何掩码西装)。第三和第四个结果也是如此。现在我反转第二个和第四个蒙版,但您可以将第一个蒙版复制到第二个蒙版,将第三个蒙版复制到第四个蒙版。只需一次调用_mm_shuffle_epi32
即可完成此元素的注册内复制。以上是关于与 SIMD 内在函数进行比较和交换的主要内容,如果未能解决你的问题,请参考以下文章