【发布时间】:2011-11-15 19:36:35
【问题描述】:
来自previous 的另一个 Haskell 优化问题。我需要递归生成一个列表,类似于许多介绍性 Haskell 文章中的 fibs 函数:
generateSchedule :: [Word32] -> [Word32]
generateSchedule blkw = take 80 ws
where
ws = blkw ++ zipWith4 gen (drop 13 ws) (drop 8 ws) (drop 2 ws) ws
gen a b c d = rotate (a `xor` b `xor` c `xor` d) 1
对我来说,上述函数已成为最耗时和最耗费分配的函数。探查器给了我以下统计数据:
COST CENTRE MODULE %time %alloc ticks bytes
generateSchedule Test.Hash.SHA1 22.1 40.4 31 702556640
我曾想过应用未装箱的向量来计算列表,但由于列表是递归的,因此无法找到方法。这在 C 中会有一个自然的实现,但我看不出有什么方法可以让它更快(除了展开和编写 80 行变量声明)。有什么帮助吗?
更新:实际上我确实快速展开它以查看它是否有帮助。代码是here。它很丑,实际上它更慢。
COST CENTRE MODULE %time %alloc ticks bytes
generateSchedule GG.Hash.SHA1 22.7 27.6 40 394270592
【问题讨论】:
-
我仍然认为您需要完全放弃列表。不仅仅是作为中介,将您的数据输入为
ByteString并使用 Data.Vector.Storable 或类似的。当输入是单词列表时,我认为优化没有多大意义。如果你完全展开partcb,那么你甚至不需要这个generateSchedule函数(partab);在展开时它将是明确的(内联的)。另外:您为此付出了足够的努力,我对目标感到好奇-是教育还是您想在生产代码中使用实现?如果#2,是否有理由避免cryptohash? -
教育。我想知道我是否可以编写干净、惯用的 Haskell,它的速度相当,而无需求助于让我希望我只是用 C 语言编写的优化技巧。在 SHA1 的情况下,我开始觉得情况就是这样。我还查看了Data.Digest.Pure.SHA 的来源。这很棒——速度是 C 实现速度的 2-3 倍。但这不是我想写的那种代码。
-
仅供参考我的完整最新代码here。
-
只需解压 Vec160 结构(在每个
Word32字段之前使用{-# UNPACK #-}pragma),即可获得 23% 的廉价提升 -
你确定
generateSchedule实际上是这里的瓶颈吗?如果blkw尚未评估,评估它的成本可能会归于generateSchedule。如果它被评估,那么用列表表示它可能不是正确的事情。
标签: optimization haskell