2015-10-23 54 views
-1

I posted检查字节[]为全零的方法。 Mono.Simd提供如此高的性能,我想知道这是否可能。SSE指令违反RAM理论带宽

static unsafe bool IsAllZeros(byte[] data) 
{ 
    fixed (byte* bytes = data) { 
     int len = data.Length; 
     int rem = len % (16*16); 
     Vector16b* b = (Vector16b*)bytes; 
     Vector16b* e = b + len/(16*16); 
     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; 
    } 
} 

上述代码256 MB在2,6477毫秒提供94 GB/s。 这甚至可能吗?

我的DDR2内存具有800 Mhz的频率。 Wikipedia给出了理论最大带宽为800M * 2 * 64 * 2 = 25GB/s的公式。

+0

你只处理数组的1/16。 –

+0

也是'b + = 16'正确吗?它不应该是'b ++'吗? –

+0

循环在一次迭代中处理16个向量,这就是为什么它会移动16个。顺便说一下,您应该将其发布到代码审阅页面上。 https://codereview.stackexchange.com/questions/108470/sse-instruction-to-check-if-byte-array-is-zeroes-c – ArekBulski

回答

3

这是很好的,你做了带宽计算,因为它暴露了算法中的一个主要错误 - 循环在达到e时结束,这只是通过输入方式的1/16。

系统中的实际最大理论带宽仅略低于12.8 GB/s(DDR2/6400等级,两个通道的时间减去DRAM忙于刷新并且无法访问的几个周期) 。这与您的问题中的计算不同,因为您对DDR使用了两个因子,并将其应用于已包含该因子的数字。

算法的带宽为每2.65 ms或6.0 GB/s(假设未找到非零元素,因此需要扫描整个阵列)为16MB,约为理论极限的一半。即使使用Mono-SIMD编织器,对于未编译的C#也是一样。

+0

SIMD代码最终被殴打。目前的记录是每26毫秒256MB或9.8GB/s的带宽。 – ArekBulski