Skip to content

Commit 8535b03

Browse files
author
Jaro Reinders
committed
Small fixes and add sieve bench
1 parent a12c7c5 commit 8535b03

File tree

7 files changed

+142
-49
lines changed

7 files changed

+142
-49
lines changed

bench/Bench.hs

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import qualified Array
33
import Test.Tasty.Bench
44
import qualified Fleet.Array as Fleet
55
import Quicksort (quicksort)
6-
import qualified QuicksortA
6+
import qualified QuicksortMA
77
import qualified QuicksortIM
88
import qualified Data.List as List
9+
import qualified Eratosthenes as Fleet
10+
import qualified EratosthenesMA as MA
911

1012
class Indexable a where
1113
(!) :: a -> Int -> Int
@@ -49,18 +51,27 @@ main = do
4951
!arr2 = Fleet.set 0 0 arr3
5052
!arr1 = Fleet.set 0 0 arr2
5153
!arr0 = Fleet.set 0 0 arr1
52-
!marr <- QuicksortA.fromList list
54+
!marr <- QuicksortMA.fromList list
5355
defaultMain
54-
[ bench "array" $ whnf fooA (Array.fromList list)
55-
, bench "fleet" $ whnf fooDA arr0
56-
, bench "fleet 1" $ whnf fooDA arr1
57-
, bench "fleet 2" $ whnf fooDA arr2
58-
, bench "fleet 5" $ whnf fooDA arr5
59-
, bench "fleet 7" $ whnf fooDA arr7
60-
, bench "fleet 10" $ whnf fooDA arr10
61-
, bench "quicksort array" $ whnfIO (QuicksortA.clone marr >>= \marr' -> QuicksortA.quicksort marr' 0 9973)
62-
, bench "quicksort fleet" $ whnf (Quicksort.quicksort 0 9973) (Fleet.copy arr0)
63-
, bench "quicksort fleet copy" $ whnf (Quicksort.quicksort 0 9973 . Fleet.copy) arr0
64-
, bench "quicksort intmap" $ whnf (QuicksortIM.quicksort 0 9973) (QuicksortIM.fromList list)
65-
, bench "sort" $ nf (\xs -> List.sort xs) list
56+
[ bgroup "read"
57+
[ bench "array" $ whnf fooA (Array.fromList list)
58+
, bench "fleet" $ whnf fooDA arr0
59+
-- reading old versions:
60+
, bench "fleet 1" $ whnf fooDA arr1
61+
, bench "fleet 2" $ whnf fooDA arr2
62+
, bench "fleet 5" $ whnf fooDA arr5
63+
, bench "fleet 7" $ whnf fooDA arr7
64+
, bench "fleet 10" $ whnf fooDA arr10
65+
]
66+
, bgroup "quicksort"
67+
[ bench "MutArr" $ whnfIO (QuicksortMA.clone marr >>= \marr' -> QuicksortMA.quicksort marr' 0 9973)
68+
, bench "Fleet" $ whnf (Quicksort.quicksort 0 9973) (Fleet.copy arr0)
69+
, bench "Fleet copy" $ whnf (Quicksort.quicksort 0 9973 . Fleet.copy) arr0
70+
, bench "IntMap" $ whnf (QuicksortIM.quicksort 0 9973) (QuicksortIM.fromList list)
71+
, bench "List.sort" $ nf (\xs -> List.sort xs) list
72+
]
73+
, bgroup "sieve"
74+
[ bench "fleet" $ nf Fleet.sieve 100000
75+
, bench "MutArr" $ nfIO (MA.sieve 100000)
76+
]
6677
]

bench/Eratosthenes.hs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{-# OPTIONS_GHC -O2 #-}
2+
module Eratosthenes where
3+
4+
import Fleet.Array as Fleet
5+
6+
sieve :: Int -> [Int]
7+
sieve n = go 2 (Fleet.replicate (n + 1) True) where
8+
go !p !xs
9+
| p > n = []
10+
| xs ! p = p : go (p + 1) (go' p (p + p) xs)
11+
| otherwise = go (p + 1) xs
12+
go' !d !i !xs
13+
| i > n = xs
14+
| otherwise = go' d (i + d) (set i False xs)

bench/EratosthenesMA.hs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{-# OPTIONS_GHC -ddump-simpl -ddump-to-file -dsuppress-all -dno-suppress-type-signatures -dno-typeable-binds -ddump-stg-final -ddump-stg-from-core -ddump-prep #-}
2+
{-# OPTIONS_GHC -O2 #-}
3+
module EratosthenesMA where
4+
5+
import MutArr as MA
6+
7+
sieve :: Int -> IO [Int]
8+
sieve n = do
9+
arr <- MA.replicate (n + 1) True
10+
go arr 2
11+
where
12+
go :: MutArr Bool -> Int -> IO [Int]
13+
go !ma !p
14+
| p > n = pure []
15+
| otherwise = do
16+
isPrime <- readMA ma p
17+
if isPrime then do
18+
go' ma p (p + p)
19+
xs <- go ma (p + 1)
20+
pure (p : xs)
21+
else
22+
go ma (p + 1)
23+
go' ma d i
24+
| i > n = pure ()
25+
| otherwise = do
26+
writeMA ma i False
27+
go' ma d (i + d)

bench/QuicksortA.hs renamed to bench/MutArr.hs

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
{-# LANGUAGE MagicHash, UnboxedTuples #-}
2-
{-# OPTIONS_GHC -Wno-name-shadowing -ddump-simpl -ddump-to-file -dsuppress-all -dno-suppress-type-signatures -dno-typeable-binds #-}
3-
module QuicksortA (MutArr, fromList, toList, clone, quicksort) where
2+
module MutArr where
43

5-
import GHC.Exts hiding (fromList, toList)
6-
import GHC.IO (IO (IO))
4+
import GHC.Exts
5+
import GHC.Base
76

87
data MutArr a = MA (MutableArray# RealWorld a)
98

@@ -22,6 +21,11 @@ fromList xs = IO $ \s ->
2221
go arr _ [] s = (# s, MA arr #)
2322
go arr i (x:xs) s = go arr (i +# 1#) xs (writeArray# arr i x s)
2423

24+
replicate :: Int -> a -> IO (MutArr a)
25+
replicate (I# n) x = IO $ \s ->
26+
case newArray# n x s of
27+
(# s', arr #) -> (# s', MA arr #)
28+
2529
toList :: MutArr a -> IO [a]
2630
toList (MA arr) = IO $ \s ->
2731
let
@@ -48,26 +52,3 @@ swap !arr !i !j = do
4852
y <- readMA arr j
4953
writeMA arr i y
5054
writeMA arr j x
51-
52-
{-# INLINEABLE quicksort #-}
53-
quicksort :: Ord a => MutArr a -> Int -> Int -> IO ()
54-
quicksort !arr !l !r
55-
| r - l <= 1 = pure ()
56-
| otherwise = do
57-
x <- readMA arr (r - 1)
58-
m <- partition arr l (r - 1) x
59-
swap arr (r - 1) m
60-
quicksort arr (m + 1) r
61-
quicksort arr l m
62-
63-
{-# INLINEABLE partition #-}
64-
partition :: Ord a => MutArr a -> Int -> Int -> a -> IO Int
65-
partition arr l r x = go arr l l where
66-
go !arr !m !i
67-
| i == r = pure m
68-
| otherwise = do
69-
y <- readMA arr i
70-
if y <= x then do
71-
swap arr i m
72-
go arr (m + 1) (i + 1)
73-
else go arr m (i + 1)

bench/QuicksortMA.hs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{-# LANGUAGE MagicHash, UnboxedTuples #-}
2+
{-# OPTIONS_GHC -Wno-name-shadowing -ddump-simpl -ddump-to-file -dsuppress-all -dno-suppress-type-signatures -dno-typeable-binds #-}
3+
module QuicksortMA (MutArr, fromList, toList, clone, quicksort) where
4+
5+
import MutArr
6+
7+
{-# INLINEABLE quicksort #-}
8+
quicksort :: Ord a => MutArr a -> Int -> Int -> IO ()
9+
quicksort !arr !l !r
10+
| r - l <= 1 = pure ()
11+
| otherwise = do
12+
x <- readMA arr (r - 1)
13+
m <- partition arr l (r - 1) x
14+
swap arr (r - 1) m
15+
quicksort arr (m + 1) r
16+
quicksort arr l m
17+
18+
{-# INLINEABLE partition #-}
19+
partition :: Ord a => MutArr a -> Int -> Int -> a -> IO Int
20+
partition arr l r x = go arr l l where
21+
go !arr !m !i
22+
| i == r = pure m
23+
| otherwise = do
24+
y <- readMA arr i
25+
if y <= x then do
26+
swap arr i m
27+
go arr (m + 1) (i + 1)
28+
else go arr m (i + 1)

fleet-array.cabal

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,13 @@ library
4444
benchmark fleet-array-bench
4545
import: warnings
4646
main-is: Bench.hs
47-
other-modules: Array, Quicksort, QuicksortA, QuicksortIM
47+
other-modules: Array
48+
, Quicksort
49+
, QuicksortMA
50+
, QuicksortIM
51+
, Eratosthenes
52+
, EratosthenesMA
53+
, MutArr
4854
build-depends: base, fleet-array, tasty-bench ^>= {0.4.1}, containers
4955
hs-source-dirs: bench/
5056
default-language: GHC2021

src/Fleet/Array.hs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ latest version.
2424
module Fleet.Array
2525
( Array
2626
, fromList
27+
, replicate
2728
, toList
2829
, (!)
2930
, index
@@ -33,17 +34,23 @@ module Fleet.Array
3334
, pseq
3435
) where
3536

37+
import Prelude hiding (replicate)
38+
3639
import Data.Tuple (Solo (MkSolo))
3740
import GHC.Exts hiding (fromList, toList, Lifted)
3841

3942
import Data.Kind (Type)
40-
import GHC.IO.Unsafe (unsafeDupablePerformIO)
4143
import GHC.Conc (pseq)
44+
import GHC.Base (IO (IO))
45+
-- import GHC.IO.Unsafe (unsafeDupablePerformIO)
4246

4347
import Fleet.Array.MutVar
4448
import Fleet.Array.Lift
4549
import Fleet.Array.MutArray
4650

51+
unsafeDupablePerformIO :: IO a -> a
52+
unsafeDupablePerformIO (IO f) = runRW# (\s -> case f s of (# _ , x #) -> x)
53+
4754
data Op a = Set {-# UNPACK #-} !Int a | Swap {-# UNPACK #-} !Int {-# UNPACK #-} !Int
4855

4956
-- | Fleet arrays.
@@ -75,11 +82,18 @@ fromList xs = unsafeDupablePerformIO $ do
7582
v <- newMutVar (Current arr0)
7683
pure (A v)
7784

85+
replicate :: Int -> a -> Array a
86+
replicate n x = unsafeDupablePerformIO $ do
87+
arr <- newMutArray n x
88+
v <- newMutVar (Current arr)
89+
pure (A v)
90+
7891
copyInternal :: ArrayVar a -> IO (MutArray a)
7992
copyInternal v = do
8093
av <- readMutVar v
8194
case av of
8295
Current arr -> cloneMutArray arr 0 (sizeofMutArray arr)
96+
-- _ -> error "Accessing old version"
8397
Diff op v' -> do
8498
clone <- copyInternal v'
8599
appOp clone op
@@ -134,6 +148,7 @@ A v0 ! i0 = unsafeDupablePerformIO (go v0 i0) where
134148
dat <- readMutVar v
135149
case dat of
136150
Current arr -> readMutArray arr i
151+
-- _ -> error "Accessing old version"
137152
Diff (Set j x) v'
138153
| i == j -> pure x
139154
| otherwise -> go v' i
@@ -152,6 +167,7 @@ index i0 (A v0) = unsafeDupablePerformIO (go v0 i0) where
152167
dat <- readMutVar v
153168
case dat of
154169
Current arr -> MkSolo <$> readMutArray arr i
170+
-- _ -> error "Accessing old version"
155171
Diff (Set j x) xs
156172
| i == j -> pure (MkSolo x)
157173
| otherwise -> go xs i
@@ -182,12 +198,22 @@ reversePointers v = do
182198
dat <- readMutVar v
183199
case dat of
184200
Current arr -> pure arr
185-
Diff op v' -> do
186-
arr <- reversePointers v'
187-
op' <- invert arr op
188-
appOp arr op
189-
writeMutVar v' (Diff op' v)
190-
pure arr
201+
Diff op v' -> reversePointersDiff v op v'
202+
203+
-- this needs to be a separate function, because we want the good weather path
204+
-- (where dat = Current ...) to inline and optimize. The recursion in this
205+
-- function, which prevents inlining, thus needs to be extracted from
206+
-- reversePointers.
207+
reversePointersDiff :: ArrayVar a -> Op a -> ArrayVar a -> IO (MutArray a)
208+
reversePointersDiff v op v' = do
209+
dat <- readMutVar v'
210+
arr <- case dat of
211+
Current arr -> pure arr
212+
Diff op' v'' -> reversePointersDiff v' op' v''
213+
op' <- invert arr op
214+
appOp arr op
215+
writeMutVar v' (Diff op' v)
216+
pure arr
191217

192218
{-# INLINE appDiffOp #-}
193219
appDiffOp :: Op a -> Array a -> Array a

0 commit comments

Comments
 (0)