【发布时间】:2012-04-26 21:15:07
【问题描述】:
我一直在为 GHC 中的低级手动循环优化而苦苦挣扎。我的程序包含一些执行数值计算的循环。真实数据被包装在其他数据结构中,程序被分解为“循环控制流函数”和“计算函数”,这样一些数据结构字段最终会在内部循环中被读取。我希望 GHC 将这些读数移出内部循环。这是代码的简化版本,用于显示发生了什么。
data D = D !Double !C
data C = C Double
-- This function is called in every loop iteration.
-- Parameter 'c' is loop-invariant.
exampleLoopBody i a c =
case c of C b -> a + b * fromIntegral i
-- The body of this function is a counted loop that should be optimized
foo x =
case x
of D acc0 c ->
let loop i acc =
if i > 100
then acc
else loop (i+1) (exampleLoopBody i acc c)
in loop 0 acc0
每次循环迭代都会计算case c of C b,但这是冗余计算,因为c 是循环不变的。我可以通过在循环之外放置一个冗余的 case 表达式来让 GHC 将其解除:
foo x =
case x
of D acc0 c ->
case c -- This case statement inserted for optimization purposes
of C b -> b `seq` -- It will read 'b' outside of the loop
let loop i acc =
if i > 100
then acc
else loop (i+1) (exampleLoopBody i acc c)
in loop 0 acc0
编译器内联exampleLoopBody。之后,内部 case 语句是多余的并被消除:
foo x =
case x
of D acc0 c ->
case c
of C b -> b `seq`
let loop i acc =
if i > 100
then acc
else loop (i+1) (acc + b * fromIntegral i) -- The inlined case expression disappears
in loop 0 acc0
seq 的目的是确保 case 表达式不是死代码。 seq 检查b 是否为_|_。 GHC 注意到,由于 b 已被计算,因此在循环体中重用该值很有用。
现在,问题来了:我真的希望所有相关的数据字段都是严格的。如果我在数据定义中插入严格注释,像这样,
data C = C !Double
那么就 GHC 而言,seq 和 case c of C b 无效。 GHC 删除了它们,我明白了:
foo x =
case x
of D acc0 c ->
let loop i acc =
if i > 100
then acc
else loop (i+1) (case c of C b -> acc + b * fromIntegral i) -- Evaluate the case in every iteration
in loop 0 acc0
这段代码在每次迭代中都会评估case c of C b,这正是我试图避免的。
如果我不能依赖seq,我不知道如何强制b 在循环体之外计算。在这种情况下我可以使用一些技巧吗?
【问题讨论】:
-
您使用的是哪个 GHC 版本?在 7.4.1 和 7.2.2 的每次迭代中,如果没有
case,我都会得到很好的核心。纯未装箱Double#s. -
@DanielFischer 我使用的是 7.0.3,在通过简化程序后,
Doubles 之一被装箱。仅供参考,我的真实用例实际上涉及静态大小的向量,例如Cons Double (Cons Double Nil)。我可以尝试在较新的 GHC 中运行它,看看会发生什么。 -
嗯,我也得到了 7.0.4 的未装箱循环。
$wfoo工人有一个装箱的参数(也有 7.4.1 和 7.2.2),但循环本身是letreced 在里面并采用未装箱的Double#(另一个Double#是静态的,甚至)。 -
是的,
$wfoo为我提供了一个装箱参数,循环获取并返回未装箱的Double#s。$wfoo的 boxed 参数被循环体内的case拆箱。 -
对我来说,
case在循环体之外。它可能是 32 位与 64 位的东西吗?你的操作系统是什么?
标签: optimization haskell