仍在Haskell的SHA1实现中工作。现在我有一个工作的实施,这是内部循环:优化Haskell内循环
iterateBlock' :: Int -> [Word32] -> Word32 -> Word32 -> Word32 -> Word32 -> Word32 -> [Word32]
iterateBlock' 80 ws a b c d e = [a, b, c, d, e]
iterateBlock' t (w:ws) a b c d e = iterateBlock' (t+1) ws a' b' c' d' e'
where
a' = rotate a 5 + f t b c d + e + w + k t
b' = a
c' = rotate b 30
d' = c
e' = d
探查告诉我,这个函数需要我的实现的运行时间的1/3。我可以想象没有办法进一步优化它,除了可能内联临时变量,但我相信-O2无论如何会为我做到这一点。
任何人都可以看到可以进一步应用的重要优化?
仅供参考k和f调用低于。他们非常简单,我认为没有办法优化这些。除非Data.Bits模块很慢?
f :: Int -> Word32 -> Word32 -> Word32 -> Word32
f t b c d
| t <= 19 = (b .&. c) .|. ((complement b) .&. d)
| t <= 39 = b `xor` c `xor` d
| t <= 59 = (b .&. c) .|. (b .&. d) .|. (c .&. d)
| otherwise = b `xor` c `xor` d
k :: Int -> Word32
k t
| t <= 19 = 0x5A827999
| t <= 39 = 0x6ED9EBA1
| t <= 59 = 0x8F1BBCDC
| otherwise = 0xCA62C1D6
没有尝试,我猜很多问题是保持您的块数据列表(太多点/内存流量)。我会努力转移到“Word32”的一个未装箱的向量,并手动展开循环。除此之外,请用一个严格/不包装的结构来保存'a','b','c','d'和'e';那么你只有一个需要通过的变量(并且你一定会在上面放置一个爆炸模式,对吧?)。 –
我也会尝试用表格查找替换所有'(<=)',但我不确定它会有多大帮助。 –
另一件事:在C中编写严格的算术函数并使用FFI调用它通常是一个好主意。如果您小心地引入无副作用,运行时可以使用快速调用C语言来提供良好的性能。 – fuz