我应该期望Data.Vector融合以下功能吗?

时间:2017-02-21 13:39:48

标签: haskell haskell-vector

我最近开始使用Data.Vector。我的理解是它应该能够采用矢量操作链并通过融合有效地组合它们。

特别是,我希望这两个函数具有相似的性能特征(即searchTopDown融合到像searchTd这样的东西)。

import qualified Data.Vector.Unboxed as VU
import Data.Vector.Unboxed (fromList, (!))

--| Going down from i searches the vector for the element satisfying predicate 
searchTopDown :: VU.Vector Int -> Int -> (Int -> Bool) -> (Int, Int)
searchTopDown vec i pred =
    VU.head $ VU.dropWhile (not . pred . snd)
    $ VU.reverse $ VU.take (1 + i)
    $ VU.indexed vec

searchTd :: VU.Vector Int -> Int -> (Int -> Bool) -> (Int, Int)
searchTd vec i pred = let val = vec ! i
                    in
                      if pred val then (i,  val) else searchTd vec (i-1) pred

但是,对此代码进行基准测试会显示数量级的性能差异。

testTd/150
                 lower bound    estimate    upper bound
OLS regression      4.51 μs     4.53 μs     4.56 μs
R² goodness-of-fit  1.000       1.000       1.000
Mean execution time 4.52 μs     4.53 μs     4.55 μs
Standard deviation  35.2 ns     50.0 ns     69.8 ns

topDown/150
                 lower  bound    estimate    upper bound
OLS regression     75.4 μs       76.6 μs     77.9 μs
R² goodness-of-fit  0.997        0.998       0.999
Mean execution time 74.6 μs      75.2 μs     76.1 μs
Standard deviation  1.58 μs      2.42 μs     3.75 μs

问题:是什么阻止了searchTopDown被融合?我该怎么做才能帮助融合?什么时候我应该期待融合?

用于基准测试的代码:

import qualified Data.List as L
import Criterion.Main

vec :: VU.Vector Int
vec = fromList $ L.replicate 100 (-1) L.++ L.replicate 100 1

testTd :: Int -> Int
testTd i = fst $ searchTd vec i (<0)

testTopDown :: Int -> Int
testTopDown i = fst $ searchTopDown vec i (<0)


benchMain = defaultMain [
     bgroup "testTd"    [ bench "1"  $ whnf testTd 1
                        , bench "90"  $ whnf testTd 90
                        , bench "100"  $ whnf testTd 100
                        , bench "150" $ whnf testTd 150
      ],
      bgroup "topDown"  [ bench "1"  $ whnf testTopDown 1
                        , bench "90"  $ whnf testTopDown 90
                        , bench "100"  $ whnf testTopDown 100
                        , bench "150" $ whnf testTopDown 150
      ]
  ]

修改 遵循@Zeta建议(添加-O2)我从这两个函数中获得了出色的性能。但是,我在一个更大的项目中遇到了这个问题,因此我将基准测试代码更改为类似于它。对于这种情况,searchTopDown似乎是i的线性。新的基准测试代码和结果(以微秒为单位):

import Data.Vector.Unboxed (fromList, (!))
import qualified Data.Vector.Unboxed as VU
import qualified Data.Vector.Unboxed.Mutable as VM
import Control.Monad.ST
import qualified Data.List as L

datStream :: [(Int, Int)]
datStream = L.zip [0..] $ L.replicate 100 (-1) L.++ L.replicate 100 1

vecUpdate v (iChg, vChg) = runST $ do
    mv <- VU.unsafeThaw v
    VM.modify mv (+ vChg) iChg
    VU.unsafeFreeze mv

vecs :: [VU.Vector Int]
vecs = let vecInit = VU.replicate 200 0 in L.drop 1 $ L.scanl' vecUpdate vecInit datStream

test f i = L.sum $ L.map (\x -> fst $ f x i (<0)) vecs
testTd = test searchTd
testTopDown = test searchTopDown

enter image description here

0 个答案:

没有答案