基于SSE4.2的加速计算crc32-c的一个小技巧
CRC32c(CRC32-Castagnoli), 是CRC32诸多变种中的一种, 由于其在之前主要应用于iSCI协议中, 所以CRC32-C又名crc32_iscsi(emm, 其实这是Intel给它起的名字, 在intel/isa-l代码中crc32_iscsi其实就是CRC32-Castagnoli).
由于这个指令广泛应用于存储, 网络等领域, 许多CPU架构会对这个CRC32c做硬件加速(都什么年代了, 还在用传统查表法).
以amd64为例, 在sse4.2中, 存在一个指令名为"crc32", 其实就是CRC32c的硬件加速指令, 通过这个指令, 可以获得比查表法快得多的计算速度.
根据Intel的一篇论文"Fast CRC Computation for iSCSI Polynomial Using CRC32 Instruction".
crc32指令一次最多可以处理8byte数据, 但是, 在一些intel的硬件实现中, 执行一次这条指令需要3个周期.
不过, 由于CPU的流水线特性, 如果三个连续的crc32指令间不存在数据依赖的话, 那么就可以让这三个指令流水线化执行, 从而使得执行一次crc32指令的周期无限接近于1.
所以说, 严格来说也算不上优化啦, 只是顺从硬件的特性而已.
但是, 我们知道, CRC运算是要从头顺序地计算到尾的, 如果是三份独立的数据倒是简单, 但是对于一块大数据来说, 就不能简单地切成三块来算了.
不过, 这里还是有一些trick可以做的, CRC的计算过程我这里就不详细展开了(假设大家懂得都懂:P), 我们假设 CRC(I, X) 是CRC32的一个计算函数, 其中, I是初值, X是我们要计算的数据.
那么, CRC(I, X)有下列性质:
CRC(I, AB) = CRC(CRC(I, A), B)CRC(I, A xor B) = CRC(I, A) xor CRC(0, B)
所以, 假如我们有ABC三段长度相同的数据(假如长度为K)需要计算, 那么有
CRC(I, ABC) = CRC(I, AB0 xor 00C)
= CRC(I, AB0) xor CRC(0, C)
= CRC(CRC(I, AB), 0) xor CRC(0, C)
= CRC(CRC(I, AO xor B), O) xor CRC(0, C)
= CRC(CRC(I, AO) xor CRC(0, B), O) xor CRC(0, C)
= CRC(CRC(CRC(I, A), O) xor CRC(0, B), O) xor CRC(0, C)
注意, 这里的0是长度与A,B,C相等的全零数据段
到这里, 我们需要计算的就是 CRC(I, A), CRC(0, B) 以及 CRC(0, C). 这里, 就可以通过我们上面提到的crc32汇编指令, 将数据拆分成三个不相关的数据流, 一起计算, 从而让CPU能够平均一个周期即可计算一次数据, 避免CPU流水线排空的发生.
在计算完成后, 我们还需要将三组数据联合在一起, 我们以聚合CRC(I, A) 和 CRC(0, B)为例:
CRC(I, AB) = CRC(CRC(I, A), O) xor CRC(0, B)
在这里, 我们需要将CRC(I, A)作为初始值, 计算长度为B的全零数据, 然后再将数据与CRC(0, B)异或即可.
用crc32指令直接计算CRC(X, 0) (X=CRC(I,A))就行, 不过还是会出现CPU的停顿, 或者, 这里还有一个小trick, 我们知道, 即使是计算全为0的数据, 由于初始值的存在, 会让不同长度的全零数据有着不同的计算结果, 由于我们假设了数据段长度都是K, 那么, 我们也许可以提前计算出所有可能初始值计算长度为K全零数据的结果?
但是, 初始值的长度是32位, 如果我们使用一个大小为4G的表, 那显然太蠢了, 其实CRC还有一个性质我们没有利用. 假设abcd各是8bit的数字, 那么abcd就是32位, 有:
CRC(abcd, 0) = CRC(a000, 0) xor CRC(0b00, 0) xor CRC(00c0, 0) xor CRC(000d, 0)
注意, 这里a000中的0与后面的0意义不同, "a000"代表一个32位的数字, 而后面的0依旧是长度为K的全零数据段.
通过这个技巧, 我们可以将2^32大小的查表法, 拆分为4个2^8大小的表, 从而加速这个聚合的过程.
接着, 通过同样的方法, 聚合CRC(I, AB)和CRC(0, C).
这样, 通过这两个trick, 我们在使用Intel CPU计算CRC32c时, 就可以让速度从单纯使用crc指令提高接近三倍啦.

浙公网安备 33010602011771号