【发布时间】:2011-12-11 17:45:34
【问题描述】:
我一直在通过实现特征选择算法来学习一些 Haskell。
我在基准数据集上的性能从 20 秒缩短到 5 秒,而 C 程序在 0.5 秒内处理相同的数据集。数据集可以在here 找到。要运行,请像这样调用编译后的二进制文件:./Mrmr 10 test_nci9_s3.csv。
代码是here,有兴趣优化mutualInfoInnerLoop:
mutualInfoInnerLoop :: Double -> Data.Vector.Unboxed.Vector (Int, Int) -> Double -> (Int, Int, Double) -> Double
mutualInfoInnerLoop n xys !acc (!i, !j, !px_py)
| n == 0 || px_py == 0 || pxy == 0 = acc
| otherwise = pxy * logBase 2 ( pxy / px_py ) + acc
where
pxy = ( fromIntegral . U.foldl' accumEq2 0 $ xys ) / n
accumEq2 :: Int -> (Int, Int) -> Int
accumEq2 !acc (!i', !j')
| i' == i && j' == j = acc + 1
| otherwise = acc
分析器说:
COST CENTRE MODULE %time %alloc
mutualInfoInnerLoop Main 75.0 47.9
mutualInfo Main 14.7 32.1
parseCsv Main 5.9 13.1
CAF GHC.Float 1.5 0.0
readInt Main 1.5 1.2
doMrmr Main 1.5 4.0
这表明mutualInfoInnerLoop 进行了50% 的分配,75% 的运行时间在程序中。分配令人不安。
此外,该函数的核心有一个签名:
mutualInfoInnerLoop_rXG
:: GHC.Types.Double
-> Data.Vector.Unboxed.Base.Vector (GHC.Types.Int, GHC.Types.Int)
-> GHC.Types.Double
-> (GHC.Types.Int, GHC.Types.Int, GHC.Types.Double)
-> GHC.Types.Double
[GblId,
Arity=4,
Caf=NoCafRefs,
Str=DmdType U(L)LU(L)U(U(L)U(L)U(L))m]
将大多数参数显示为延迟评估和装箱(与严格和未装箱相反)。
我尝试过 BangPatterns,我尝试过 MagicHash,但我似乎无法让它更快。
大家有什么建议吗?
【问题讨论】:
-
我猜你已经尝试过 ghc -O2 了?
-
是的,我有。源代码也用
{-# LANGUAGE BangPatterns #-}和{-# OPTIONS_GHC -O2 -fexcess-precision -funbox-strict-fields #-}注释 -
您能否提供
Int和您用于基准测试的文件? -
核心不足为奇。您已将
mutualInfoInnerLoop注释为 NOINLINE,因此 GHC 不会内联它。因此,没有一个论点可以被拆箱。如果将NOINLINE更改为INLINE会发生什么? -
如果我们的想法是满足或击败 C 代码,那么我们也需要它。
标签: optimization haskell functional-programming