翻转字节数组 – 提高性能

我有一些代码管理从传感器arrays接收的数据。控制传感器的PIC使用8个SAR-ADC并行读取4096个数据字节。 这意味着它读取前8个字节的最高有效位; 然后它读取第二位,依此类推,直到第八位(最低位)。
基本上,对于它读取的每8个字节,它创建(并向计算机发送)8个字节,如下所示:

// rxData[0] = MSB[7] MSB[6] MSB[5] MSB[4] MSB[3] MSB[2] MSB[1] MSB[0] // rxData[1] = B6[7] B6[6] B6[5] B6[4] B6[3] B6[2] B6[1] B6[0] // rxData[2] = B5[7] B5[6] B5[5] B5[4] B5[3] B5[2] B5[1] B5[0] // rxData[3] = B4[7] B4[6] B4[5] B4[4] B4[3] B4[2] B4[1] B4[0] // rxData[4] = B3[7] B3[6] B3[5] B3[4] B3[3] B3[2] B3[1] B3[0] // rxData[5] = B2[7] B2[6] B2[5] B2[4] B2[3] B2[2] B2[1] B2[0] // rxData[6] = B1[7] B1[6] B1[5] B1[4] B1[3] B1[2] B1[1] B1[0] // rxData[7] = LSB[7] LSB[6] LSB[5] LSB[4] LSB[3] LSB[2] LSB[1] LSB[0] 

对于系统读取和处理的所有4096个字节重复该模式。
想象一下,每个8字节读取是分开进行的,然后我们可以将它们视为8by8位数组。 我需要在从左下角(LSB [7])到右上角(MSB [0])的对角线周围镜像这个数组。 完成此操作后,生成的8by8位数组在其行中包含从传感器读取的正确数据字节。 我曾经在PIC控制器上执行此操作,使用左移等等,但这会大大减慢系统速度。 因此,现在使用以下代码在我们处理数据的计算机上执行此操作:

 BitArray ba = new BitArray(rxData); BitArray ba2 = new BitArray(ba.Count); for (int i = 0; i < ba.Count; i++) { ba2[i] = ba[(((int)(i / 64)) + 1) * 64 - 1 - (i % 8) * 8 - (int)(i / 8) + ((int)(i / 64)) * 8]; } byte[] data = new byte[rxData.Length]; ba2.CopyTo(data, 0); 

请注意,此代码有效。
rxData是接收的字节数组。
我用于循环中的ba []索引的公式代码用于上面描述的arrays的镜像。

在别处检查数组的大小,以确保它始终包含正确的字节数(4096)。

到目前为止,这是我的问题的背景。

在我的系统的每个处理循环中,我需要执行两次镜像,因为我的数据处理是连续获取的两个数组之间的差异。 速度对我的系统很重要(可能是处理的主要限制因素),镜像占我处理执行时间的10%到30%。

我想知道是否有其他解决方案可以与我的镜像代码进行比较,这可能会让我提高性能。 使用BitArrays是我找到的唯一方法来处理接收字节中的不同位。

谢谢

