forked from ku-fpg/hermit-streamfusion
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Concat.hs
142 lines (126 loc) · 4.79 KB
/
Concat.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
{-# LANGUAGE BangPatterns, RankNTypes #-}
{-# OPTIONS_GHC -funbox-strict-fields #-}
{-# OPTIONS_GHC -fspec-constr #-}
{-# OPTIONS_GHC -fdicts-cheap #-}
{- OPTIONS_GHC -optlo-globalopt #-}
{- OPTIONS_GHC -optlo-loop-unswitch #-}
{- OPTIONS_GHC -optlo-mem2reg #-}
{- OPTIONS_GHC -optlo-prune-eh #-}
{-# OPTIONS_GHC -optlo-O3 -optlc-O3 #-} -- this is fast...
module Main where
import Data.Vector as V
import GHC.Enum as E
import Data.Vector.Fusion.Stream as VS
import Data.Vector.Fusion.Stream.Monadic as M
import Data.Vector.Fusion.Stream.Size as VS
import Criterion.Main as C
import Control.Monad.ST
import qualified Data.Vector.Unboxed.Mutable as VUM
import qualified Data.Vector.Unboxed as VU
import HERMIT.Optimization.StreamFusion.Vector
-- | Note: Data.Vector.concatMap = Data.Vector.Generic.concatMap
-- which is implemented in terms of flatten (with entire
-- inner vector in state, so not properly fused).
-- We cannot hope to optimize this.
concatTestV :: Int -> Int
concatTestV n = V.sum $ V.concatMap (\(!x) -> V.enumFromN 1 x) $ V.enumFromN 1 n
{-# NOINLINE concatTestV #-}
concatTestS :: Int -> Int
concatTestS n = VS.foldl' (+) 0 $ VS.concatMap (\(!x) -> VS.enumFromStepN 1 1 x) $ VS.enumFromStepN 1 1 n
{-# NOINLINE concatTestS #-}
-- | And again, this time we flatten the resulting stream. If this is fast
-- (enough), we can start the fusion process on ADP.
--
-- NOTE This does actually reduce to the desired tight loop.
flattenTest :: Int -> Int
flattenTest !n = VS.foldl' (+) 0 $ VS.flatten mk step Unknown $ VS.enumFromStepN 1 1 n
where
mk !x = (1,x)
{-# INLINE mk #-}
step (!i,!max)
| i<=max = VS.Yield i (i+1,max)
-- | max>(0::Int) = VS.Yield i (i+1,max-1) -- 10% faster
| otherwise = VS.Done
{-# INLINE step #-}
{-# NOINLINE flattenTest #-}
flattenTestDown :: Int -> Int
flattenTestDown !n = VS.foldl' (+) 0 $ VS.flatten mk step Unknown $ VS.enumFromStepN 1 1 n
where
mk !x = (x,1)
{-# INLINE mk #-}
step (!i,!min)
| i>=min = VS.Yield i (i-1,min)
| otherwise = VS.Done
{-# INLINE step #-}
{-# NOINLINE flattenTestDown #-}
-- nestedConcatS 3 = sum [1,1,2,2,1,2,3,2,3,3]
nestedConcatS :: Int -> Int
nestedConcatS n = VS.foldl' (+) 0 $ VS.concatMap (\(!x) -> VS.concatMap (\(!y) -> VS.enumFromStepN y 1 x) $ VS.enumFromStepN 1 1 x) $ VS.enumFromStepN 1 1 n
{-# NOINLINE nestedConcatS #-}
concatMapMonadic :: Int -> Int
concatMapMonadic k = runST $ do
tbl <- VU.thaw $ VU.fromList [0 .. k]
M.foldl' (+) 0 $ M.concatMapM (\(!x) -> VUM.unsafeRead tbl x >>= \z -> return $ M.enumFromStepN 1 1 z) $ M.enumFromStepN 1 1 k
{-# NOINLINE concatMapMonadic #-}
{-
nestedFlatten :: Int -> Int
nestedFlatten !n = VS.foldl' (+) 0 $ VS.flatten mk step Unknown $ VS.enumFromStepN 1 1 n
where
mk !x = (1,1,x)
{-# INLINE mk #-}
step (!i,!j,!x)
| (i<=x) && (j<=i) = VS.Yield j (i,j+1,x)
| i<=x = VS.Skip (i+1,1,x)
| otherwise = VS.Done
{-# INLINE step #-}
{-# NOINLINE nestedFlatten #-}
-}
main = do
-- print $ concatTestV 1000
print $ concatTestS 1000
print $ flattenTest 1000
print $ concatMapMonadic 1000
-- print $ flattenTestDown 1000
putStrLn $ "nestedConcatS: " Prelude.++ (show $ nestedConcatS 100)
-- putStrLn $ "nestedFlatten: " Prelude.++ (show $ nestedFlatten 100)
defaultMain
[ bgroup "concat tests / 100"
[ bench "concatTestS" $ whnf concatTestS 100
-- , bench "concatTestV" $ whnf concatTestV 100
, bench "flattenTest" $ whnf flattenTest 100
, bench "concatMapMonadic" $ whnf concatMapMonadic 100
]
, bgroup "concat tests / 1000"
[ bench "concatTestS" $ whnf concatTestS 1000
-- , bench "concatTestV" $ whnf concatTestV 1000
, bench "flattenTest" $ whnf flattenTest 1000
, bench "concatMapMonadic" $ whnf concatMapMonadic 1000
]
{- for paper
, bgroup "concat tests / 5000"
[ bench "concatTestS" $ whnf concatTestS 5000
, bench "flattenTest" $ whnf flattenTest 5000
]
, bgroup "concat tests / 10000"
[ bench "concatTestS" $ whnf concatTestS 10000
, bench "flattenTest" $ whnf flattenTest 10000
]
, bgroup "concat tests / 20000"
[ bench "concatTestS" $ whnf concatTestS 20000
, bench "flattenTest" $ whnf flattenTest 20000
]
-}
, bgroup "nested tests / 100"
[ bench "nestedConcatS" $ whnf nestedConcatS 100
]
{-
, bgroup "nested tests / 10"
[ bench "nestedConcatS" $ whnf nestedConcatS 10
, bench "nestedFlatten" $ whnf nestedFlatten 10
]
, bgroup "nested tests / 100"
[ bench "nestedConcatS" $ whnf nestedConcatS 100
, bench "nestedFlatten" $ whnf nestedFlatten 100
]
-}
]