packages feed

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
-}