显而易见的解决方案是提取位并再次组合它们。 你可以用一个循环来做,但因为它同时使用左右移位,否则你需要一个负移位量,所以我展开它以便更容易理解和更快的速度

 out[0] = ((rxData[0] & 0x80) ) | ((rxData[1] & 0x80) >> 1) | ((rxData[2] & 0x80) >> 2) | ((rxData[3] & 0x80) >> 3) | ((rxData[4] & 0x80) >> 4) | ((rxData[5] & 0x80) >> 5) | ((rxData[6] & 0x80) >> 6) | ((rxData[7] & 0x80) >> 7); out[1] = ((rxData[0] & 0x40) << 1) | ((rxData[1] & 0x40) ) | ((rxData[2] & 0x40) >> 1) | ((rxData[3] & 0x40) >> 2) | ((rxData[4] & 0x40) >> 3) | ((rxData[5] & 0x40) >> 4) | ((rxData[6] & 0x40) >> 5) | ((rxData[7] & 0x40) >> 6); out[2] = ((rxData[0] & 0x20) << 2) | ((rxData[1] & 0x20) << 1) | ((rxData[2] & 0x20) ) | ((rxData[3] & 0x20) >> 1) | ((rxData[4] & 0x20) >> 2) | ((rxData[5] & 0x20) >> 3) | ((rxData[6] & 0x20) >> 4) | ((rxData[7] & 0x20) >> 5); out[3] = ((rxData[0] & 0x10) << 3) | ((rxData[1] & 0x10) << 2) | ((rxData[2] & 0x10) << 1) | ((rxData[3] & 0x10) ) | ((rxData[4] & 0x10) >> 1) | ((rxData[5] & 0x10) >> 2) | ((rxData[6] & 0x10) >> 3) | ((rxData[7] & 0x10) >> 4); out[4] = ((rxData[0] & 0x08) << 4) | ((rxData[1] & 0x08) << 3) | ((rxData[2] & 0x08) << 2) | ((rxData[3] & 0x08) << 1) | ((rxData[4] & 0x08) ) | ((rxData[5] & 0x08) >> 1) | ((rxData[6] & 0x08) >> 2) | ((rxData[7] & 0x08) >> 3); out[5] = ((rxData[0] & 0x04) << 5) | ((rxData[1] & 0x04) << 4) | ((rxData[2] & 0x04) << 3) | ((rxData[3] & 0x04) << 2) | ((rxData[4] & 0x04) << 1) | ((rxData[5] & 0x04) ) | ((rxData[6] & 0x04) >> 1) | ((rxData[7] & 0x04) >> 2); out[6] = ((rxData[0] & 0x02) << 6) | ((rxData[1] & 0x02) << 5) | ((rxData[2] & 0x02) << 4) | ((rxData[3] & 0x02) << 3) | ((rxData[4] & 0x02) << 2) | ((rxData[5] & 0x02) << 1) | ((rxData[6] & 0x02) ) | ((rxData[7] & 0x02) >> 1); out[7] = ((rxData[0] & 0x01) << 7) | ((rxData[1] & 0x01) << 6) | ((rxData[2] & 0x01) << 5) | ((rxData[3] & 0x01) << 4) | ((rxData[4] & 0x01) << 3) | ((rxData[5] & 0x01) << 2) | ((rxData[6] & 0x01) << 1) | ((rxData[7] & 0x01) ); 

您可能会发现BitVector比BitArray执行得更好。

对于布尔值和内部使用的小整数,BitVector32比BitArray更有效。 BitArray可以根据需要无限增长,但它具有类实例所需的内存和性能开销。 相反,BitVector32仅使用32位。

http://msdn.microsoft.com/en-us/library/system.collections.specialized.bitvector32.aspx

如果你初始化一个BitVector32数组并对它们进行操作,那么它应该比你现在操作BitArray更快。

如果使用一个线程执行镜像,则第二个线程可以执行连续读取分析,也可以提高性能。 任务并行库数据流为该类型的解决方案提供了一个很好的框架。 您可以使用一个源块来获取数据缓冲区,使用一个转换块来执行镜像,使用一个目标块来执行数据处理。

这实际上与位板问题中的get列相同,因此通过将字节数组视为64位整数可以更有效地解决它

 byte get_byte(ulong matrix, uint col) { const ulong column_mask = 0x8080808080808080ull; const ulong magic = 0x2040810204081ull; ulong column = ((matrix << col) & column_mask) * magic; return (byte)(column >> 56); } // Actually the below step is not needed. You can read rxData directly into the `ulong` // variable instead of a bit array. Remember to CHANGE THE ENDIANNESS if necessary ulong matrix = (rxData[7] << 56) | (rxData[6] << 48) | (rxData[5] << 40) | (rxData[4] << 32) | (rxData[3] << 24) | (rxData[2] << 16) | (rxData[1] << 8) | rxData[0]; for (int i = 0; i < 8; i++) data[i] = get_byte(matrix, i); 

在较新的x86 CPU中,您可以使用BMI2指令集中的PDEP指令。 我不确定C#中是否有任何相应的内在函数。 如果内在不存在,那么你必须使用这样的本机代码

 data[i] = _pext_u64(matrix, column_mask << col);