monad-par-0.1: examples/partree/Tree.hs
-- -*- haskell -*-
--
-- ADT of a binary tree (values only in leaves).
-- Parallel functions use par and seq directly.
-- ---------------------------------------------------------------------------
module Tree(Tree,
list2tree, tree2list, (^:),
tree_map, tree_fold,
depth, create_forest,
force_tree, par_tree_map) where
import Control.Parallel
import Control.Parallel.Strategies
import Control.Monad.Par
infixl 2 ^:
data Tree a = Leaf a
| Node (Tree a) (Tree a)
deriving (Eq, Read, Show)
tree_map :: (Integral a, Integral b) => (a -> b) -> Tree a -> Tree b
tree_map f (Leaf x) = Leaf (f x)
tree_map f (Node left right) = Node (tree_map f left) (tree_map f right)
par_tree_map :: (Integral a, Integral b) => (a -> b) -> Tree a -> Tree b
par_tree_map f t =
runPar $ par_tree_map' f t
par_tree_map' :: (Integral a, Integral b) => (a -> b) -> Tree a -> Par (Tree b)
par_tree_map' f (Leaf x) = return $ Leaf (f x)
par_tree_map' f (Node left right) =
do l' <- spawn_ $ par_tree_map' f left
r <- par_tree_map' f right
l <- get l'
return (Node l r)
-- force evaluation of tree (could use Strategies module instead!)
force_tree :: (Integral a) => Tree a -> ()
force_tree t@(Leaf x) = x `seq` ()
force_tree t@(Node left right) = (force_tree left) `seq`
(force_tree right) `seq`
()
-- just would you'd expect
tree_fold :: (Integral a) => (a -> a -> a) -> a -> Tree a -> a
tree_fold o z (Leaf x) = z `o` x
tree_fold o z (Node left right) = tree_fold o z' right
where z' = tree_fold o z left
list2tree :: (Integral a) => [a] -> Tree a
list2tree [] = error "list2tree: empty list"
list2tree [x] = Leaf x
list2tree l = Node (list2tree left) (list2tree right)
where (left,right) = splitAt ((length l) `div` 2 ) l
tree2list :: (Integral a) => Tree a -> [a]
tree2list (Leaf x) = [x]
tree2list (Node left right) = tree2list left ++ tree2list right
-- combine 2 trees
(^:) :: (Integral a) => Tree a -> Tree a -> Tree a
t1 ^: t2 = Node t1 t2
depth :: Tree a -> Int
depth (Leaf _) = 0
depth (Node left right) = max (depth left) (depth right) + 1
-- The following functions are useful for heavily heap allocating test fcts
create_forest :: (Integral a) => Tree a -> [Tree a]
create_forest (Leaf x) = [ (Leaf y) | y <- [2..x], gcd x y == 1 ]
create_forest (Node left right) = [ (Node left' right')
| left' <- create_forest left,
right' <- create_forest right]
{-
On a Harpertown Windows machine with 4 cores (8 threads), using
Haskell Platform 2011.2.0.0.
Note the CPU utilization rates (elapsed time * num_of_threads/CPU time)
range between 70% and 77% when -N > 1.
Compare that with Strategies, which has a higher CPU utilization rate
(> 95%) and a smaller user time for -N > 1.
E:\cchen15\icfp\partree-mp>timeit partree.exe 1000 10 +RTS -N1
partree 1000 10 = 23712
Fri Mar 18 13:56:45 2011
Cmd: partree.exe 1000 10 +RTS -N1
Elapsed: 4.898 sec
User 4.867 sec
System 0.016 sec
Total CPU 4.883 sec
Peak WorkingSet Size: 7229440
Peak Pagefile Usage: 5836800
Page Fault Count: 1806
Peak Paged Pool usage: 85688
Peak NonPaged Pool usage: 5568
E:\cchen15\icfp\partree-mp>timeit partree.exe 1000 10 +RTS -N2
partree 1000 10 = 23712
Fri Mar 18 13:56:54 2011
Cmd: partree.exe 1000 10 +RTS -N2
Elapsed: 9.313 sec
User 12.605 sec
System 1.841 sec
Total CPU 14.446 sec
Peak WorkingSet Size: 12619776
Peak Pagefile Usage: 10133504
Page Fault Count: 3122
Peak Paged Pool usage: 85688
Peak NonPaged Pool usage: 6048
E:\cchen15\icfp\partree-mp>timeit partree.exe 1000 10 +RTS -N4
partree 1000 10 = 23712
Fri Mar 18 13:57:07 2011
Cmd: partree.exe 1000 10 +RTS -N4
Elapsed: 9.968 sec
User 22.761 sec
System 5.756 sec
Total CPU 28.517 sec
Peak WorkingSet Size: 13414400
Peak Pagefile Usage: 11677696
Page Fault Count: 3317
Peak Paged Pool usage: 85688
Peak NonPaged Pool usage: 6720
E:\cchen15\icfp\partree-mp>timeit partree.exe 1000 10 +RTS -N8
partree 1000 10 = 23712
Fri Mar 18 13:57:25 2011
Cmd: partree.exe 1000 10 +RTS -N8
Elapsed: 9.843 sec
User 46.239 sec
System 11.029 sec
Total CPU 57.268 sec
Peak WorkingSet Size: 14729216
Peak Pagefile Usage: 15175680
Page Fault Count: 3637
Peak Paged Pool usage: 85688
Peak NonPaged Pool usage: 7968
-}