我有一个非递归函数,用于计算最长公共子序列,经过测试表现良好(使用ghc 7.6.1
编译并使用-O2 -fllvm
标志),如果在同一模块中使用Criterion
进行测量。另一方面,如果我将该函数转换为模块,仅导出该函数(按照这里的建议),然后再次使用Criterion进行测量,则会出现约2倍的减速(如果我将 Criterion 测试移回定义函数的模块,则问题消失)。我尝试使用INLINE
pragma标记该函数,但它对跨模块性能测量没有任何影响。
在我看来,GHC可能正在执行严格性分析,当函数和主要函数(从中可以调用该函数)位于同一模块中时,这种分析效果很好,但是当它们分开时则不行。我希望能指导如何将该功能模块化,以便在从其他模块调用时能够良好地运行。有关代码过长无法在此粘贴-如果您想尝试,请在此处查看。以下是我尝试做的小例子(包括代码片段):
-- Function to find longest common subsequence given unboxed vectors a and b
-- It returns indices of LCS in a and b
lcs :: (U.Unbox a, Eq a) => Vector a -> Vector a -> (Vector Int,Vector Int)
lcs a b | (U.length a > U.length b) = lcsh b a True
| otherwise = lcsh a b False
-- This section below measures performance of lcs function - if I move it to
-- a different module, performance degrades ~2x - mean goes from ~1.25us to ~2.4us
-- on my test machine
{--
config :: Config
config = defaultConfig { cfgSamples = ljust 100 }
a = U.fromList ['a'..'j'] :: Vector Char
b = U.fromList ['a'..'k'] :: Vector Char
suite :: [Benchmark]
suite = [
bench "lcs 10" $ whnf (lcs a) b
]
main :: IO()
main = defaultMainWith config (return ()) suite
--}
a
专门化为Char
,因为它从未与任何其他类型一起使用,这样可以消除类型类的开销。你可以尝试玩弄一下SPECIALIZE
修饰符(或手动更改为Char
),看看是否有任何效果。 - hammarSPECIALIZE
/INLINE
/INLINEABLE
。类似的程序存在吗?它本质上应该是名称混淆,对吗? - gspr