用于检查字节数组是否为零的SSE指令C#

假设我有一个byte[]并想检查所有字节是否为零。 For循环是一种显而易见的方法,而LINQ All()是一种奇特的方式,但最高性能至关重要。

如何使用Mono.Simd来加速检查字节数组是否满了零? 我正在寻找最前沿的方法,而不仅仅是正确的解决方案。

最佳代码如下。 完整的其他方法和时间测量。

 static unsafe bool BySimdUnrolled (byte[] data) { fixed (byte* bytes = data) { int len = data.Length; int rem = len % (16 * 16); Vector16b* b = (Vector16b*)bytes; Vector16b* e = (Vector16b*)(bytes + len - rem); Vector16b zero = Vector16b.Zero; while (b < e) { if ((*(b) | *(b + 1) | *(b + 2) | *(b + 3) | *(b + 4) | *(b + 5) | *(b + 6) | *(b + 7) | *(b + 8) | *(b + 9) | *(b + 10) | *(b + 11) | *(b + 12) | *(b + 13) | *(b + 14) | *(b + 15)) != zero) return false; b += 16; } for (int i = 0; i < rem; i++) if (data [len - 1 - i] != 0) return false; return true; } } 

最终被这段代码打败了:

 static unsafe bool ByFixedLongUnrolled (byte[] data) { fixed (byte* bytes = data) { int len = data.Length; int rem = len % (sizeof(long) * 16); long* b = (long*)bytes; long* e = (long*)(bytes + len - rem); while (b < e) { if ((*(b) | *(b + 1) | *(b + 2) | *(b + 3) | *(b + 4) | *(b + 5) | *(b + 6) | *(b + 7) | *(b + 8) | *(b + 9) | *(b + 10) | *(b + 11) | *(b + 12) | *(b + 13) | *(b + 14) | *(b + 15)) != 0) return false; b += 16; } for (int i = 0; i < rem; i++) if (data [len - 1 - i] != 0) return false; return true; } } 

时间测量(256MBarrays):

 LINQ All(b => b == 0) : 6350,4185 ms Foreach over byte[] : 580,4394 ms For with byte[].Length property : 809,7283 ms For with Length in local variable : 407,2158 ms For unrolled 16 times : 334,8038 ms For fixed byte* : 272,386 ms For fixed byte* unrolled 16 times : 141,2775 ms For fixed long* : 52,0284 ms For fixed long* unrolled 16 times : 25,9794 ms SIMD Vector16b equals Vector16b.Zero : 56,9328 ms SIMD Vector16b also unrolled 16 times : 32,6358 ms 

结论:

  • Mono.Simd只有一套有限的指令。 我没有找到计算标量和(向量)或最大值(向量)的指令。 然而,有向量相等运算符返回bool。
  • 循环展开是一种强大的技术。 即使是最快的代码也可以从中获益。
  • LINQ非常慢,因为它使用来自lambda表达式的委托。 如果你需要最先进的性能,那么显然这不是你要走的路。
  • 所有提出的方法都使用短路评估 ,这意味着它们一旦遇到非零就会结束。
  • SIMD代码最终遭到殴打。 关于SIMD是否真的让事情变得更快,还有其他问题。

在Peer Review上发布此代码 ,到目前为止发现并修复了2个错误。