monad-par 0.1.0.3 → 0.3
raw patch · 68 files changed
+2318/−6665 lines, 68 filesdep +QuickCheckdep +abstract-dequedep +abstract-pardep ~HUnitdep ~basedep ~deepseqnew-uploaderPVP ok
version bump matches the API change (PVP)
Dependencies added: QuickCheck, abstract-deque, abstract-par, array, containers, monad-par-extras, mtl, mwc-random, parallel, test-framework, test-framework-hunit, test-framework-quickcheck2, test-framework-th, time
Dependency ranges changed: HUnit, base, deepseq
API changes (from Hackage documentation)
- Control.Monad.Par: InclusiveRange :: Int -> Int -> InclusiveRange
- Control.Monad.Par: data InclusiveRange
- Control.Monad.Par: parFor :: InclusiveRange -> (Int -> Par ()) -> Par ()
- Control.Monad.Par: parMap :: (Traversable t, NFData b) => (a -> b) -> t a -> Par (t b)
- Control.Monad.Par: parMapM :: (Traversable t, NFData b) => (a -> Par b) -> t a -> Par (t b)
- Control.Monad.Par: parMapReduceRange :: NFData a => InclusiveRange -> (Int -> Par a) -> (a -> a -> Par a) -> a -> Par a
- Control.Monad.Par: parMapReduceRangeThresh :: NFData a => Int -> InclusiveRange -> (Int -> Par a) -> (a -> a -> Par a) -> a -> Par a
- Control.Monad.Par: pval :: NFData a => a -> Par (IVar a)
- Control.Monad.Par.AList: AList :: [a] -> AList a
- Control.Monad.Par.AList: ANil :: AList a
- Control.Monad.Par.AList: ASing :: a -> AList a
- Control.Monad.Par.AList: Append :: (AList a) -> (AList a) -> AList a
- Control.Monad.Par.AList: append :: AList a -> AList a -> AList a
- Control.Monad.Par.AList: cons :: a -> AList a -> AList a
- Control.Monad.Par.AList: data AList a
- Control.Monad.Par.AList: empty :: AList a
- Control.Monad.Par.AList: fromList :: [a] -> AList a
- Control.Monad.Par.AList: head :: AList a -> a
- Control.Monad.Par.AList: instance NFData a => NFData (AList a)
- Control.Monad.Par.AList: instance Show a => Show (AList a)
- Control.Monad.Par.AList: length :: AList a -> Int
- Control.Monad.Par.AList: null :: AList a -> Bool
- Control.Monad.Par.AList: parBuild :: NFData a => InclusiveRange -> (Int -> a) -> Par (AList a)
- Control.Monad.Par.AList: parBuildM :: NFData a => InclusiveRange -> (Int -> Par a) -> Par (AList a)
- Control.Monad.Par.AList: parBuildThresh :: NFData a => Int -> InclusiveRange -> (Int -> a) -> Par (AList a)
- Control.Monad.Par.AList: parBuildThreshM :: NFData a => Int -> InclusiveRange -> (Int -> Par a) -> Par (AList a)
- Control.Monad.Par.AList: singleton :: a -> AList a
- Control.Monad.Par.AList: tail :: AList a -> AList a
- Control.Monad.Par.AList: toList :: AList a -> [a]
- Control.Monad.Par.IList: Cons :: a -> IVar (IList a) -> IList a
- Control.Monad.Par.IList: Null :: IList a
- Control.Monad.Par.IList: data IList a
- Control.Monad.Par.IList: hd :: IList a -> a
- Control.Monad.Par.IList: instance NFData a => NFData (IList a)
- Control.Monad.Par.IList: tl :: IList a -> IVar (IList a)
- Control.Monad.Par.Internal: Blocked :: [a -> Trace] -> IVarContents a
- Control.Monad.Par.Internal: Done :: Trace
- Control.Monad.Par.Internal: Empty :: IVarContents a
- Control.Monad.Par.Internal: Fork :: Trace -> Trace -> Trace
- Control.Monad.Par.Internal: Full :: a -> IVarContents a
- Control.Monad.Par.Internal: Get :: (IVar a) -> (a -> Trace) -> Trace
- Control.Monad.Par.Internal: IVar :: (IORef (IVarContents a)) -> IVar a
- Control.Monad.Par.Internal: New :: (IVarContents a) -> (IVar a -> Trace) -> Trace
- Control.Monad.Par.Internal: Par :: ((a -> Trace) -> Trace) -> Par a
- Control.Monad.Par.Internal: Put :: (IVar a) -> a -> Trace -> Trace
- Control.Monad.Par.Internal: Sched :: {-# UNPACK #-} !Int -> IORef [Trace] -> IORef [MVar Bool] -> [Sched] -> Sched
- Control.Monad.Par.Internal: Yield :: Trace -> Trace
- Control.Monad.Par.Internal: data IVarContents a
- Control.Monad.Par.Internal: data Sched
- Control.Monad.Par.Internal: data Trace
- Control.Monad.Par.Internal: get :: IVar a -> Par a
- Control.Monad.Par.Internal: idle :: Sched -> IORef [MVar Bool]
- Control.Monad.Par.Internal: instance Applicative Par
- Control.Monad.Par.Internal: instance Functor Par
- Control.Monad.Par.Internal: instance Monad Par
- Control.Monad.Par.Internal: instance NFData (IVar a)
- Control.Monad.Par.Internal: new :: Par (IVar a)
- Control.Monad.Par.Internal: newFull :: NFData a => a -> Par (IVar a)
- Control.Monad.Par.Internal: newFull_ :: a -> Par (IVar a)
- Control.Monad.Par.Internal: newtype IVar a
- Control.Monad.Par.Internal: newtype Par a
- Control.Monad.Par.Internal: no :: Sched -> {-# UNPACK #-} !Int
- Control.Monad.Par.Internal: pollIVar :: IVar a -> IO (Maybe a)
- Control.Monad.Par.Internal: put :: NFData a => IVar a -> a -> Par ()
- Control.Monad.Par.Internal: put_ :: IVar a -> a -> Par ()
- Control.Monad.Par.Internal: runCont :: Par a -> (a -> Trace) -> Trace
- Control.Monad.Par.Internal: runPar :: Par a -> a
- Control.Monad.Par.Internal: runParAsync :: Par a -> a
- Control.Monad.Par.Internal: runParAsyncHelper :: Par a -> (a, IO ())
- Control.Monad.Par.Internal: sched :: Bool -> Sched -> Trace -> IO ()
- Control.Monad.Par.Internal: scheds :: Sched -> [Sched]
- Control.Monad.Par.Internal: workpool :: Sched -> IORef [Trace]
- Control.Monad.Par.Internal: yield :: Par ()
- Control.Monad.Par.OpenList: Cons :: a -> IVar (IList a) -> IList a
- Control.Monad.Par.OpenList: Null :: IList a
- Control.Monad.Par.OpenList: async_test :: IO ()
- Control.Monad.Par.OpenList: chaintest :: Int -> Par (IList Int)
- Control.Monad.Par.OpenList: close :: NFData a => OpenList a -> Par (OpenList a)
- Control.Monad.Par.OpenList: cons :: NFData a => a -> OpenList a -> Par (OpenList a)
- Control.Monad.Par.OpenList: data IList a
- Control.Monad.Par.OpenList: data OpenList a
- Control.Monad.Par.OpenList: empty :: OpenList a
- Control.Monad.Par.OpenList: fromList :: NFData a => [a] -> Par (OpenList a)
- Control.Monad.Par.OpenList: hd :: IList a -> a
- Control.Monad.Par.OpenList: head :: OpenList a -> a
- Control.Monad.Par.OpenList: instance NFData a => NFData (OpenList a)
- Control.Monad.Par.OpenList: instance Show a => Show (OpenList a)
- Control.Monad.Par.OpenList: join :: NFData a => OpenList a -> OpenList a -> Par (OpenList a)
- Control.Monad.Par.OpenList: lazy_chaintest :: Int -> Par [Int]
- Control.Monad.Par.OpenList: length :: Num t => OpenList a -> Par t
- Control.Monad.Par.OpenList: newCell :: a -> Par (IList a)
- Control.Monad.Par.OpenList: openlist_tests :: Test
- Control.Monad.Par.OpenList: parBuild :: NFData a => InclusiveRange -> (Int -> a) -> Par (OpenList a)
- Control.Monad.Par.OpenList: parBuildM :: NFData a => InclusiveRange -> (Int -> Par a) -> Par (OpenList a)
- Control.Monad.Par.OpenList: parMapM :: NFData a => (a1 -> Par a) -> OpenList a1 -> Par (OpenList a)
- Control.Monad.Par.OpenList: singleton :: a -> Par (OpenList a)
- Control.Monad.Par.OpenList: tail :: OpenList a -> Par (OpenList a)
- Control.Monad.Par.OpenList: tl :: IList a -> IVar (IList a)
- Control.Monad.Par.OpenList: toLazyList :: OpenList a -> Par [a]
- Control.Monad.Par.OpenList: toList :: NFData a => (OpenList a) -> Par [a]
+ Control.Monad.Par: class NFData a
+ Control.Monad.Par: spawnP :: ParFuture future m => forall a. NFData a => a -> m (future a)
+ Control.Monad.Par.Scheds.Direct: Blocked :: [a -> IO ()] -> IVarContents a
+ Control.Monad.Par.Scheds.Direct: Empty :: IVarContents a
+ Control.Monad.Par.Scheds.Direct: Full :: a -> IVarContents a
+ Control.Monad.Par.Scheds.Direct: IVar :: (IORef (IVarContents a)) -> IVar a
+ Control.Monad.Par.Scheds.Direct: Sched :: {-# UNPACK #-} !Int -> WSDeque (Par ()) -> HotVar GenIO -> Bool -> HotVar Bool -> HotVar [MVar Bool] -> [Sched] -> Sched
+ Control.Monad.Par.Scheds.Direct: data IVarContents a
+ Control.Monad.Par.Scheds.Direct: data Par a
+ Control.Monad.Par.Scheds.Direct: data Sched
+ Control.Monad.Par.Scheds.Direct: fork :: Par () -> Par ()
+ Control.Monad.Par.Scheds.Direct: get :: IVar a -> Par a
+ Control.Monad.Par.Scheds.Direct: idle :: Sched -> HotVar [MVar Bool]
+ Control.Monad.Par.Scheds.Direct: instance Applicative Par
+ Control.Monad.Par.Scheds.Direct: instance Functor Par
+ Control.Monad.Par.Scheds.Direct: instance Monad Par
+ Control.Monad.Par.Scheds.Direct: instance MonadCont Par
+ Control.Monad.Par.Scheds.Direct: instance MonadReader Sched Par
+ Control.Monad.Par.Scheds.Direct: instance NFData (IVar a)
+ Control.Monad.Par.Scheds.Direct: instance ParFuture IVar Par
+ Control.Monad.Par.Scheds.Direct: instance ParIVar IVar Par
+ Control.Monad.Par.Scheds.Direct: instance ParUnsafe IVar Par
+ Control.Monad.Par.Scheds.Direct: instance Show (IORef a)
+ Control.Monad.Par.Scheds.Direct: isMain :: Sched -> Bool
+ Control.Monad.Par.Scheds.Direct: killflag :: Sched -> HotVar Bool
+ Control.Monad.Par.Scheds.Direct: new :: Par (IVar a)
+ Control.Monad.Par.Scheds.Direct: newFull :: NFData a => a -> Par (IVar a)
+ Control.Monad.Par.Scheds.Direct: newFull_ :: a -> Par (IVar a)
+ Control.Monad.Par.Scheds.Direct: newtype IVar a
+ Control.Monad.Par.Scheds.Direct: no :: Sched -> {-# UNPACK #-} !Int
+ Control.Monad.Par.Scheds.Direct: put :: NFData a => IVar a -> a -> Par ()
+ Control.Monad.Par.Scheds.Direct: put_ :: IVar a -> a -> Par ()
+ Control.Monad.Par.Scheds.Direct: rng :: Sched -> HotVar GenIO
+ Control.Monad.Par.Scheds.Direct: runPar :: Par a -> a
+ Control.Monad.Par.Scheds.Direct: scheds :: Sched -> [Sched]
+ Control.Monad.Par.Scheds.Direct: spawn :: NFData a => Par a -> Par (IVar a)
+ Control.Monad.Par.Scheds.Direct: spawn1_ :: (a -> Par b) -> a -> Par (IVar b)
+ Control.Monad.Par.Scheds.Direct: spawnP :: NFData a => a -> Par (IVar a)
+ Control.Monad.Par.Scheds.Direct: spawn_ :: Par a -> Par (IVar a)
+ Control.Monad.Par.Scheds.Direct: workpool :: Sched -> WSDeque (Par ())
+ Control.Monad.Par.Scheds.Sparks: Done :: a -> Par a
+ Control.Monad.Par.Scheds.Sparks: Future :: a -> Future a
+ Control.Monad.Par.Scheds.Sparks: data Future a
+ Control.Monad.Par.Scheds.Sparks: data Par a
+ Control.Monad.Par.Scheds.Sparks: get :: Future a -> Par a
+ Control.Monad.Par.Scheds.Sparks: instance Applicative Par
+ Control.Monad.Par.Scheds.Sparks: instance Functor Par
+ Control.Monad.Par.Scheds.Sparks: instance Monad Par
+ Control.Monad.Par.Scheds.Sparks: instance ParFuture Future Par
+ Control.Monad.Par.Scheds.Sparks: runPar :: Par a -> a
+ Control.Monad.Par.Scheds.Sparks: spawn :: NFData a => Par a -> Par (Future a)
+ Control.Monad.Par.Scheds.Sparks: spawnP :: NFData a => a -> Par (Future a)
+ Control.Monad.Par.Scheds.Sparks: spawn_ :: Par a -> Par (Future a)
+ Control.Monad.Par.Scheds.Trace: data IVar a
+ Control.Monad.Par.Scheds.Trace: data Par a
+ Control.Monad.Par.Scheds.Trace: fork :: Par () -> Par ()
+ Control.Monad.Par.Scheds.Trace: get :: IVar a -> Par a
+ Control.Monad.Par.Scheds.Trace: instance ParFuture IVar Par
+ Control.Monad.Par.Scheds.Trace: instance ParIVar IVar Par
+ Control.Monad.Par.Scheds.Trace: new :: Par (IVar a)
+ Control.Monad.Par.Scheds.Trace: newFull :: NFData a => a -> Par (IVar a)
+ Control.Monad.Par.Scheds.Trace: newFull_ :: a -> Par (IVar a)
+ Control.Monad.Par.Scheds.Trace: put :: NFData a => IVar a -> a -> Par ()
+ Control.Monad.Par.Scheds.Trace: put_ :: IVar a -> a -> Par ()
+ Control.Monad.Par.Scheds.Trace: runPar :: Par a -> a
+ Control.Monad.Par.Scheds.Trace: spawn :: NFData a => Par a -> Par (IVar a)
+ Control.Monad.Par.Scheds.Trace: spawnP :: NFData a => a -> Par (IVar a)
+ Control.Monad.Par.Scheds.Trace: spawn_ :: Par a -> Par (IVar a)
+ Control.Monad.Par.Scheds.TraceInternal: Blocked :: [a -> Trace] -> IVarContents a
+ Control.Monad.Par.Scheds.TraceInternal: Done :: Trace
+ Control.Monad.Par.Scheds.TraceInternal: Empty :: IVarContents a
+ Control.Monad.Par.Scheds.TraceInternal: Fork :: Trace -> Trace -> Trace
+ Control.Monad.Par.Scheds.TraceInternal: Full :: a -> IVarContents a
+ Control.Monad.Par.Scheds.TraceInternal: Get :: (IVar a) -> (a -> Trace) -> Trace
+ Control.Monad.Par.Scheds.TraceInternal: IVar :: (IORef (IVarContents a)) -> IVar a
+ Control.Monad.Par.Scheds.TraceInternal: New :: (IVarContents a) -> (IVar a -> Trace) -> Trace
+ Control.Monad.Par.Scheds.TraceInternal: Par :: ((a -> Trace) -> Trace) -> Par a
+ Control.Monad.Par.Scheds.TraceInternal: Put :: (IVar a) -> a -> Trace -> Trace
+ Control.Monad.Par.Scheds.TraceInternal: Sched :: {-# UNPACK #-} !ThreadNumber -> IORef WorkPool -> IORef AllStatus -> Array ThreadNumber Sched -> IORef ThreadId -> Sched
+ Control.Monad.Par.Scheds.TraceInternal: Yield :: Trace -> Trace
+ Control.Monad.Par.Scheds.TraceInternal: data IVarContents a
+ Control.Monad.Par.Scheds.TraceInternal: data Sched
+ Control.Monad.Par.Scheds.TraceInternal: data Trace
+ Control.Monad.Par.Scheds.TraceInternal: get :: IVar a -> Par a
+ Control.Monad.Par.Scheds.TraceInternal: instance Applicative Par
+ Control.Monad.Par.Scheds.TraceInternal: instance Functor Par
+ Control.Monad.Par.Scheds.TraceInternal: instance Monad Par
+ Control.Monad.Par.Scheds.TraceInternal: instance NFData (IVar a)
+ Control.Monad.Par.Scheds.TraceInternal: new :: Par (IVar a)
+ Control.Monad.Par.Scheds.TraceInternal: newFull :: NFData a => a -> Par (IVar a)
+ Control.Monad.Par.Scheds.TraceInternal: newFull_ :: a -> Par (IVar a)
+ Control.Monad.Par.Scheds.TraceInternal: newtype IVar a
+ Control.Monad.Par.Scheds.TraceInternal: newtype Par a
+ Control.Monad.Par.Scheds.TraceInternal: no :: Sched -> {-# UNPACK #-} !ThreadNumber
+ Control.Monad.Par.Scheds.TraceInternal: pollIVar :: IVar a -> IO (Maybe a)
+ Control.Monad.Par.Scheds.TraceInternal: put :: NFData a => IVar a -> a -> Par ()
+ Control.Monad.Par.Scheds.TraceInternal: put_ :: IVar a -> a -> Par ()
+ Control.Monad.Par.Scheds.TraceInternal: runCont :: Par a -> (a -> Trace) -> Trace
+ Control.Monad.Par.Scheds.TraceInternal: runPar :: Par a -> a
+ Control.Monad.Par.Scheds.TraceInternal: runParAsync :: Par a -> a
+ Control.Monad.Par.Scheds.TraceInternal: runParAsyncHelper :: Par a -> (a, IO ())
+ Control.Monad.Par.Scheds.TraceInternal: sched :: Bool -> WorkLimit -> Sched -> (IORef [Trace]) -> UId -> Trace -> IO ()
+ Control.Monad.Par.Scheds.TraceInternal: scheds :: Sched -> Array ThreadNumber Sched
+ Control.Monad.Par.Scheds.TraceInternal: status :: Sched -> IORef AllStatus
+ Control.Monad.Par.Scheds.TraceInternal: tId :: Sched -> IORef ThreadId
+ Control.Monad.Par.Scheds.TraceInternal: workpool :: Sched -> IORef WorkPool
+ Control.Monad.Par.Scheds.TraceInternal: yield :: Par ()
- Control.Monad.Par: fork :: Par () -> Par ()
+ Control.Monad.Par: fork :: ParIVar ivar m => m () -> m ()
- Control.Monad.Par: get :: IVar a -> Par a
+ Control.Monad.Par: get :: ParFuture future m => forall a. future a -> m a
- Control.Monad.Par: new :: Par (IVar a)
+ Control.Monad.Par: new :: ParIVar ivar m => forall a. m (ivar a)
- Control.Monad.Par: newFull :: NFData a => a -> Par (IVar a)
+ Control.Monad.Par: newFull :: ParIVar ivar m => forall a. NFData a => a -> m (ivar a)
- Control.Monad.Par: newFull_ :: a -> Par (IVar a)
+ Control.Monad.Par: newFull_ :: ParIVar ivar m => forall a. a -> m (ivar a)
- Control.Monad.Par: put :: NFData a => IVar a -> a -> Par ()
+ Control.Monad.Par: put :: ParIVar ivar m => forall a. NFData a => ivar a -> a -> m ()
- Control.Monad.Par: put_ :: IVar a -> a -> Par ()
+ Control.Monad.Par: put_ :: ParIVar ivar m => forall a. ivar a -> a -> m ()
- Control.Monad.Par: spawn :: NFData a => Par a -> Par (IVar a)
+ Control.Monad.Par: spawn :: ParFuture future m => forall a. NFData a => m a -> m (future a)
- Control.Monad.Par: spawn_ :: Par a -> Par (IVar a)
+ Control.Monad.Par: spawn_ :: ParFuture future m => forall a. m a -> m (future a)
Files
- Control/Monad/Par.hs +132/−271
- Control/Monad/Par/AList.hs +0/−190
- Control/Monad/Par/IList.hs +0/−28
- Control/Monad/Par/Internal.hs +0/−292
- Control/Monad/Par/OpenList.hs +0/−454
- Control/Monad/Par/Scheds/Direct.hs +626/−0
- Control/Monad/Par/Scheds/Sparks.hs +67/−0
- Control/Monad/Par/Scheds/Trace.hs +56/−0
- Control/Monad/Par/Scheds/TraceInternal.hs +595/−0
- Control/Monad/Par/Stream.hs +0/−367
- examples/Makefile +0/−33
- examples/PortablePixmap.lhs +0/−127
- examples/benchlist.txt +0/−27
- examples/benchmark.sh +0/−226
- examples/blackscholes.hs +0/−153
- examples/blackscholes_data.hs +0/−1006
- examples/cholesky.hs +0/−321
- examples/cholesky_matrix6.dat +0/−1
- examples/coins.hs +0/−240
- examples/common.mk +0/−10
- examples/get_cholesky_data.sh +0/−2
- examples/mandel.hs +0/−96
- examples/matmult/ListAux.hs +0/−41
- examples/matmult/Makefile +0/−4
- examples/matmult/MatMult.hs +0/−215
- examples/matmult/matmult.stdout +0/−1
- examples/minimax/Board.hs +0/−121
- examples/minimax/Game.hs +0/−67
- examples/minimax/Main.hs +0/−20
- examples/minimax/Makefile +0/−4
- examples/minimax/Prog.hs +0/−47
- examples/minimax/Tree.hs +0/−41
- examples/minimax/Wins.hs +0/−39
- examples/minimax/minimax.stdout +0/−18
- examples/nbody.hs +0/−123
- examples/ntimes +0/−153
- examples/ntimes_minmedmax +0/−38
- examples/parfib.hs +0/−74
- examples/partree/Makefile +0/−4
- examples/partree/Tree.hs +0/−146
- examples/partree/partree.hs +0/−34
- examples/plot_scaling.hs +0/−355
- examples/primes.hs +0/−52
- examples/queens.hs +0/−32
- examples/run_tests.sh +0/−19
- examples/stream/DEVLOG.txt +0/−141
- examples/stream/Makefile +0/−32
- examples/stream/disjoint_working_sets_pipeline.hs +0/−276
- examples/stream/fft_pipeline.hs +0/−75
- examples/stream/simple1_measureSrc.hs +0/−35
- examples/sumeuler/ListAux.hs +0/−41
- examples/sumeuler/Makefile +0/−7
- examples/sumeuler/SumEuler.hs +0/−287
- examples/sumeuler/SumEulerPrimes.hs +0/−36
- examples/timeout.sh +0/−91
- monad-par.cabal +111/−59
- tests/AListTest.hs +61/−19
- tests/AllTests.hs +18/−0
- tests/AsyncTest.hs +45/−0
- tests/Makefile +32/−0
- tests/ParTests.hs +119/−0
- tests/Test.hs +0/−74
- tests/TestHelpers.hs +90/−0
- tests/TestParDist.hs +115/−0
- tests/Test_ContReaderT.hs +37/−0
- tests/Test_ReaderContT.hs +35/−0
- tests/hs_cassandra_microbench.hs +88/−0
- tests/hs_cassandra_microbench2.hs +91/−0
Control/Monad/Par.hs view
@@ -1,303 +1,164 @@-{-# LANGUAGE RankNTypes, NamedFieldPuns, BangPatterns,- ExistentialQuantification- #-}-{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing -fwarn-unused-imports #-} --- | This module provides a monad @Par@, for speeding up pure--- computations using parallel processors. It cannot be used for--- speeding up computations that use IO (for that, see--- @Control.Concurrent@). The result of a given @Par@ computation is--- always the same - ie. it is deterministic, but the computation may--- be performed more quickly if there are processors available to--- share the work.------ For example, the following program fragment computes the values of--- @(f x)@ and @(g x)@ in parallel, and returns a pair of their results:------ > runPar $ do--- > fx <- pval (f x) -- start evaluating (f x)--- > gx <- pval (g x) -- start evaluating (g x)--- > a <- get fx -- wait for fx--- > b <- get gx -- wait for gx--- > return (a,b) -- return results------ @Par@ can be used for specifying pure parallel computations in--- which the order of the computation is not known beforehand.--- The programmer specifies how information flows from one--- part of the computation to another, but not the order in which--- computations will be evaluated at runtime. Information flow is--- described using "variables" called @IVar@s, which support 'put' and--- 'get' operations. For example, suppose you have a problem that--- can be expressed as a network with four nodes, where @b@ and @c@--- require the value of @a@, and @d@ requires the value of @b@ and @c@:------ > a--- > / \ --- > b c--- > \ /--- > d------ Then you could express this in the @Par@ monad like this:------ > runPar $ do--- > [a,b,c,d] <- sequence [new,new,new,new]--- > fork $ do x <- get a; put b (x+1)--- > fork $ do x <- get a; put c (x+2)--- > fork $ do x <- get b; y <- get c; put d (x+y)--- > fork $ do put a (3 :: Int)--- > get d------ The result of the above computation is always 9. The 'get' operation--- waits until its input is available; multiple 'put's to the same--- @IVar@ are not allowed, and result in a runtime error. Values--- stored in @IVar@s are usually fully evaluated (although there are--- ways provided to pass lazy values if necessary).------ In the above example, @b@ and @c@ will be evaluated in parallel.--- In practice the work involved at each node is too small here to see--- the benefits of parallelism though: typically each node should--- involve much more work. The granularity is completely under your--- control - too small and the overhead of the @Par@ monad will--- outweigh any parallelism benefits, whereas if the nodes are too--- large then there might not be enough parallelism to use all the--- available processors.------ Unlike @Control.Parallel@, in @Control.Monad.Par@ parallelism is--- not combined with laziness, so sharing and granulairty are--- completely under the control of the programmer. New units of--- parallel work are only created by @fork@, @par@, and a few other--- combinators.------ The implementation is based on a work-stealing scheduler that--- divides the work as evenly as possible betwen the available--- processors at runtime.-----module Control.Monad.Par (- -- * The @Par@ monad- Par,- runPar,- fork,-- -- * Communication: @IVar@s- IVar,- new, newFull, newFull_,- get,- put, put_,-- -- * Operations- pval,- spawn, spawn_,- parMap, parMapM,- parMapReduceRangeThresh, parMapReduceRange,- InclusiveRange(..),- parFor,-- ) where--import Control.Monad.Par.Internal-import Control.DeepSeq-import Data.Traversable-import Control.Monad as M hiding (mapM, sequence, join)-import Prelude hiding (mapM, sequence, head,tail)+{-| (NOTE: This module reexports a default Par scheduler. A generic+ interface can be found in "Control.Monad.Par.Class" and other+ schedulers, sometimes with different capabilities, can be found in+ "Control.Monad.Par.Scheds".) -import GHC.Conc (numCapabilities)+ The @monad-par@ package provides a family of @Par@ monads, for speeding up pure+ computations using parallel processors. They cannot be used for+ speeding up computations that use IO (for that, see+ @Control.Concurrent@). The result of a given @Par@ computation is+ always the same - ie. it is deterministic, but the computation may+ be performed more quickly if there are processors available to+ share the work. --- -----------------------------------------------------------------------------+ For example, the following program fragment computes the values of+ @(f x)@ and @(g x)@ in parallel, and returns a pair of their results: --- | forks a computation to happen in parallel. The forked--- computation may exchange values with other computations using--- @IVar@s.-fork :: Par () -> Par ()-fork p = Par $ \c -> Fork (runCont p (\_ -> Done)) (c ())+ > runPar $ do+ > fx <- spawn (return (f x)) -- start evaluating (f x)+ > gx <- spawn (return (g x)) -- start evaluating (g x)+ > a <- get fx -- wait for fx+ > b <- get gx -- wait for gx+ > return (a,b) -- return results --- > both a b >> c == both (a >> c) (b >> c)--- is this useful for anything?--- both :: Par a -> Par a -> Par a--- both a b = Par $ \c -> Fork (runCont a c) (runCont b c)+ @Par@ can be used for specifying pure parallel computations in+ which the order of the computation is not known beforehand.+ The programmer specifies how information flows from one+ part of the computation to another, but not the order in which+ computations will be evaluated at runtime. Information flow is+ described using "variables" called @IVar@s, which support 'put' and+ 'get' operations. For example, suppose you have a problem that+ can be expressed as a network with four nodes, where @b@ and @c@+ require the value of @a@, and @d@ requires the value of @b@ and @c@: --- -------------------------------------------------------------------------------- Derived functions+ > a+ > / \ + > b c + > \ / + > d --- | Like 'spawn', but the result is only head-strict, not fully-strict.-spawn_ :: Par a -> Par (IVar a)-spawn_ p = do- r <- new- fork (p >>= put_ r)- return r+ Then you could express this in the @Par@ monad like this: --- | Like 'fork', but returns a @IVar@ that can be used to query the--- result of the forked computataion.------ > spawn p = do--- > r <- new--- > fork (p >>= put r)--- > return r----spawn :: NFData a => Par a -> Par (IVar a)-spawn p = do- r <- new- fork (p >>= put r)- return r+ > runPar $ do+ > [a,b,c,d] <- sequence [new,new,new,new]+ > fork $ do x <- get a; put b (x+1)+ > fork $ do x <- get a; put c (x+2)+ > fork $ do x <- get b; y <- get c; put d (x+y)+ > fork $ do put a (3 :: Int)+ > get d --- | equivalent to @spawn . return@-pval :: NFData a => a -> Par (IVar a)-pval a = spawn (return a)+ The result of the above computation is always 9. The 'get' operation+ waits until its input is available; multiple 'put's to the same+ @IVar@ are not allowed, and result in a runtime error. Values+ stored in @IVar@s are usually fully evaluated (although there are+ ways provided to pass lazy values if necessary). --- -------------------------------------------------------------------------------- Parallel maps over Traversable data structures+ In the above example, @b@ and @c@ will be evaluated in parallel.+ In practice the work involved at each node is too small here to see+ the benefits of parallelism though: typically each node should+ involve much more work. The granularity is completely under your+ control - too small and the overhead of the @Par@ monad will+ outweigh any parallelism benefits, whereas if the nodes are too+ large then there might not be enough parallelism to use all the+ available processors. --- | Applies the given function to each element of a data structure--- in parallel (fully evaluating the results), and returns a new data--- structure containing the results.------ > parMap f xs = mapM (pval . f) xs >>= mapM get------ @parMap@ is commonly used for lists, where it has this specialised type:------ > parMap :: NFData b => (a -> b) -> [a] -> Par [b]----parMap :: (Traversable t, NFData b) => (a -> b) -> t a -> Par (t b)-parMap f xs = mapM (pval . f) xs >>= mapM get+ Unlike @Control.Parallel@, in @Control.Monad.Par@ parallelism is+ not combined with laziness, so sharing and granulairty are+ completely under the control of the programmer. New units of+ parallel work are only created by @fork@ and a few other+ combinators. --- | Like 'parMap', but the function is a @Par@ monad operation.------ > parMapM f xs = mapM (spawn . f) xs >>= mapM get----parMapM :: (Traversable t, NFData b) => (a -> Par b) -> t a -> Par (t b)-parMapM f xs = mapM (spawn . f) xs >>= mapM get+ The implementation is based on a work-stealing scheduler that+ divides the work as evenly as possible between the available+ processors at runtime. -{-# SPECIALISE parMap :: (NFData b) => (a -> b) -> [a] -> Par [b] #-}-{-# SPECIALISE parMapM :: (NFData b) => (a -> Par b) -> [a] -> Par [b] #-}+ For more information on the programming model, please see these sources: + * The wiki/tutorial (<http://www.haskell.org/haskellwiki/Par_Monad:_A_Parallelism_Tutorial>)+ * The original paper (<http://www.cs.indiana.edu/~rrnewton/papers/haskell2011_monad-par.pdf>)+ * Tutorial slides (<http://community.haskell.org/~simonmar/slides/CUFP.pdf>)+ * Other slides: <http://www.cs.ox.ac.uk/ralf.hinze/WG2.8/28/slides/simon.pdf>, + <http://www.cs.indiana.edu/~rrnewton/talks/2011_HaskellSymposium_ParMonad.pdf> --- TODO: Perhaps should introduce a class for the "splittable range" concept.-data InclusiveRange = InclusiveRange Int Int+ -} --- | Computes a binary map\/reduce over a finite range. The range is--- recursively split into two, the result for each half is computed in--- parallel, and then the two results are combined. When the range--- reaches the threshold size, the remaining elements of the range are--- computed sequentially.------ For example, the following is a parallel implementation of------ > foldl (+) 0 (map (^2) [1..10^6])------ > parMapReduceRangeThresh 100 (InclusiveRange 1 (10^6))--- > (\x -> return (x^2))--- > (\x y -> return (x+y))--- > 0----parMapReduceRangeThresh- :: NFData a- => Int -- ^ threshold- -> InclusiveRange -- ^ range over which to calculate- -> (Int -> Par a) -- ^ compute one result- -> (a -> a -> Par a) -- ^ combine two results (associative)- -> a -- ^ initial result- -> Par a+module Control.Monad.Par + (+ -- * The Par Monad+ Par, + runPar, -parMapReduceRangeThresh threshold (InclusiveRange min max) fn binop init- = loop min max- where- loop min max- | max - min <= threshold =- let mapred a b = do x <- fn b;- result <- a `binop` x- return result- in foldM mapred init [min..max]+ fork,+ -- | forks a computation to happen in parallel. The forked+ -- computation may exchange values with other computations using+ -- @IVar@s. - | otherwise = do- let mid = min + ((max - min) `quot` 2)- rght <- spawn $ loop (mid+1) max- l <- loop min mid- r <- get rght- l `binop` r+ -- * Communication: IVars+ IVar, --- How many tasks per process should we aim for. Higher numbers--- improve load balance but put more pressure on the scheduler.-auto_partition_factor :: Int-auto_partition_factor = 4+ new, + -- | creates a new @IVar@ --- | \"Auto-partitioning\" version of 'parMapReduceRangeThresh' that chooses the threshold based on--- the size of the range and the number of processors..-parMapReduceRange :: NFData a => InclusiveRange -> (Int -> Par a) -> (a -> a -> Par a) -> a -> Par a-parMapReduceRange (InclusiveRange start end) fn binop init =- loop (length segs) segs- where- segs = splitInclusiveRange (auto_partition_factor * numCapabilities) (start,end)- loop 1 [(st,en)] =- let mapred a b = do x <- fn b;- result <- a `binop` x- return result- in foldM mapred init [st..en]- loop n segs =- let half = n `quot` 2- (left,right) = splitAt half segs in- do l <- spawn$ loop half left- r <- loop (n-half) right- l' <- get l- l' `binop` r+ newFull, + -- | creates a new @IVar@ that contains a value + newFull_, + -- | creates a new @IVar@ that contains a value (head-strict only) --- TODO: A version that works for any splittable input domain. In this case--- the "threshold" is a predicate on inputs.--- parMapReduceRangeGeneric :: (inp -> Bool) -> (inp -> Maybe (inp,inp)) -> inp ->+ get, + -- | read the value in an @IVar@. 'get' can only return when the+ -- value has been written by a prior or parallel @put@ to the same+ -- @IVar@. + put, + -- | put a value into a @IVar@. Multiple 'put's to the same @IVar@+ -- are not allowed, and result in a runtime error.+ --+ -- 'put' fully evaluates its argument, which therefore must be an+ -- instance of 'NFData'. The idea is that this forces the work to+ -- happen when we expect it, rather than being passed to the consumer+ -- of the @IVar@ and performed later, which often results in less+ -- parallelism than expected.+ --+ -- Sometimes partial strictness is more appropriate: see 'put_'.+ -- --- Experimental:+ put_,+ -- | like 'put', but only head-strict rather than fully-strict. --- | Parallel for-loop over an inclusive range. Semantically equivalent--- to--- --- > parFor (InclusiveRange n m) f = forM_ [n..m] f------ except that the implementation will split the work into an--- unspecified number of subtasks in an attempt to gain parallelism.--- The exact number of subtasks is chosen at runtime, and is probably--- a small multiple of the available number of processors.------ Strictly speaking the semantics of 'parFor' depends on the--- number of processors, and its behaviour is therefore not--- deterministic. However, a good rule of thumb is to not have any--- interdependencies between the elements; if this rule is followed--- then @parFor@ has deterministic semantics. One easy way to follow--- this rule is to only use 'put' or 'put_' in @f@, never 'get'.+ -- * Operations+ spawn,+ -- | Like 'fork', but returns a @IVar@ that can be used to query the+ -- result of the forked computataion. Therefore @spawn@ provides /futures/ or /promises/.+ --+ -- > spawn p = do+ -- > r <- new+ -- > fork (p >>= put r)+ -- > return r+ -- -parFor :: InclusiveRange -> (Int -> Par ()) -> Par ()-parFor (InclusiveRange start end) body =- do- let run (x,y) = for_ x (y+1) body- range_segments = splitInclusiveRange (4*numCapabilities) (start,end)+ spawn_,+ -- | Like 'spawn', but the result is only head-strict, not fully-strict. - vars <- M.forM range_segments (\ pr -> spawn_ (run pr))- M.mapM_ get vars- return ()+ spawnP,+ -- | Spawn a pure (rather than monadic) computation. Fully-strict.+ -- + -- > spawnP = spawn . return -splitInclusiveRange :: Int -> (Int, Int) -> [(Int, Int)]-splitInclusiveRange pieces (start,end) =- map largepiece [0..remain-1] ++- map smallpiece [remain..pieces-1]- where- len = end - start + 1 -- inclusive [start,end]- (portion, remain) = len `quotRem` pieces- largepiece i =- let offset = start + (i * (portion + 1))- in (offset, offset + portion)- smallpiece i =- let offset = start + (i * portion) + remain- in (offset, offset + portion - 1)+ module Control.Monad.Par.Combinator,+ -- | This module also reexports the Combinator library for backwards+ -- compatibility with version 0.1. --- My own forM for numeric ranges (not requiring deforestation optimizations).--- Inclusive start, exclusive end.-{-# INLINE for_ #-}-for_ :: Monad m => Int -> Int -> (Int -> m ()) -> m ()-for_ start end _fn | start > end = error "for_: start is greater than end"-for_ start end fn = loop start- where- loop !i | i == end = return ()- | otherwise = do fn i; loop (i+1)+ NFData()+ -- | /(0.3)/ Reexport 'NFData' for fully-strict operators. + )+where +-- (0.3) Export 'Par' operators via the generic interface.+import Control.Monad.Par.Class+import Control.Monad.Par.Scheds.Trace hiding (spawn_, spawn, spawnP, put, get, new, newFull, fork, put_, newFull_)+-- import Control.Monad.Par.Scheds.Direct +import Control.Monad.Par.Combinator
− Control/Monad/Par/AList.hs
@@ -1,190 +0,0 @@-{-# LANGUAGE CPP #-}-{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing -fwarn-unused-imports #-}---- | This module defines the 'AList' type, a list that supports--- constant-time append, and is therefore ideal for building the--- result of tree-shaped parallel computations.--module Control.Monad.Par.AList- (- -- * The 'AList' type and operations- AList(..),- empty, singleton, cons, head, tail, length, null, append,- toList, fromList,- -- * Operations to build 'AList's in the 'Par' monad- parBuildThresh, parBuildThreshM,- parBuild, parBuildM,- )-where ---import Control.DeepSeq-import Prelude hiding (length,head,tail,null)-import qualified Prelude as P-import Control.Monad.Par---- | List that support constant-time append (sometimes called--- join-lists).-data AList a = ANil | ASing a | Append (AList a) (AList a) | AList [a]--instance NFData a => NFData (AList a) where- rnf ANil = ()- rnf (ASing a) = rnf a - rnf (Append l r) = rnf l `seq` rnf r- rnf (AList l) = rnf l--#if 0- data Tree a = Empty | Leaf a | Node (Tree a) a (Tree a)- instance Traversable Tree- traverse f Empty = pure Empty- traverse f (Leaf x) = Leaf <$> f x- traverse f (Node l k r) = Node <$> traverse f l <*> f k <*> traverse f r-#endif----- TODO: Finish me:--- instance F.Foldable AList where--- foldr fn init al = --- case al of --- ANil -> ---- instance Functor AList where--- fmap = undefined---- -- Walk the data structure without introducing any additional data-parallelism.--- instance Traversable AList where --- traverse f al = --- case al of --- ANil -> pure ANil--- ASing x -> ASing <$> f x--instance Show a => Show (AList a) where - show al = "fromList "++ show (toList al)---- | /O(1)/ Append two 'AList's-append :: AList a -> AList a -> AList a-append ANil r = r-append l ANil = l-append l r = Append l r--{-# INLINE empty #-}-{-# INLINE singleton #-}-{-# INLINE fromList #-}---- | /O(1)/ an empty 'AList'-empty :: AList a-empty = ANil---- | /O(1)/ a singleton 'AList'-singleton :: a -> AList a-singleton = ASing---- | /O(1)/ convert an ordinary list to an 'AList'-fromList :: [a] -> AList a-fromList = AList---- | /O(1)/ prepend an element-cons :: a -> AList a -> AList a-cons x ANil = ASing x-cons x al = Append (ASing x) al--- If we tracked length perhaps this could make an effort at balance.---- | /O(n)/ take the head element of an 'AList'------ NB. linear-time, because the list might look like this:------ > (((... `append` a) `append` b) `append` c)----head :: AList a -> a-head al = - case loop al of- Just x -> x - Nothing -> error "cannot take head of an empty AList"- where - -- Alas there are an infinite number of representations for null:- loop al =- case al of - Append l r -> case loop l of - x@(Just _) -> x- Nothing -> loop r- ASing x -> Just x- AList (h:_) -> Just h- AList [] -> Nothing- ANil -> Nothing---- | /O(n)/ take the tail element of an 'AList'-tail :: AList a -> AList a-tail al = - case loop al of- Just x -> x - Nothing -> error "cannot take tail of an empty AList"- where - loop al =- case al of - Append l r -> case loop l of - (Just x) -> Just (Append x r)- Nothing -> loop r-- ASing _ -> Just ANil- AList (_:t) -> Just (AList t)- AList [] -> Nothing- ANil -> Nothing---- | /O(n)/ find the length of an 'AList'-length :: AList a -> Int-length ANil = 0-length (ASing _) = 1-length (Append l r) = length l + length r-length (AList l) = P.length l ----- | /O(n)/ returns 'True' if the 'AList' is empty-null :: AList a -> Bool-null = (==0) . length ---- | /O(n)/ converts an 'AList' to an ordinary list-toList :: AList a -> [a]-toList a = go a []- where go ANil rest = rest- go (ASing a) rest = a : rest- go (Append l r) rest = go l $! go r rest- go (AList xs) rest = xs ++ rest---- TODO: Provide a strategy for @par@-based maps:---appendM :: AList a -> AList a -> Par (AList a)-appendM x y = return (append x y)---- | Build a balanced 'AList' in parallel, constructing each element as a--- function of its index. The threshold argument provides control--- over the degree of parallelism. It indicates under what number--- of elements the build process should switch from parallel to--- serial.-parBuildThresh :: NFData a => Int -> InclusiveRange -> (Int -> a) -> Par (AList a)-parBuildThresh threshold range fn =- parMapReduceRangeThresh threshold range- (return . singleton . fn) appendM empty---- | Variant of 'parBuildThresh' in which the element-construction function is itself a 'Par' computation.-parBuildThreshM :: NFData a => Int -> InclusiveRange -> (Int -> Par a) -> Par (AList a)-parBuildThreshM threshold range fn =- parMapReduceRangeThresh threshold range - ((fmap singleton) . fn) appendM empty---- | \"Auto-partitioning\" version of 'parBuildThresh' that chooses the threshold based on--- the size of the range and the number of processors..-parBuild :: NFData a => InclusiveRange -> (Int -> a) -> Par (AList a)-parBuild range fn =- parMapReduceRange range (return . singleton . fn) appendM empty---- | like 'parBuild', but the construction function is monadic-parBuildM :: NFData a => InclusiveRange -> (Int -> Par a) -> Par (AList a)-parBuildM range fn =- parMapReduceRange range ((fmap singleton) . fn) appendM empty----- | A parMap over an AList can result in more balanced parallelism than--- the default parMap over Traversable data types.--- parMap :: NFData b => (a -> b) -> AList a -> Par (AList b)-
− Control/Monad/Par/IList.hs
@@ -1,28 +0,0 @@---- ILists: lists whose cdr fields are IVars, filled in asynchronously--- via Par computation.---- This module mostly exists as a datatype to use in building other,--- higher-level abstractions. (See OpenList and Stream.)--module Control.Monad.Par.IList - (- IList(..)- )-where--import Control.Monad.Par-import Control.DeepSeq---- | An 'IList' is the equivalent of a lazy list in the 'Par' monad.--- The tail of the list is an 'IVar', which allows the list to be--- produced and consumed in parallel.-data IList a = Null | Cons { hd :: a, tl :: IVar (IList a) }---- | To fully evaluate an 'IList' means to evaluate both the head--- and tail. This does not evaluate the entire spine of the list--- of course, because the tail is an 'IVar'.-instance NFData a => NFData (IList a) where--- rnf Null = r0- rnf Null = ()- rnf (Cons a b) = rnf a `seq` rnf b
− Control/Monad/Par/Internal.hs
@@ -1,292 +0,0 @@-{-# LANGUAGE RankNTypes, NamedFieldPuns, BangPatterns,- ExistentialQuantification, CPP- #-}-{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing -fno-warn-unused-do-bind #-}---- | This module exposes the internals of the @Par@ monad so that you--- can build your own scheduler or other extensions. Do not use this--- module for purposes other than extending the @Par@ monad with new--- functionality.--module Control.Monad.Par.Internal (- Trace(..), Sched(..), Par(..),- IVar(..), IVarContents(..),- sched,- runPar, runParAsync, runParAsyncHelper,- new, newFull, newFull_, get, put_, put,- pollIVar, yield,- ) where---import Control.Monad as M hiding (mapM, sequence, join)-import Prelude hiding (mapM, sequence, head,tail)-import Data.IORef-import System.IO.Unsafe-import Control.Concurrent hiding (yield)-import GHC.Conc hiding (yield)-import Control.DeepSeq-import Control.Applicative--- import Text.Printf---- -----------------------------------------------------------------------------data Trace = forall a . Get (IVar a) (a -> Trace)- | forall a . Put (IVar a) a Trace- | forall a . New (IVarContents a) (IVar a -> Trace)- | Fork Trace Trace- | Done- | Yield Trace---- | The main scheduler loop.-sched :: Bool -> Sched -> Trace -> IO ()-sched _doSync queue t = loop t- where - loop t = case t of- New a f -> do- r <- newIORef a- loop (f (IVar r))- Get (IVar v) c -> do- e <- readIORef v- case e of- Full a -> loop (c a)- _other -> do- r <- atomicModifyIORef v $ \e -> case e of- Empty -> (Blocked [c], reschedule queue)- Full a -> (Full a, loop (c a))- Blocked cs -> (Blocked (c:cs), reschedule queue)- r- Put (IVar v) a t -> do- cs <- atomicModifyIORef v $ \e -> case e of- Empty -> (Full a, [])- Full _ -> error "multiple put"- Blocked cs -> (Full a, cs)- mapM_ (pushWork queue. ($a)) cs- loop t- Fork child parent -> do- pushWork queue child- loop parent- Done ->- if _doSync- then reschedule queue--- We could fork an extra thread here to keep numCapabilities workers--- even when the main thread returns to the runPar caller...- else do putStrLn " [par] Forking replacement thread..\n"- forkIO (reschedule queue); return ()--- But even if we don't we are not orphaning any work in this--- threads work-queue because it can be stolen by other threads.--- else return ()-- Yield parent -> do - -- Go to the end of the worklist:- let Sched { workpool } = queue- -- TODO: Perhaps consider Data.Seq here.- -- This would also be a chance to steal and work from opposite ends of the queue.- atomicModifyIORef workpool $ \ts -> (ts++[parent], ())- reschedule queue---- | Process the next item on the work queue or, failing that, go into--- work-stealing mode.-reschedule :: Sched -> IO ()-reschedule queue@Sched{ workpool } = do- e <- atomicModifyIORef workpool $ \ts ->- case ts of- [] -> ([], Nothing)- (t:ts') -> (ts', Just t)- case e of- Nothing -> steal queue- Just t -> sched True queue t----- RRN: Note -- NOT doing random work stealing breaks the traditional--- Cilk time/space bounds if one is running strictly nested (series--- parallel) programs.---- | Attempt to steal work or, failing that, give up and go idle.-steal :: Sched -> IO ()-steal q@Sched{ idle, scheds, no=my_no } = do- -- printf "cpu %d stealing\n" my_no- go scheds- where- go [] = do m <- newEmptyMVar- r <- atomicModifyIORef idle $ \is -> (m:is, is)- if length r == numCapabilities - 1- then do- -- printf "cpu %d initiating shutdown\n" my_no- mapM_ (\m -> putMVar m True) r- else do- done <- takeMVar m- if done- then do- -- printf "cpu %d shutting down\n" my_no- return ()- else do- -- printf "cpu %d woken up\n" my_no- go scheds- go (x:xs)- | no x == my_no = go xs- | otherwise = do- r <- atomicModifyIORef (workpool x) $ \ ts ->- case ts of- [] -> ([], Nothing)- (x:xs) -> (xs, Just x)- case r of- Just t -> do- -- printf "cpu %d got work from cpu %d\n" my_no (no x)- sched True q t- Nothing -> go xs---- | If any worker is idle, wake one up and give it work to do.-pushWork :: Sched -> Trace -> IO ()-pushWork Sched { workpool, idle } t = do- atomicModifyIORef workpool $ \ts -> (t:ts, ())- idles <- readIORef idle- when (not (null idles)) $ do- r <- atomicModifyIORef idle (\is -> case is of- [] -> ([], return ())- (i:is) -> (is, putMVar i False))- r -- wake one up--data Sched = Sched- { no :: {-# UNPACK #-} !Int,- workpool :: IORef [Trace],- idle :: IORef [MVar Bool],- scheds :: [Sched] -- Global list of all per-thread workers.- }--- deriving Show--newtype Par a = Par {- runCont :: (a -> Trace) -> Trace-}--instance Functor Par where- fmap f m = Par $ \c -> runCont m (c . f)--instance Monad Par where- return a = Par ($ a)- m >>= k = Par $ \c -> runCont m $ \a -> runCont (k a) c--instance Applicative Par where- (<*>) = ap- pure = return--newtype IVar a = IVar (IORef (IVarContents a))--- data IVar a = IVar (IORef (IVarContents a))---- Forcing evaluation of a IVar is fruitless.-instance NFData (IVar a) where- rnf _ = ()----- From outside the Par computation we can peek. But this is nondeterministic.-pollIVar :: IVar a -> IO (Maybe a)-pollIVar (IVar ref) = - do contents <- readIORef ref- case contents of - Full x -> return (Just x)- _ -> return (Nothing)---data IVarContents a = Full a | Empty | Blocked [a -> Trace]---{-# INLINE runPar_internal #-}-runPar_internal :: Bool -> Par a -> a-runPar_internal _doSync x = unsafePerformIO $ do- workpools <- replicateM numCapabilities $ newIORef []- idle <- newIORef []- let states = [ Sched { no=x, workpool=wp, idle, scheds=states }- | (x,wp) <- zip [0..] workpools ]--#if __GLASGOW_HASKELL__ >= 701 /* 20110301 */- --- -- We create a thread on each CPU with forkOnIO. The CPU on which- -- the current thread is running will host the main thread; the- -- other CPUs will host worker threads.- --- -- Note: GHC 7.1.20110301 is required for this to work, because that- -- is when threadCapability was added.- --- (main_cpu, _) <- threadCapability =<< myThreadId-#else- --- -- Lacking threadCapability, we always pick CPU #0 to run the main- -- thread. If the current thread is not running on CPU #0, this- -- will require some data to be shipped over the memory bus, and- -- hence will be slightly slower than the version above.- --- let main_cpu = 0-#endif-- m <- newEmptyMVar- forM_ (zip [0..] states) $ \(cpu,state) ->- forkOnIO cpu $- if (cpu /= main_cpu)- then reschedule state- else do- rref <- newIORef Empty- sched _doSync state $ runCont (x >>= put_ (IVar rref)) (const Done)- readIORef rref >>= putMVar m-- r <- takeMVar m- case r of- Full a -> return a- _ -> error "no result"---runPar :: Par a -> a-runPar = runPar_internal True---- | An asynchronous version in which the main thread of control in a--- Par computation can return while forked computations still run in--- the background. -runParAsync :: Par a -> a-runParAsync = runPar_internal False---- | An alternative version in which the consumer of the result has--- | the option to "help" run the Par computation if results it is--- | interested in are not ready yet.-runParAsyncHelper :: Par a -> (a, IO ())-runParAsyncHelper = undefined -- TODO: Finish Me.---- --------------------------------------------------------------------------------- | creates a new @IVar@-new :: Par (IVar a)-new = Par $ New Empty---- | creates a new @IVar@ that contains a value-newFull :: NFData a => a -> Par (IVar a)-newFull x = deepseq x (Par $ New (Full x))---- | creates a new @IVar@ that contains a value (head-strict only)-newFull_ :: a -> Par (IVar a)-newFull_ !x = Par $ New (Full x)---- | read the value in a @IVar@. The 'get' can only return when the--- value has been written by a prior or parallel @put@ to the same--- @IVar@.-get :: IVar a -> Par a-get v = Par $ \c -> Get v c---- | like 'put', but only head-strict rather than fully-strict.-put_ :: IVar a -> a -> Par ()-put_ v !a = Par $ \c -> Put v a (c ())---- | put a value into a @IVar@. Multiple 'put's to the same @IVar@--- are not allowed, and result in a runtime error.------ 'put' fully evaluates its argument, which therefore must be an--- instance of 'NFData'. The idea is that this forces the work to--- happen when we expect it, rather than being passed to the consumer--- of the @IVar@ and performed later, which often results in less--- parallelism than expected.------ Sometimes partial strictness is more appropriate: see 'put_'.----put :: NFData a => IVar a -> a -> Par ()-put v a = deepseq a (Par $ \c -> Put v a (c ()))---- | Allows other parallel computations to progress. (should not be--- necessary in most cases).-yield :: Par ()-yield = Par $ \c -> Yield (c ())
− Control/Monad/Par/OpenList.hs
@@ -1,454 +0,0 @@-{-# LANGUAGE ScopedTypeVariables, CPP, BangPatterns #-}-{-# OPTIONS_GHC -fwarn-unused-imports #-}--- -Wall -fno-warn-name-shadowing---- | Some experimental support for 'OpenList's, which are streams in--- the 'Par' monad that support constant-time append.--module Control.Monad.Par.OpenList---module Main- (- OpenList(),- empty, singleton, cons, head, tail, length,- close, join,- toList, fromList, toLazyList, - parMapM, parBuild, parBuildM, - openlist_tests, - chaintest, - async_test, lazy_chaintest--- , main-- , IList(..), newCell- )-where --import Control.Monad hiding (join)-import Control.DeepSeq-import Control.Concurrent.MVar-import Control.Monad.Par hiding (parMapM)-import Control.Monad.Par.IList-import Control.Monad.Par.Internal--import Prelude hiding (length,head,tail,drop,take,null)-import qualified Prelude as P--- import System.IO.Unsafe-import GHC.IO (unsafePerformIO, unsafeDupablePerformIO)-import Test.HUnit -import Debug.Trace---- -------------------------------------------------------------------------------- Open Lists -- IVars at the tail.------ These have some of the advantages of imperative lists, such as--- constant time appending, while retaining determinism and having--- O(1) access to the head of the list unlike tree-shaped lists--- (e.g. append-based rather than cons-based).----- An OpenList must be handled functionally. Extending the list as--- an effect will not change its tail pointer.-data OpenList a = OpenList (IList a) (IList a)---- This is likewise a pretty meaningless NFData instance:-instance NFData a => NFData (OpenList a) where - rnf (OpenList hp tp) = rnf hp `seq` rnf tp ----- | An empty open list. Supports further extension.-empty :: OpenList a-empty = OpenList Null Null--null :: OpenList a -> Bool-null (OpenList Null Null) = True-null _ = False---- | A single element open list.-singleton :: a -> Par (OpenList a)-singleton x = - do pv <- new - let cell = Cons x pv- return (OpenList cell cell)---- TODO/FIXME: Need to decide whether there should be closed and open empty lists!!---- | Terminate a non-empty open list so that it cannot be extended further.-close :: NFData a => OpenList a -> Par (OpenList a)-close orig@(OpenList Null _) = return orig-close orig@(OpenList _ tp) = do put (tl tp) Null; return orig----- This version ignores the tail pointer and seeks out the end of the--- list (at the present time).--- unsafeClose :: NFData a => OpenList a -> Par (OpenList a)--- unsafeClose orig@(OpenList Null _) = return orig------ | Destructive append operation.-join :: NFData a => OpenList a -> OpenList a -> Par (OpenList a)-join (OpenList Null _) right = return right-join left (OpenList Null _) = return left -join (OpenList hp1 tp1) (OpenList hp2 tp2) =- do put (tl tp1) hp2- return (OpenList hp1 tp2)---- | Head of an OpenList.-head :: OpenList a -> a-head (OpenList Null _) = error "cannot take head of null OpenList"-head (OpenList hp _) = hd hp--headCell (OpenList hp _) = OpenList hp hp -lastCell (OpenList _ tp) = OpenList tp tp---- | Tail of an OpenList. Beware, if the list contains only one--- element (e.g. the result of tail will be null), it must be CLOSED--- for tail to work.-tail :: OpenList a -> Par (OpenList a)--- NOTE: We could fix this limitation by adding a length field to the OpenList.-tail (OpenList Null _) = error "cannot take tail of null OpenList"-tail (OpenList hp tp) = - do nxt <- get (tl hp)- case nxt of- Null -> return empty- _ -> return (OpenList nxt tp)---drop :: NFData a => Int -> OpenList a -> Par (OpenList a)-drop 0 ls = return ls-drop n ls = do tl <- tail ls- drop (n-1) tl---- This copies a prefix and makes it open once again irrespective of--- whether the input list is open or closed.-take :: NFData a => Int -> OpenList a -> Par (OpenList a)-take 0 ls = return empty-take n ls = do tl <- tail ls- rest <- take (n-1) tl- cons (head ls) rest---- Take the length of a closed OpenList.--- length :: OpenList a -> Par Int-length (OpenList Null _) = return 0--- length (OpenList (Cons a _) (Cons b _)) | a == b = return 1-length ls = do t <- tail ls - len <- length t- return (len+1)---- | Add an element to the front of an OpenList. Works irrespective--- | of whether the input is closed.-cons :: NFData a => a -> OpenList a -> Par (OpenList a)--- Careful, consing should not close the openlist:-cons car (OpenList Null _) = singleton car-cons car (OpenList hp tp) = - do cdr <- newFull_ hp- return (OpenList (Cons car cdr) tp)--newCell x = do pv <-new; return (Cons x pv)---- | Convert a list to an OpenList, open to extension at the tail.-fromList :: NFData a => [a] -> Par (OpenList a)-fromList [] = return empty-fromList (h:t) = - -- This function is inefficient and could be replaced with an additional IList data constructor.- do head <- newCell h- rest <- loop head t- return (OpenList head rest)- where - loop last [] = return last- loop last (h:t) = - do cell <- newCell h- put (tl last) cell- loop cell t---- | Convert a CLOSED OpenList to a list. -toList :: NFData a => (OpenList a) -> Par [a] --- Note: presently not tail-recursive:-toList (OpenList hp _) = loop hp- where - loop Null = return []- loop (Cons head pv) = - do - rest <- get pv- converted <- loop rest- return (head : converted)---- Strict map over closed lists.--- --- parMap for OpenLists does not support a nice divide-and-conquer.--- (Well, it would support the appending if we were willing to scan ahead to find the length.)--- OpenLists are not Traversable... so we can't just use Par.parMap.------ TODO: Perhaps this should use a strategy for each element:--- parMapM :: NFData b => (a -> Par b) -> OpenList a -> Par (OpenList b)-parMapM _ (OpenList Null _) = return empty--- parMapM fn (OpenList (Cons a _) (Cons b _)) | a == b = fn a >>= singleton -parMapM fn ls = - do h <- spawn (fn (head ls))- t <- tail ls- h' <- get h- t2 <- parMapM fn t- cons h' t2---- maybe the following too?--- parMapM_ :: (a -> Par ()) -> OpenList a -> Par () ---- | Build an OpenList with a divide-and-conquer parallel strategy.-parBuild :: NFData a => InclusiveRange -> (Int -> a) -> Par (OpenList a)-parBuild range fn =- parMapReduceRange range (singleton . fn) join empty---- | Build an OpenList with a divide-and-conquer parallel strategy,--- allowing nested parallelism in the per-element computation.-parBuildM :: NFData a => InclusiveRange -> (Int -> Par a) -> Par (OpenList a)-parBuildM range fn =- parMapReduceRange range ((>>= singleton) . fn) join empty----- | OpenLists can only be printed properly in the Par monad. @show@--- on an open list will only give a hint -- what the first and last--- elements of the openlist are.-instance Show a => Show (OpenList a) where - show (OpenList Null _) = "OpenList []"- show (OpenList (Cons fst _) (Cons lst _)) = - "OpenList ["++show fst++".."++ show lst ++"]"-- --debugshow (OpenList (Cons h1 _) (Cons h2 _)) = "Cons|Cons|eq/"++show(h1==h2)-debugshow (OpenList Null Null) = "Null|Null"-debugshow (OpenList Null (Cons _ _)) = error$ "invalid Null|Cons openlist"-debugshow (OpenList (Cons _ _) Null) = error$ "invalid Cons|Null openlist"---- Check the length of an openlist from head pointer to tail pointer--- (not including anything present beyond the tail pointer).--- WARNING: ASSUMES UNIQUE ELEMENTS:-debuglength :: Eq a => OpenList a -> Par Int-debuglength (OpenList Null Null) = return 0-debuglength orig@(OpenList (Cons hp1 tp1) (Cons hp2 tp2))- | hp1 == hp2 = return 1- | otherwise = do rest <- tail orig- sum <- debuglength rest- return (1 + sum)---- -------------------------------------------------------------------------------- Synchronization using native Haskell IVars (e.g. MVars).---- The MList datatype is internal to the module.--- These MVars are only written once:-data MList a = MNull | MCons (a, MVar (MList a))--_unsafe_io :: IO a -> Par a-_unsafe_io io = let x = unsafePerformIO io in- x `seq` return x--_unsafe_dupable :: IO a -> Par a-_unsafe_dupable io = - let x = unsafeDupablePerformIO io in - x `seq` return x---- Return a lazy list:-mListToList :: MList a -> [a]-mListToList MNull = []-mListToList (MCons(hd,tl)) = - let rest = unsafeDupablePerformIO$ - do tl' <- readMVar tl - return (mListToList tl')- in (hd : rest)--iListToMList :: IList a -> Par (MList a)-iListToMList Null = return MNull-iListToMList il = - do mv <- _unsafe_dupable newEmptyMVar- fork $ do t <- get (tl il)- r <- iListToMList t- _unsafe_io$ putMVar mv r- return (MCons (hd il, mv))---- | Asynchronously convert an OpenList to a lazy list. Returns immediately.-toLazyList :: OpenList a -> Par [a]-toLazyList (OpenList head _) = iListToMList head >>= return . mListToList --- toLazyList ol = toMList ol >>= return . mListToList --------- -------------------------------------------------------------------------------- Testing--test_ol0 = runPar (cons 'a' empty >>= cons 'b' >>= close >>= tail >>= tail >>= length)--test_ol1 :: Int-test_ol1 = runPar$ do l :: OpenList Int <- join empty empty- length l--test_ol2 :: String-test_ol2 = show$ runPar$ do - ls1 <- fromList [10,11,12]- ls2 <- singleton (5::Int)- join ls1 ls2--test_ol3 :: [Int]-test_ol3 = runPar$ do ol :: OpenList Int <- fromList [1..10]- close ol- toList ol--test_ol4 :: Int-test_ol4 = runPar$ do ol <- fromList [1..10] - t1 <- tail ol- t2 <- tail t1- return (head t2)--test_ol5 :: Int-test_ol5 = runPar$ fromList ([1..10] :: [Int]) >>= close >>= length--test_ol6 :: [Int]-test_ol6 = runPar$ do- l1 <- fromList [1..10]- close l1- l2 <- parMapM (return . (+ 1)) l1- close l2- toList l2---test_ol7 :: [Int]-test_ol7 = runPar$ do - a <- singleton 1- b <- singleton 2- join a b- close b- toLazyList a--test_ol8 :: [Int]-test_ol8 = runPar$ do - a <- singleton 1- b <- singleton 2- c <- singleton 3- d <- singleton 4- join c d- join a b- join b c- close d- toLazyList a--test_ll :: [Int]-test_ll = runPar$- do l <- fromList [1..1000]- close l - toLazyList l--chaintest :: Int -> Par (IList Int)-chaintest 0 = error "must have chain length >= 1"-chaintest len = loop 0 len - where - loop i 1 = do tl <- if i == len-1 - then newFull_ Null - else new- when (i == len-1) (print_$ " == GOT END: "++show i)- return (Cons i tl)- loop i n =- do let half = n `quot` 2- ifst <- spawn_$ loop i half - fork $ do - snd <- loop (i+half) half- fst <- get ifst- lastfst <- dropIList (half-1) fst - put (tl lastfst) snd- return () - get ifst--dropIList :: NFData a => Int -> IList a -> Par (IList a)-dropIList 0 ls = return ls-dropIList n ls = do rest <- get (tl ls)- dropIList (n-1) rest---- lazy_chaintest i = chaintest i >>= toLazyList-lazy_chaintest :: Int -> Par [Int]-lazy_chaintest i = do il <- chaintest i - ml <- iListToMList il- return (mListToList ml)---- If we create a large, lazy chain, taking just the head should be quick.-async_test = - do putStrLn "BeginTest"--- let lazy = runParAsync$ lazy_chaintest 1048576--- let lazy = runParAsync$ lazy_chaintest 32768- let lazy = runParAsync$ lazy_chaintest 1024--- let lazy = runPar$ lazy_chaintest 1024- putStrLn$ "Resulting list "++ show lazy- putStrLn$ "Got head: "++ show (P.take 3 lazy)- putStrLn "EndTest"------------------------------------------------------------------------------------print_ msg = trace msg $ return ()--dbg0 = debugshow$ runPar$ singleton 'a' >>= close ---- This one is an error:-err1 = debugshow$ runPar$ singleton 'a' >>= tail >>= close --- But this will work:-dbg1 = debugshow$ runPar$ fromList "ab" >>= tail >>= close --dbg2 = debugshow$ runPar$ singleton 'a' >>= close >>= tail ---- This is invalid:-err2 = debugshow$ runPar$ singleton 'a' >>= tail ---- TODO: HUnit These.-openlist_tests :: Test-openlist_tests = - TestList - [- -- First a few small, unnamed tests:- 0 ~=? runPar (length (empty :: OpenList Int)),- "a" ~=? runPar (singleton 'a' >>= close >>= toList),- 1 ~=? runPar (singleton 'a' >>= close >>= length),- 1 ~=? runPar (cons 'b' empty >>= close >>= length),-- TestLabel "singleton, close" $ "Cons|Cons|eq/True" ~=? dbg0,- TestLabel "tail then close - SKETCHY" $ "Cons|Cons|eq/True" ~=? dbg1,- TestLabel "close then tail" $ "Null|Null" ~=? dbg2,--- TestLabel "tail no close" $ "" ~=? dbg3,-- TestLabel "tail of singleton" $ - 0 ~=? runPar (singleton 'a' >>= close >>= tail >>= length),- TestLabel "tail tail of cons cons" $ - 0 ~=? test_ol0,-- TestLabel "join of two empty's still length zero" $ - 0 ~=? test_ol1,- TestLabel "test show instance" $ - "OpenList [10..5]" ~=? test_ol2,-- TestLabel "toList" $ - [1..10] ~=? test_ol3,-- TestLabel "head . tail . tail" $ - 3 ~=? test_ol4,-- TestLabel "length . fromList" $ - 10 ~=? test_ol5,-- TestLabel "test parMap" $ - [2..11] ~=? test_ol6,-- TestLabel "test 7" $ - [1,2] ~=? test_ol7,-- TestLabel "test 8" $ - [1..4] ~=? test_ol8,-- TestLabel "test lazy list conversion" $ - [1..1000] ~=? test_ll,-- TestLabel "chaintest" $- [0..511] ~=? runPar (lazy_chaintest 512),-- TestLabel "asynchronous chaintest" $- [0..511] ~=? runParAsync (lazy_chaintest 512)-- ]--main = async_test
+ Control/Monad/Par/Scheds/Direct.hs view
@@ -0,0 +1,626 @@+{-# LANGUAGE RankNTypes, NamedFieldPuns, BangPatterns,+ ExistentialQuantification, CPP, ScopedTypeVariables,+ TypeSynonymInstances, MultiParamTypeClasses,+ GeneralizedNewtypeDeriving, PackageImports+ #-}++{- OPTIONS_GHC -Wall -fno-warn-name-shadowing -fno-warn-unused-do-bind -}++-- {- LANGUAGE Trustworthy -}+-- TODO: Before declaring this module TRUSTWORTHY/SAFE, we need to+-- make the IVar type abstract.++-- | A scheduler for the Par monad based on directly performing IO+-- actions when Par methods are called (i.e. without using a lazy+-- trace data structure).++module Control.Monad.Par.Scheds.Direct (+ Sched(..), Par,+ IVar(..), IVarContents(..),+-- sched,+ runPar, + new, get, put_, fork,+ newFull, newFull_, put,+ spawn, spawn_, spawnP,+ spawn1_+-- runParAsync, runParAsyncHelper,+-- yield,+ ) where++import Control.Applicative+import Control.Concurrent hiding (yield)+import Debug.Trace+import Data.IORef+import Text.Printf+import GHC.Conc+import "mtl" Control.Monad.Cont as C+import qualified "mtl" Control.Monad.Reader as RD+-- import qualified Data.Array as A+-- import qualified Data.Vector as A+import qualified Data.Sequence as Seq+import System.Random.MWC as Random+import System.IO.Unsafe (unsafePerformIO)+import System.Mem.StableName+import qualified Control.Monad.Par.Class as PC+import qualified Control.Monad.Par.Unsafe as UN+import Control.DeepSeq++-- import Data.Concurrent.Deque.Class as DQ+#ifdef REACTOR_DEQUE+-- These performed ABYSMALLY:+import Data.Concurrent.Deque.ChaseLev+import Data.Concurrent.Deque.ChaseLev.DequeInstance+import qualified Data.Concurrent.Deque.ReactorDeque as R+import Data.Array.IO+#else+import Data.Concurrent.Deque.Class (WSDeque)+import Data.Concurrent.Deque.Reference.DequeInstance+import Data.Concurrent.Deque.Reference as R+#endif++import Prelude hiding (null)+import qualified Prelude++--------------------------------------------------------------------------------+-- Configuration Toggles+--------------------------------------------------------------------------------++-- define DEBUG+#ifdef DEBUG+dbg = True+#else+dbg = False+#endif++#define FORKPARENT+#define WAKEIDLE++--------------------------------------------------------------------------------+-- Core type definitions+--------------------------------------------------------------------------------++-- Our monad stack looks like this:+-- ---------+-- ContT+-- ReaderT+-- IO+-- ---------+-- The ReaderT monad is there for retrieving the scheduler given the+-- fact that the API calls do not get it as an argument.+-- +-- Note that the result type for continuations is unit. Forked+-- computations return nothing.+--+newtype Par a = Par { unPar :: C.ContT () ROnly a }+ deriving (Monad, MonadCont, RD.MonadReader Sched)+type ROnly = RD.ReaderT Sched IO++data Sched = Sched + { + ---- Per worker ----+ no :: {-# UNPACK #-} !Int,+#ifdef REACTOR_DEQUE+ workpool :: R.Deque IOArray (Par ()),+#else+ workpool :: WSDeque (Par ()),+#endif+ rng :: HotVar GenIO, -- Random number gen for work stealing.+ isMain :: Bool, -- Are we the main/master thread? ++ ---- Global data: ----+ killflag :: HotVar Bool,+ idle :: HotVar [MVar Bool],+ scheds :: [Sched] -- A global list of schedulers.+ }++newtype IVar a = IVar (IORef (IVarContents a))++data IVarContents a = Full a | Empty | Blocked [a -> IO ()]++unsafeParIO :: IO a -> Par a +unsafeParIO io = Par (lift$ lift io)+io = unsafeParIO -- shorthand used below++--------------------------------------------------------------------------------+-- Helpers #1: Atomic Variables+--------------------------------------------------------------------------------+-- TEMP: Experimental++#ifndef HOTVAR+#define HOTVAR 1+#endif+newHotVar :: a -> IO (HotVar a)+modifyHotVar :: HotVar a -> (a -> (a,b)) -> IO b+modifyHotVar_ :: HotVar a -> (a -> a) -> IO ()+writeHotVar :: HotVar a -> a -> IO ()+readHotVar :: HotVar a -> IO a+-- readHotVarRaw :: HotVar a -> m a+-- writeHotVarRaw :: HotVar a -> m a++{-# INLINE newHotVar #-}+{-# INLINE modifyHotVar #-}+{-# INLINE modifyHotVar_ #-}+{-# INLINE readHotVar #-}+{-# INLINE writeHotVar #-}+++#if HOTVAR == 1+type HotVar a = IORef a+newHotVar = newIORef+modifyHotVar = atomicModifyIORef+modifyHotVar_ v fn = atomicModifyIORef v (\a -> (fn a, ()))+readHotVar = readIORef+writeHotVar = writeIORef+instance Show (IORef a) where + show ref = "<ioref>"++-- hotVarTransaction = id+hotVarTransaction = error "Transactions not currently possible for IO refs"+readHotVarRaw = readHotVar+writeHotVarRaw = writeHotVar+++#elif HOTVAR == 2 +#warning "Using MVars for hot atomic variables."+-- This uses MVars that are always full with *something*+type HotVar a = MVar a+newHotVar x = do v <- newMVar; putMVar v x; return v+modifyHotVar v fn = modifyMVar v (return . fn)+modifyHotVar_ v fn = modifyMVar_ v (return . fn)+readHotVar = readMVar+writeHotVar v x = do swapMVar v x; return ()+instance Show (MVar a) where + show ref = "<mvar>"++-- hotVarTransaction = id+-- We could in theory do this by taking the mvar to grab the lock.+-- But we'd need some temporary storage....+hotVarTransaction = error "Transactions not currently possible for MVars"+readHotVarRaw = readHotVar+writeHotVarRaw = writeHotVar+++#elif HOTVAR == 3+#warning "Using TVars for hot atomic variables."+-- Simon Marlow said he saw better scaling with TVars (surprise to me):+type HotVar a = TVar a+newHotVar = newTVarIO+modifyHotVar tv fn = atomically (do x <- readTVar tv + let (x2,b) = fn x+ writeTVar tv x2+ return b)+modifyHotVar_ tv fn = atomically (do x <- readTVar tv; writeTVar tv (fn x))+readHotVar x = atomically $ readTVar x+writeHotVar v x = atomically $ writeTVar v x+instance Show (TVar a) where + show ref = "<tvar>"++hotVarTransaction = atomically+readHotVarRaw = readTVar+writeHotVarRaw = writeTVar++#endif+++-----------------------------------------------------------------------------+-- Helpers #2: Pushing and popping work.+-----------------------------------------------------------------------------++{-# INLINE popWork #-}+popWork :: Sched -> IO (Maybe (Par ()))+popWork Sched{ workpool, no } = do + mb <- R.tryPopL workpool + if dbg + then case mb of + Nothing -> return Nothing+ Just x -> do sn <- makeStableName mb+ printf " [%d] -> POP work unit %d\n" no (hashStableName sn)+ return mb+ else return mb++{-# INLINE pushWork #-}+pushWork :: Sched -> Par () -> IO ()+pushWork Sched { workpool, idle, no, isMain } task = do+-- modifyHotVar_ workpool (`pushL` task)+ R.pushL workpool task+ when dbg $ do sn <- makeStableName task+ printf " [%d] -> PUSH work unit %d\n" no (hashStableName sn)+#ifdef WAKEIDLE+ --when isMain$ -- Experimenting with reducing contention by doing this only from a single thread.+ -- TODO: We need to have a proper binary wakeup-tree.+ tryWakeIdle idle+#endif+++tryWakeIdle idle = do+-- NOTE: I worry about having the idle var hammmered by all threads on their spawn-path:+ -- If any worker is idle, wake one up and give it work to do.+ idles <- readHotVar idle -- Optimistically do a normal read first.+ when (not (Prelude.null idles)) $ do+ when dbg$ printf "Waking %d idle thread(s).\n" (length idles)+ r <- modifyHotVar idle (\is -> case is of+ [] -> ([], return ())+ (i:is) -> (is, putMVar i False))+ r -- wake an idle worker up by putting an MVar.++rand :: HotVar GenIO -> IO Int+rand ref = Random.uniformR (0, numCapabilities-1) =<< readHotVar ref++--------------------------------------------------------------------------------+-- Running computations in the Par monad+--------------------------------------------------------------------------------++instance NFData (IVar a) where+ rnf _ = ()++runPar userComp = unsafePerformIO $ do+ +#if __GLASGOW_HASKELL__ >= 701 /* 20110301 */+ --+ -- We create a thread on each CPU with forkOnIO. The CPU on which+ -- the current thread is running will host the main thread; the+ -- other CPUs will host worker threads.+ --+ -- Note: GHC 7.1.20110301 is required for this to work, because that+ -- is when threadCapability was added.+ --+ (main_cpu, _) <- threadCapability =<< myThreadId+#else+ --+ -- Lacking threadCapability, we always pick CPU #0 to run the main+ -- thread. If the current thread is not running on CPU #0, this+ -- will require some data to be shipped over the memory bus, and+ -- hence will be slightly slower than the version above.+ --+ let main_cpu = 0+#endif+ allscheds <- makeScheds main_cpu++ m <- newEmptyMVar+ forM_ (zip [0..] allscheds) $ \(cpu,sched) ->+ forkOnIO cpu $+ if (cpu /= main_cpu)+ then do when dbg$ printf " [%d] Entering scheduling loop.\n" cpu+ runReaderWith sched $ rescheduleR errK+ when dbg$ printf " [%d] Exited scheduling loop. FINISHED.\n" cpu+ else do+ let userComp' = do when dbg$ io$ printf " [%d] Starting Par computation on main thread.\n" main_cpu+ res <- userComp+ finalSched <- RD.ask + when dbg$ io$ printf " [%d] Out of Par computation on main thread. Writing MVar...\n" (no finalSched)++ -- Sanity check our work queues:+ when dbg $ io$ sanityCheck allscheds+ io$ putMVar m res+ + RD.runReaderT (C.runContT (unPar userComp') trivialCont) sched+ when dbg$ do putStrLn " *** Out of entire runContT user computation on main thread."+ sanityCheck allscheds+ -- Not currently requiring that other scheduler threads have exited before we + -- (the main thread) exit. But we do signal here that they should terminate:+ writeIORef (killflag sched) True++ when dbg$ do putStrLn " *** Reading final MVar on main thread."+ takeMVar m -- Final value.+++-- Make sure there is no work left in any deque after exiting.+sanityCheck :: [Sched] -> IO ()+sanityCheck allscheds = do+ forM_ allscheds $ \ Sched{no, workpool} -> do+ b <- R.nullQ workpool+ when (not b) $ do + printf "WARNING: After main thread exited non-empty queue remains for worker %d\n" no+ putStrLn "Sanity check complete."+++-- Create the default scheduler(s) state:+makeScheds main = do+ workpools <- replicateM numCapabilities $ R.newQ+ rngs <- replicateM numCapabilities $ Random.create >>= newHotVar + idle <- newHotVar [] + killflag <- newHotVar False+ let allscheds = [ Sched { no=x, idle, killflag, isMain= (x==main),+ workpool=wp, scheds=allscheds, rng=rng+ }+ | (x,wp,rng) <- zip3 [0..] workpools rngs]+ return allscheds++++--------------------------------------------------------------------------------+-- IVar operations+--------------------------------------------------------------------------------++{-# INLINE new #-}+-- | creates a new @IVar@+new :: Par (IVar a)+new = io$ do r <- newIORef Empty+ return (IVar r)++{-# INLINE get #-}+-- | read the value in a @IVar@. The 'get' can only return when the+-- value has been written by a prior or parallel @put@ to the same+-- @IVar@.+get iv@(IVar v) = do + callCC $ \cont -> + do+ e <- io$ readIORef v+ case e of+ Full a -> return a+ _ -> do+ sch <- RD.ask+# ifdef DEBUG+ sn <- io$ makeStableName iv+ let resched = trace (" ["++ show (no sch) ++ "] - Rescheduling on unavailable ivar "++show (hashStableName sn)++"!") +#else+ let resched = +# endif+ reschedule+ -- Because we continue on the same processor the Sched stays the same:+ -- TODO: Try NOT using monads as first class values here. Check for performance effect:+ r <- io$ atomicModifyIORef v $ \e -> case e of+ Empty -> (Blocked [pushWork sch . cont], resched)+ Full a -> (Full a, return a)+ Blocked ks -> (Blocked (pushWork sch . cont:ks), resched)+ r++-- | NOTE unsafePeek is NOT exposed directly through this module. (So+-- this module remains SAFE in the Safe Haskell sense.) It can only+-- be accessed by importing Control.Monad.Par.Unsafe.+{-# INLINE unsafePeek #-}+unsafePeek iv@(IVar v) = do + e <- io$ readIORef v+ case e of + Full a -> return (Just a)+ _ -> return Nothing++{-# INLINE put_ #-}+-- | @put_@ is a version of @put@ that is head-strict rather than fully-strict.+put_ iv@(IVar v) !content = do+ sched <- RD.ask + io$ do + ks <- atomicModifyIORef v $ \e -> case e of+ Empty -> (Full content, [])+ Full _ -> error "multiple put"+ Blocked ks -> (Full content, ks)++#ifdef DEBUG+ sn <- makeStableName iv+ printf " [%d] Put value %s into IVar %d. Waking up %d continuations.\n" + (no sched) (show content) (hashStableName sn) (length ks)+#endif+ mapM_ ($content) ks+ return ()+++-- | NOTE unsafeTryPut is NOT exposed directly through this module. (So+-- this module remains SAFE in the Safe Haskell sense.) It can only+-- be accessed by importing Control.Monad.Par.Unsafe.+{-# INLINE unsafeTryPut #-}+unsafeTryPut iv@(IVar v) !content = do+ -- Head strict rather than fully strict.+ sched <- RD.ask + io$ do + (ks,res) <- atomicModifyIORef v $ \e -> case e of+ Empty -> (Full content, ([], content))+ Full x -> (Full x, ([], x))+ Blocked ks -> (Full content, (ks, content))+#ifdef DEBUG+ sn <- makeStableName iv+ printf " [%d] unsafeTryPut: value %s in IVar %d. Waking up %d continuations.\n" + (no sched) (show content) (hashStableName sn) (length ks)+#endif+ mapM_ ($content) ks+ return res+++-- TODO: Continuation (parent) stealing version.+{-# INLINE fork #-}+fork :: Par () -> Par ()+#ifdef FORKPARENT+#warning "FORK PARENT POLICY USED"+fork task = do + sched <- RD.ask + callCC$ \parent -> do+ let wrapped = parent ()+ -- Is it possible to slip in a new Sched here?+ -- let wrapped = lift$ RD.runReaderT (parent ()) undefined+ io$ pushWork sched wrapped+ -- Then execute the child task and return to the scheduler when it is complete:+ task + -- If we get to this point we have finished the child task:+ reschedule -- We reschedule to pop the cont we pushed.+ io$ putStrLn " !!! ERROR: Should not reach this point #1" ++ when dbg$ do + sched2 <- RD.ask + io$ printf " called parent continuation... was on cpu %d now on cpu %d\n" (no sched) (no sched2)++#else+fork task = do+ sch <- RD.ask+ io$ when dbg$ printf " [%d] forking task...\n" (no sch)+ io$ pushWork sch task+#endif+ +-- This routine "longjmp"s to the scheduler, throwing out its own continuation.+reschedule :: Par a +reschedule = Par $ C.ContT rescheduleR++-- Reschedule ignores its continuation.+-- It runs the scheduler loop indefinitely, until it observers killflag==True+rescheduleR :: ignoredCont -> ROnly ()+rescheduleR k = do+ mysched <- RD.ask + when dbg$ liftIO$ printf " [%d] - Reschedule...\n" (no mysched)+ mtask <- liftIO$ popWork mysched+ case mtask of+ Nothing -> do k <- liftIO$ readIORef (killflag mysched) + unless k $ do + liftIO$ steal mysched+#ifdef WAKEIDLE+-- io$ tryWakeIdle (idle mysched)+#endif+ rescheduleR errK+ Just task -> do+ -- When popping work from our own queue the Sched (Reader value) stays the same:+ when dbg $ do sn <- liftIO$ makeStableName task+ liftIO$ printf " [%d] popped work %d from own queue\n" (no mysched) (hashStableName sn)+ let C.ContT fn = unPar task + -- Run the stolen task with a continuation that returns to the scheduler if the task exits normally:+ fn (\ () -> do + sch <- RD.ask+ when dbg$ liftIO$ printf " + task finished successfully on cpu %d, calling reschedule continuation..\n" (no sch)+ rescheduleR errK)++{-# INLINE runReaderWith #-}+runReaderWith state m = RD.runReaderT m state+++-- | Attempt to steal work or, failing that, give up and go idle.+steal :: Sched -> IO ()+steal mysched@Sched{ idle, scheds, rng, no=my_no } = do+ when dbg$ printf " [%d] + stealing\n" my_no+ i <- getnext (-1 :: Int)+ go maxtries i+ where+-- maxtries = numCapabilities -- How many times should we attempt theft before going idle?+ maxtries = 20 * numCapabilities -- How many times should we attempt theft before going idle?++ getnext _ = rand rng++ ----------------------------------------+ -- IDLING behavior:+ go 0 _ = + do m <- newEmptyMVar+ r <- modifyHotVar idle $ \is -> (m:is, is)+ if length r == numCapabilities - 1+ then do+ when dbg$ printf " [%d] | initiating shutdown\n" my_no+ mapM_ (\m -> putMVar m True) r+ else do+ done <- takeMVar m+ if done+ then do+ when dbg$ printf " [%d] | shutting down\n" my_no+ return ()+ else do+ when dbg$ printf " [%d] | woken up\n" my_no+ i <- getnext (-1::Int)+ go maxtries i+ ----------------------------------------+ go tries i+ | i == my_no = do i' <- getnext i+ go (tries-1) i'++ | otherwise = do+ let schd = scheds!!i+ when dbg$ printf " [%d] | trying steal from %d\n" my_no (no schd)++-- let dq = workpool schd :: WSDeque (Par ())+ let dq = workpool schd + r <- R.tryPopR dq++ case r of+ Just task -> do+ when dbg$ do sn <- makeStableName task+ printf " [%d] | stole work (unit %d) from cpu %d\n" my_no (hashStableName sn) (no schd)+ runReaderWith mysched $ + C.runContT (unPar task)+ (\_ -> do+ when dbg$ do sn <- liftIO$ makeStableName task+ liftIO$ printf " [%d] | DONE running stolen work (unit %d) from %d\n" my_no (hashStableName sn) (no schd)+ return ())++ Nothing -> do i' <- getnext i+ go (tries-1) i'++errK = error "this closure shouldn't be used"+trivialCont _ = +#ifdef DEBUG+ trace "trivialCont evaluated!"+#endif+ return ()++----------------------------------------------------------------------------------------------------+++--------------------------------------------------------------------------------+-- <boilerplate>++-- TEMP: TODO: Factor out this boilerplate somehow.++{-# INLINE spawn1_ #-}+-- Spawn a one argument function instead of a thunk. This is good for debugging if the value supports "Show".+spawn1_ f x = +#ifdef DEBUG+ do sn <- io$ makeStableName f+ sch <- RD.ask; when dbg$ io$ printf " [%d] spawning fn %d with arg %s\n" (no sch) (hashStableName sn) (show x)+#endif+ spawn_ (f x)++-- The following is usually inefficient! +newFull_ a = do v <- new+ put_ v a+ return v++newFull a = deepseq a (newFull_ a)++{-# INLINE put #-}+put v a = deepseq a (put_ v a)++spawn p = do r <- new; fork (p >>= put r); return r+spawn_ p = do r <- new; fork (p >>= put_ r); return r+spawnP a = spawn (return a)++-- In Debug mode we require that IVar contents be Show-able:+#ifdef DEBUG+put :: (Show a, NFData a) => IVar a -> a -> Par ()+spawn :: (Show a, NFData a) => Par a -> Par (IVar a)+spawn_ :: Show a => Par a -> Par (IVar a)+spawn1_ :: (Show a, Show b) => (a -> Par b) -> a -> Par (IVar b)+put_ :: Show a => IVar a -> a -> Par ()+get :: Show a => IVar a -> Par a+runPar :: Show a => Par a -> a +newFull :: (Show a, NFData a) => a -> Par (IVar a)+newFull_ :: Show a => a -> Par (IVar a)+#else+spawn :: NFData a => Par a -> Par (IVar a)+spawn_ :: Par a -> Par (IVar a)+spawn1_ :: (a -> Par b) -> a -> Par (IVar b)+put_ :: IVar a -> a -> Par ()+put :: NFData a => IVar a -> a -> Par ()+get :: IVar a -> Par a+runPar :: Par a -> a +newFull :: NFData a => a -> Par (IVar a)+newFull_ :: a -> Par (IVar a)+++instance PC.ParFuture IVar Par where+ get = get+ spawn = spawn+ spawn_ = spawn_+ spawnP = spawnP++instance PC.ParIVar IVar Par where+ fork = fork+ new = new+ put_ = put_+ newFull = newFull+ newFull_ = newFull_++instance UN.ParUnsafe IVar Par where+ unsafePeek = unsafePeek+ unsafeTryPut = unsafeTryPut+ unsafeParIO = unsafeParIO+#endif++instance Functor Par where+ fmap f xs = xs >>= return . f++instance Applicative Par where+ (<*>) = ap+ pure = return+-- </boilerplate>+--------------------------------------------------------------------------------
+ Control/Monad/Par/Scheds/Sparks.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE MultiParamTypeClasses #-}++-- | This scheduler uses sparks (par/pseq) directly, but only supplies+-- the @Monad.Par.Class.ParFuture@ interface.++module Control.Monad.Par.Scheds.Sparks+ (+ Par(..), Future(..),+ runPar, + get, spawn, spawn_, spawnP+ ) +where ++import Control.Applicative+import Control.Monad+import Control.DeepSeq+import Control.Parallel+import qualified Control.Monad.Par.Class as PC+-- import Control.Parallel.Strategies (rpar)++{-# INLINE runPar #-}+{-# INLINE spawn #-}+{-# INLINE spawn_ #-}+{-# INLINE spawnP #-}+{-# INLINE get #-}++data Par a = Done a+data Future a = Future a++runPar :: Par a -> a+runPar (Done x) = x++spawn_ :: Par a -> Par (Future a)+-- spawn_ a = do a' <- rpar (runPar a); return (Future a')+spawn_ a = let a' = runPar a in a' `par` return (Future a')++spawn :: NFData a => Par a -> Par (Future a)+spawn a = let a' = runPar a in a' `par` return (Future (rnf a' `pseq` a'))++spawnP :: NFData a => a -> Par (Future a)+spawnP a = a `par` return (Future (rnf a `pseq` a))++get :: Future a -> Par a+get (Future a) = a `pseq` return a++--------------------------------------------------------------------------------+-- <boilerplate>++instance Monad Par where+ return x = Done x+ Done x >>= k = k x++instance PC.ParFuture Future Par where + get = get+ spawn = spawn+ spawn_ = spawn_+ spawnP = spawnP++instance Functor Par where+ fmap f xs = xs >>= return . f++instance Applicative Par where+ (<*>) = ap+ pure = return++-- </boilerplate>+--------------------------------------------------------------------------------
+ Control/Monad/Par/Scheds/Trace.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE RankNTypes, NamedFieldPuns, BangPatterns,+ ExistentialQuantification, MultiParamTypeClasses, CPP+ #-}+{- OPTIONS_GHC -Wall -fno-warn-name-shadowing -fwarn-unused-imports -}++{- | This is the scheduler described in the paper "A Monad for+ Deterministic Parallelism". It is based on a lazy @Trace@ data+ structure that separates the scheduler from the @Par@ monad+ method implementations.++ -}++module Control.Monad.Par.Scheds.Trace (+ Par, runPar, fork,+ IVar, new, newFull, newFull_, get, put, put_,+ spawn, spawn_, spawnP + ) where++import qualified Control.Monad.Par.Class as PC+import Control.Monad.Par.Scheds.TraceInternal+import Control.DeepSeq+import Control.Monad as M hiding (mapM, sequence, join)+import Prelude hiding (mapM, sequence, head,tail)++-- -----------------------------------------------------------------------------++-- Not in 6.12: {- INLINABLE fork -}+{-# INLINE fork #-}+fork :: Par () -> Par ()+fork p = Par $ \c -> Fork (runCont p (\_ -> Done)) (c ())++-- --------------------------------------------------------------------------------+-- -- Standard instances:++-- <boilerplate>+spawn p = do r <- new; fork (p >>= put r); return r+spawn_ p = do r <- new; fork (p >>= put_ r); return r+-- </boilerplate>>++spawnP :: NFData a => a -> Par (IVar a)+spawnP a = spawn (return a)++instance PC.ParFuture IVar Par where+ get = get+ spawn = spawn+ spawn_ = spawn_+ spawnP = spawnP++instance PC.ParIVar IVar Par where + fork = fork + new = new+ put = put+ put_ = put_+ newFull = newFull+ newFull_ = newFull_+-- yield = yield
+ Control/Monad/Par/Scheds/TraceInternal.hs view
@@ -0,0 +1,595 @@+{-# LANGUAGE RankNTypes, NamedFieldPuns, BangPatterns,+ ExistentialQuantification, CPP, ParallelListComp+ #-}+{- OPTIONS_GHC -Wall -fno-warn-name-shadowing -fno-warn-unused-do-bind -}++-- | This module exposes the internals of the @Par@ monad so that you+-- can build your own scheduler or other extensions. Do not use this+-- module for purposes other than extending the @Par@ monad with new+-- functionality.++module Control.Monad.Par.Scheds.TraceInternal (+ Trace(..), Sched(..), Par(..),+ IVar(..), IVarContents(..),+ sched,+ runPar, runParAsync, runParAsyncHelper,+ new, newFull, newFull_, get, put_, put,+ pollIVar, yield,+ ) where+++import Control.Monad as M hiding (sequence, join)+import Prelude hiding (mapM, sequence)+import Data.IORef+import System.IO.Unsafe+import Control.Concurrent hiding (yield)+import GHC.Conc hiding (yield)+import Control.DeepSeq+import Control.Applicative+import Data.Array+import Data.List (partition, find)+--import Text.Printf+++-- ---------------------------------------------------------------------------+-- MAIN SCHEDULING AND RUNNING+-- ---------------------------------------------------------------------------++data Trace = forall a . Get (IVar a) (a -> Trace)+ | forall a . Put (IVar a) a Trace+ | forall a . New (IVarContents a) (IVar a -> Trace)+ | Fork Trace Trace+ | Done+ | Yield Trace++data Sched = Sched+ { no :: {-# UNPACK #-} !ThreadNumber,+ -- ^ The threadnumber of this worker+ workpool :: IORef WorkPool,+ -- ^ The workpool for this worker+ status :: IORef AllStatus,+ -- ^ The Schedulers' status+ scheds :: Array ThreadNumber Sched,+ -- ^ The list of all workers by thread+ tId :: IORef ThreadId+ -- ^ The ThreadId of this worker+ }++type ThreadNumber = Int+type UId = Int+type CountRef = IORef Int+type WorkLimit = (UId, CountRef)+-- ^ The UId and the count of tasks left or Nothing if there's no limit+-- When the UId is -1, it means that the worker will remain alive until +-- purposely killed (by globalThreadShutdown).+--+-- The reason for a work limit is to make sure that nested threads properly exit.+-- Imagine a scenario where thread A, a worker thread, encounters a runPar. It +-- recursively enters worker status, but it needs ot leave worker status at some +-- point to finish the task that caused it to call runPar. Suppose now that it +-- encounters another call to runPar. If it has the ability to finish and return, +-- we must make sure it returns first for the nested runPar or else it will return +-- to the wrong place! The work limit helps achieve this.+--+-- TODO: Perhaps the work limit need not restrict what a thread can work on, but +-- instead it simply provides the singular point that a thread is allowed to return +-- from. The only concern is some potential for bad blocking - is that a legit +-- concern?++isWLUId :: WorkLimit -> (UId -> Bool) -> Bool+--isWLUId Nothing _ = False+isWLUId (uid, _) op = op uid++shouldEndWorkSet :: WorkLimit -> IO Bool+shouldEndWorkSet (u,_) | u == -1 = return False+shouldEndWorkSet (_, cr) = do+ c <- readIORef cr+ return (c == 0)++idleAtWL :: WorkLimit -> MVar Bool -> Idle+--idleAtWL Nothing m = Idle Nothing m+idleAtWL (uid, _) m = Idle uid m++-- | The main scheduler loop.+-- This takes the synchrony flag, our Sched, the particular work queue we're+-- currently working on, the uid of the work queue (for pushing work), our +-- work limit, and the already-popped, first trace in the work queue.+--+-- INVARIANT: This should only be called by threads who ARE currently marked+-- as working.+sched :: Bool -> WorkLimit -> Sched -> (IORef [Trace]) -> UId -> Trace -> IO ()+sched _doSync wl q@Sched{status, workpool} queueref uid t = loop t+ where + loop t = case t of+ New a f -> do+ r <- newIORef a+ loop (f (IVar r))+ Get (IVar v) c -> do+ e <- readIORef v+ case e of+ Full a -> loop (c a)+ _other -> do+ r <- atomicModifyIORef v $ \e -> case e of+ Empty -> (Blocked [c], go)+ Full a -> (Full a, loop (c a))+ Blocked cs -> (Blocked (c:cs), go)+ r+ Put (IVar v) a t -> do+ cs <- atomicModifyIORef v $ \e -> case e of+ Empty -> (Full a, [])+ Full _ -> error "multiple put"+ Blocked cs -> (Full a, cs)+ mapM_ (pushWork status uid queueref . ($a)) cs+ loop t+ Fork child parent -> do+ pushWork status uid queueref child+ loop parent+ Done ->+ if _doSync+ then go+ -- We could fork an extra thread here to keep numCapabilities workers+ -- even when the main thread returns to the runPar caller...+ else do -- putStrLn " [par] Forking replacement thread..\n"+ forkIO go; return ()+ -- But even if we don't we are not orphaning any work in this+ -- thread's work-queue because it can be stolen by other threads.+ -- else return ()++ Yield parent -> do + -- Go to the end of the worklist:+ -- TODO: Perhaps consider Data.Seq here.+ -- This would also be a chance to steal and work from opposite ends of the queue.+ atomicModifyIORef queueref $ \ts -> (ts++[parent],())+ go+ go = do+ mt <- atomicPopIORef queueref+ case mt of+ Just t -> loop t+ Nothing -> do+ -- SCARY: we better be working on the top queue in the pool!+ cr <- wpRemoveWork uid workpool+ workDone <- decWorkerCount uid cr status+ -- If this uid is our workLimit id AND worker count == 0, then + -- we should just return () rather than calling reschedule q+ unless (isWLUId wl (== uid) && workDone) $+ reschedule wl q+++-- | Process the next work queue on the work pool, or failing that, go into +-- work stealing mode.+--+-- INVARIANT: This should only be called by threads who are NOT currently +-- marked as working (or if they are, the task they were working +-- on executed a runPar).+reschedule :: WorkLimit -> Sched -> IO ()+reschedule wl q@Sched{ workpool, status } = do+ wp <- readIORef workpool+ case wp of+ Work uid cr wqref _ | isWLUId wl (uid >=) -> do+ incWorkerCount cr+ nextTrace <- atomicPopIORef wqref+ case nextTrace of+ Just t -> sched True wl q wqref uid t+ Nothing -> do+ wpRemoveWork uid workpool+ workDone <- decWorkerCount uid cr status+ -- If this uid is our workLimit id AND worker count == 0, then + -- we should just return () rather than calling reschedule q+ unless (isWLUId wl (== uid) && workDone) $+ reschedule wl q+ _ -> steal wl q+++-- RRN: Note -- NOT doing random work stealing breaks the traditional+-- Cilk time/space bounds if one is running strictly nested (series+-- parallel) programs.++-- | Attempt to steal work or, failing that, give up and go idle.+steal :: WorkLimit -> Sched -> IO ()+steal wl q@Sched{ status, scheds, no=my_no } = + -- printf "cpu %d stealing\n" my_no >> + go l+ where+ (l,u) = bounds scheds+ go n+ | n > u = do+ -- Prepare to go idle+ m <- newEmptyMVar+ atomicModifyIORef status $ addIdler (idleAtWL wl m)+ -- Check to see if this workset is ready to close+ s <- shouldEndWorkSet wl+ if s+ then do+ -- Time to close this workset+ --printf "cpu %d shutting down workset %d\n" my_no myPriLimit+ endWorkSet status (fst wl)+ return ()+ else do+ -- There's more work being done here, so I'll go idle+ finished <- takeMVar m+ unless finished $ go l+ | n == my_no = go (n+1)+ | otherwise = readIORef (workpool (scheds!n)) >>= tryToSteal+ where+ tryToSteal (Work uid cr wqref wp) | isWLUId wl (uid >=) = do+ incWorkerCount cr+ stolenTrace <- atomicPopIORef wqref+ case stolenTrace of+ Nothing -> decWorkerCount uid cr status >> tryToSteal wp+ Just t -> do+ sublst <- newIORef []+ atomicModifyIORef (workpool q) $ \wp' -> (Work uid cr sublst wp', ())+ sched True wl q sublst uid t+ tryToSteal _ = go (n+1)+++-- ---------------------------------------------------------------------------+-- UTILITY FUNCTIONS+-- ---------------------------------------------------------------------------++-- | Push work. Then, find an idle worker with uid less than the pushed work.+-- If one is found, wake it up.+pushWork :: IORef AllStatus -> UId -> (IORef [Trace]) -> Trace -> IO ()+pushWork status uid wqref t = do+ atomicModifyIORef wqref $ (\ts -> (t:ts, ()))+ allstatus <- readIORef status+ when (hasIdleWorker uid allstatus) $ do+ r <- atomicModifyIORef status $ getIdleWorker uid+ case r of+ Just b -> putMVar b False+ Nothing -> return ()++-- | A utility function for decreasing the task count of a work set.+-- If the count becomes 0, endWorkSet is called on the work set.+decWorkerCount :: UId -> CountRef -> IORef AllStatus -> IO Bool+decWorkerCount uid countref status = do+ done <- atomicModifyIORef countref $ + (\n -> if n == 0 then error "Impossible value in decWorkerCount" else (n-1, n == 1))+ when done $ (endWorkSet status uid >> globalWorkComplete uid)+ return done++-- | A utility function for increasing the task count of a work set.+incWorkerCount :: CountRef -> IO ()+incWorkerCount countref = do+ atomicModifyIORef countref $ (\n -> (n+1, ()))++-- | A utility for popping an element off of an IORef list.+-- The return value is Just a where a is the head of the list+-- or Nothing if the list is null.+atomicPopIORef :: IORef [a] -> IO (Maybe a)+atomicPopIORef ref = atomicModifyIORef ref $ \lst ->+ case lst of+ [] -> ([], Nothing)+ (e:es) -> (es, Just e)++-- ---------------------------------------------------------------------------+-- IDLING STATUS+-- ---------------------------------------------------------------------------++data Idle = Idle {-# UNPACK #-} !UId (MVar Bool)+data ExtIdle = ExtIdle {-# UNPACK #-} !UId (MVar ())+type AllStatus = ([Idle], [ExtIdle])++-- | A new empty PQueue of Statuses+newStatus :: AllStatus+newStatus = ([], [])++-- | Adds a new Idler to the AllStatus.+addIdler :: Idle -> AllStatus -> (AllStatus, ())+addIdler i@(Idle u _) (is, es) = ((insert is, es), ())+ where insert [] = [i]+ insert xs@(i'@(Idle u' _):xs') = if u <= u'+ then i : xs+ else i' : insert xs'++-- | Adds a new External idler to the AllStatus.+addExtIdler :: ExtIdle -> AllStatus -> (AllStatus, ())+addExtIdler e (is, es) = ((is, e:es), ())++-- | Returns an idle worker with uid less than or equal to the given one +-- (if it exists) and removes it from the AllStatus+getIdleWorker :: UId -> AllStatus -> (AllStatus, Maybe (MVar Bool))+getIdleWorker u q = case q of+ ([],_) -> (q, Nothing)+ ((Idle u' m'):rst, es) -> if u' <= u then ((rst,es), Just m') else (q, Nothing)++-- | Returns true if there is an idle worker with uid less than the given one+hasIdleWorker :: UId -> AllStatus -> Bool+hasIdleWorker uid q = case getIdleWorker uid q of+ (_, Nothing) -> False+ (_, Just _) -> True++-- | Wakes up all idle workers at the given uid with the True signal+endWorkSet :: IORef AllStatus -> UId -> IO ()+endWorkSet status uid = do+ (is, es) <- atomicModifyIORef status $ getAllAtID+ mapM_ (\(ExtIdle _ mb) -> putMVar mb ()) es+ mapM_ (\(Idle _ mb) -> putMVar mb True) is+ where+ getAllAtID (is, es) = ((is', es'), (elems1, elems2))+ where+ (elems1, is') = partition (\(Idle u _) -> u == uid) is+ (elems2, es') = partition (\(ExtIdle u _) -> u == uid) es+++-- ---------------------------------------------------------------------------+-- WorkPool+-- ---------------------------------------------------------------------------++-- | The WorkPool keeps a queue where each element has a UId, a list of +-- traces, and the countRef of how many workers are working on Traces +-- of this UId.+--+-- It should be that by the natural pushing done in sched, this pool +-- should always be in order. We take advantage of this by making +-- guarantees but not actually checking at runtime whether they're true.+data WorkPool = Work {-# UNPACK #-} !UId CountRef (IORef [Trace]) WorkPool | NoWork++-- | Pop the next work queue from the work pool. This should only be called +-- if both the work pool contains a pool, and the queue in that pool is +-- empty. Thus, it should only be called by the pool's owner.+wpRemoveWork :: UId -> IORef WorkPool -> IO CountRef+wpRemoveWork uid pRef = atomicModifyIORef pRef f+ where f :: WorkPool -> (WorkPool, CountRef)+ f (Work uid' cr' _ p') | uid == uid' = (p', cr')+ f (Work uid' cr' wq' p') = + let (p'', cr'') = f p'+ in (Work uid' cr' wq' p'', cr'')+ f NoWork = error "Impossible state in wpRemoveWork"+++-- ---------------------------------------------------------------------------+-- PAR AND IVAR+-- ---------------------------------------------------------------------------++newtype Par a = Par {+ runCont :: (a -> Trace) -> Trace+}++instance Functor Par where+ fmap f m = Par $ \c -> runCont m (c . f)++instance Monad Par where+ return a = Par ($ a)+ m >>= k = Par $ \c -> runCont m $ \a -> runCont (k a) c++instance Applicative Par where+ (<*>) = ap+ pure = return++newtype IVar a = IVar (IORef (IVarContents a))+-- data IVar a = IVar (IORef (IVarContents a))++data IVarContents a = Full a | Empty | Blocked [a -> Trace]++-- Forcing evaluation of a IVar is fruitless.+instance NFData (IVar a) where+ rnf _ = ()++-- From outside the Par computation we can peek. But this is+-- nondeterministic; it should perhaps have "unsafe" in the name.+pollIVar :: IVar a -> IO (Maybe a)+pollIVar (IVar ref) = + do contents <- readIORef ref+ case contents of + Full x -> return (Just x)+ _ -> return (Nothing)+++-- ---------------------------------------------------------------------------+-- GLOBAL THREAD IDENTIFICATION+-- ---------------------------------------------------------------------------++-- Global thread identification is handled byt the globalThreadState object.+-- The main way to interact with this object is to attempt to establish global +-- Scheds, shut down the threads and clear the Scheds, or to mark a work set +-- as complete.++data GlobalThreadState = GTS (Array ThreadNumber Sched) !UId !Int++-- | This is the global thread state variable+globalThreadState :: IORef (Maybe GlobalThreadState)+globalThreadState = unsafePerformIO $ newIORef $ Nothing++-- | This is called when a work set completes (see decWorkerCount).+-- We do this so that we can know if it's okay to do a +-- globalThreadShutdown.+globalWorkComplete :: UId -> IO ()+globalWorkComplete _ = + atomicModifyIORef globalThreadState f+ where f Nothing = error "Impossible state in globalWorkComplete."+ f (Just (GTS retA n c)) = (Just (GTS retA n (c+1)), ())++-- | Attempts to set the global Scheds. If they are already extablished, +-- this returns a Failure with a new UId (to interact with the global +-- threads) and the current global Scheds. Otherwise, it establishes +-- the given array as the global Scheds, and returns a Success containing +-- the UId to use.+data GTSResult = Success UId | Failure UId (Array ThreadNumber Sched)+globalEstablishScheds :: Array ThreadNumber Sched -> IO GTSResult+globalEstablishScheds a = + atomicModifyIORef globalThreadState f+ where f Nothing = (Just (GTS a 1 0), Success 0)+ f (Just (GTS retA n c)) = (Just (GTS retA (n+1) c), Failure n retA)++-- | Attempts to shutdown the global threads. If there are unfinished tasks, +-- this shuts down nothing and returns False. Otherwise, this shuts down +-- all threads, un-establishes the global Scheds, and returns True.+-- If the Scheds are currently unestablished, this does nothing and returns +-- False.+--+-- TODO: This can sometimes leave threads hanging who are not doing any work +-- but have not yet marked themselves as idle. Things won't exactly +-- break, but there may be MVar errors that are thrown.+globalThreadShutdown :: IO Bool+globalThreadShutdown = do + ma <- atomicModifyIORef globalThreadState f+ case ma of+ Nothing -> return False+ Just a -> do+ let s = status $ a ! (fst $ bounds a)+ (is, es) <- atomicModifyIORef s $ \x -> (newStatus, x)+ mapM_ (\(ExtIdle _ m) -> putMVar m ()) es+ mapM_ (\(Idle _ mb) -> putMVar mb True) is+ return True+ where f (Just (GTS a n c)) | n == c = (Nothing, Just a)+ f gts = (gts, Nothing)+++-- ---------------------------------------------------------------------------+-- RUNPAR+-- ---------------------------------------------------------------------------++-- [Notes on threadCapability]+--+-- We create a thread on each CPU with forkOnIO. Ideally, the CPU on +-- which the current thread is running will host the main thread; the +-- other CPUs will host worker threads.+--+-- This is possible using threadCapability, but this requires+-- GHC 7.1.20110301, because that is when threadCapability was added.+--+-- Lacking threadCapability, we always pick CPU #0 to run the main+-- thread. If the current thread is not running on CPU #0, this+-- will require some data to be shipped over the memory bus, and+-- hence will be slightly slower than the version using threadCapability.+--+-- If this is a nested runPar call, then we can do slightly better. We +-- can look at the current workers' ThreadIds and see if we are one of +-- them. If so, we do the work on that core. If not, we are once again +-- forced to choose arbitrarily, so we send the work to CPU #0.+--+++{-# INLINE runPar_internal #-}+runPar_internal :: Bool -> Par a -> a+runPar_internal _doSync x = unsafePerformIO $ do+ -- Set up the schedulers+ myTId <- myThreadId+ tIds <- replicateM numCapabilities $ newIORef myTId+ workpools <- replicateM numCapabilities $ newIORef NoWork+ statusRef <- newIORef newStatus+ let states = listArray (0, numCapabilities-1)+ [ Sched { no=n, workpool=wp, status=statusRef, scheds=states, tId=t }+ | n <- [0..] | wp <- workpools | t <- tIds ]+ res <- globalEstablishScheds states+ case res of+ Success uid -> do+#if __GLASGOW_HASKELL__ >= 701 /* 20110301 */+ -- See [Notes on threadCapability] for more details+ (main_cpu, _) <- threadCapability =<< myThreadId+#else+ let main_cpu = 0+#endif+ currentWorkers <- newIORef 1+ let workLimit' = (-1, undefined)+ let workLimit = (0, currentWorkers)+ + m <- newEmptyMVar+ rref <- newIORef Empty+ atomicModifyIORef statusRef $ addExtIdler (ExtIdle uid m)+ forM_ (elems states) $ \(state@Sched{no=cpu}) -> do+ forkOnIO cpu $ do+ myTId <- myThreadId+ --printf "cpu %d setting threadId=%s\n" cpu (show myTId)+ writeIORef (tId state) myTId+ if (cpu /= main_cpu)+ then reschedule workLimit' state+ else do+ sublst <- newIORef []+ atomicModifyIORef (workpool state) $ \wp -> (Work uid currentWorkers sublst wp, ())+ sched _doSync workLimit state sublst uid $ runCont (x >>= put_ (IVar rref)) (const Done)+ takeMVar m+ --printf "done\n"+ r <- readIORef rref+ + -- TODO: If we're doing this nested strategy, we should probably just keep the + -- threads alive indefinitely. After all, we can get some weird conditions + -- doing it this way. At the least, we should put this in steal where the + -- shutdown occurs.+ b <- globalThreadShutdown+-- putStrLn $ "Global thread shutdown: " ++ show b+ case r of+ Full a -> return a+ _ -> error "no result"++ Failure uid cScheds -> do+#if __GLASGOW_HASKELL__ >= 701 /* 20110301 */+ -- See [Notes on threadCapability] for more details+ (main_cpu, _) <- threadCapability myTId+ cTId <- readIORef $ tId $ cScheds ! main_cpu+ let doWork = cTId == myTId+#else+ cTIds <- mapM (\s -> (readIORef $ tId $ s) >>= (\t -> return (s,t))) (elems cScheds)+ let (main_cpu, doWork) = case find ((== myTId) . snd) cTIds of+ Nothing -> (0, False)+ Just (s,_) -> (no s, True)+#endif+ + rref <- newIORef Empty+ let task = runCont (x >>= put_ (IVar rref)) (const Done)+ state = cScheds ! main_cpu+ if doWork+ then do+ --printf "cpu %d using old threads, of which I am one\n" main_cpu+ currentWorkers <- newIORef 1+ sublst <- newIORef []+ let workLimit = (uid, currentWorkers)+ atomicModifyIORef (workpool state) $ \wp -> (Work uid currentWorkers sublst wp, ())+ sched _doSync workLimit state sublst uid $ task+ else do+ --printf "cpu %d using old threads, of which I am not one\n" main_cpu+ currentWorkers <- newIORef 0+ sublst <- newIORef [task]+ m <- newEmptyMVar+ atomicModifyIORef (status state) $ addExtIdler (ExtIdle uid m)+ atomicModifyIORef (workpool state) $ \wp -> (Work uid currentWorkers sublst wp, ())+ takeMVar m+ --printf "cpu %d finished in child\n" main_cpu+ r <- readIORef rref+-- globalThreadShutdown+ case r of+ Full a -> return a+ _ -> error "no result"++-- | The main way to run a Par computation+runPar :: Par a -> a+runPar = runPar_internal True++-- | An asynchronous version in which the main thread of control in a+-- Par computation can return while forked computations still run in+-- the background. +runParAsync :: Par a -> a+runParAsync = runPar_internal False++-- | An alternative version in which the consumer of the result has+-- the option to "help" run the Par computation if results it is+-- interested in are not ready yet.+runParAsyncHelper :: Par a -> (a, IO ())+runParAsyncHelper = undefined -- TODO: Finish Me.+++-- ---------------------------------------------------------------------------+-- PAR FUNCTIONS+-- ---------------------------------------------------------------------------++new :: Par (IVar a)+new = Par $ New Empty++newFull :: NFData a => a -> Par (IVar a)+newFull x = deepseq x (Par $ New (Full x))++newFull_ :: a -> Par (IVar a)+newFull_ !x = Par $ New (Full x)++get :: IVar a -> Par a+get v = Par $ \c -> Get v c++put_ :: IVar a -> a -> Par ()+put_ v !a = Par $ \c -> Put v a (c ())++put :: NFData a => IVar a -> a -> Par ()+put v a = deepseq a (Par $ \c -> Put v a (c ()))++yield :: Par ()+yield = Par $ \c -> Yield (c ())
− Control/Monad/Par/Stream.hs
@@ -1,367 +0,0 @@-{-# LANGUAGE BangPatterns, CPP #-}-{-# OPTIONS_GHC -fno-warn-name-shadowing -fwarn-unused-imports #-}--- -Wall ---- A module for stream processing built on top of Control.Monad.Par---- (In the future may want to look into the stream interface used by--- the stream fusion framework.)--#define DEBUGSTREAMS--module Control.Monad.Par.Stream - ( - streamMap, streamScan, streamFold- , countupWin, generate- , runParList, toListSpin- , measureRate, measureRateList- , browseStream- , Stream, Window, WStream-- -- TEMP:- , one_second, commaint- )-where-import Control.Monad-import Control.Monad.Par as P-import Control.Monad.Par.IList-import Control.DeepSeq----import qualified Data.Array.Unboxed as U-import Data.Array.Unboxed as U-import Data.Array.CArray as C-import Data.Int-import Data.Word-import Data.List (intersperse)-import Data.List.Split (chunk)--import Foreign.Storable--import System.CPUTime-import System.CPUTime.Rdtsc-import GHC.Conc as Conc-import System.IO-import GHC.IO (unsafePerformIO, unsafeDupablePerformIO, unsafeInterleaveIO)---import Debug.Trace-import Control.Monad.Par.Logging--debugflag = True------------------------------------------------------------------------------------- Types--type Stream a = IVar (IList a)---- A windowed stream passes chunks of stream elements.-type WStream a = Stream (Window a)--#define CARRAY-#ifdef CARRAY-type Window a = CArray Int a-#else-type Window a = U.UArray Int a-#endif-------------------------------------------------------------------------------------- Stream Operators---- | This version applies a function to every element in a stream,--- exposing data parallelism and pipeline parallelism.-streamMapDP :: NFData b => (a -> b) -> Stream a -> Par (Stream b)-streamMapDP fn instrm = - do outstrm <- new- fork$ loop instrm outstrm- return outstrm- where- loop instrm outstrm = - do - ilst <- get instrm- case ilst of - Null -> put outstrm Null -- End of stream.- Cons h t -> - do newtl <- new- h' <- pval (fn h) ---- WARNING: This only makes sense with continuation-stealing.. With child stealing this will go crazy.- fork$ loop t newtl- h'' <- get h'- put outstrm (Cons h'' newtl)- ---- This version exposes pipeline parallelism but no data parallelism.--- It shouldn't be necessary if fork is sufficiently efficient and if--- work stealing is done right.-streamMap :: NFData b => (a -> b) -> Stream a -> Par (Stream b)-streamMap fn instrm = - do outstrm <- new- fork$ loop instrm outstrm- return outstrm- where- loop instrm outstrm = - do - ilst <- get instrm- case ilst of - Null -> put outstrm Null -- End of stream.- Cons h t -> - do newtl <- new- put outstrm (Cons (fn h) newtl)- loop t newtl----- | Applies a stateful kernel to the stream. Output stream elements match input one-to-one.--- streamScan :: (NFData b, NFData c) => -streamScan :: (NFData a, NFData b, NFData c) => -- <- TEMP, don't need NFData a in general.- (a -> b -> (a,c)) -> a -> Stream b -> Par (Stream c)-streamScan fn initstate instrm = - do outstrm <- new- fork$ loop initstate instrm outstrm- return outstrm- where-#ifdef DEBUGSTREAMS- -- Create a task log for each unique input stream fed to this function:- tasklog = unsafeNewTaskSeries (nameFromValue instrm)-#endif-- loop state instrm outstrm = - do - ilst <- get instrm- case ilst of - Null -> put outstrm Null -- End of stream.- Cons h t -> - do newtl <- new- let (newstate, outp) = -#ifdef DEBUGSTREAMS- timePure tasklog$ fn state h-#else- fn state h-#endif- put outstrm (Cons outp newtl)- loop newstate t newtl---- TODO: streamMapM -- monadic version. Define the non-monadic one in--- terms of it and watch for performance regression.----- TODO: More flexible version that passes an "emit" function to the--- kernel so that it may produce zero output elements or more than one.--- This also enables nested parallelism within the kernel.--- --- streamKernel :: ((c -> Par ()) -> a -> b -> Par ()) -> a -> Stream b -> Par (Stream c)------ ALSO: Can have a "concat" operator for streams of lists where--- streamScan . concat rewrites to streamKernel perhaps...------ | Reduce a stream to a single value. This function will not return--- until it reaches the end-of-stream.-streamFold :: (a -> b -> a) -> a -> Stream b -> Par a-streamFold fn acc instrm = - do ilst <- get instrm- case ilst of - Null -> return acc - Cons h t -> streamFold fn (fn acc h) t ---- | Generate a stream of the given length by applying the function to each index (starting at zero).--- --- WARNING, this source calls yield, letting other par computations--- run, but there is no backpressure. Thus if the source runs at a--- higher rate than its consumer, buffered stream elements accumulate.-generate :: NFData a => Int -> (Int -> a) -> Par (Stream a)--- NOTE: I don't currently know of a good way to do backpressure--- directly in this system... but here are some other options: ------ (1) we can use timers and look at maximum sustained rate. ---- (2) Also, we can use coarse grained global barriers. That is, we--- can produce some number of output elements, wait until quiescence--- of all Par computations, and then produce more.---- (3) We can register computations that should only execute when a--- worker goes idle. This is a simple form of priority scheduling.-generate size fn = - do outstrm <- new- fork$ loop (0::Int) outstrm- return outstrm- where - loop n strm | n == size = - do when debugflag (print_$ " [generate] Done. Produced "++ show size++" elements.\n")- put strm Null- return ()- loop n strm = - do - newtl <- new- put strm (Cons (fn n) newtl)- P.yield -- This is necessary to avoid starving others when there- -- aren't enough worker threads to go around.- loop (n+1) newtl----- | Create a [windowed] stream of consecutive integers. Generates at--- least the target number of elements windowed into segments of a--- specified size.-countupWin :: (Storable a, NFData a, Num a) => - Int -> Int -> Par (WStream a)-countupWin bufsize target = - generate num fn- where - num = case r of 0 -> q- _ -> q+1- (q,r) = quotRem target bufsize- fn n = - let start = n * bufsize in- array (start,start + bufsize-1)- [(i, fromIntegral (n + fromIntegral i)) - | i <- [start .. start + bufsize-1]]----measureRate :: Stream a -> IO ()-measureRate strm = - do lazyls <- toListSpin strm- measureRateList lazyls--measureRateList :: [a] -> IO ()-measureRateList lazyls = - do - t0 <- getTime- print_$ " [measureRate] Counting stream rate starting at time: "++ show t0- loop t0 t0 (0::Int64) (0::Int64) lazyls- - where - loop _ _ _ n [] = - do print_$ " [measureRate] Hit end of stream after "++show n++" elements."- return ()-- loop start time lastN n (h:t) = - do - time2 <- getTime- if time2 - time > one_second then do- (print_$ " [measureRate] current rate: "++show (n+1-lastN) ++ - " Total elems&time "++ commaint (n+1)++ " " ++commaint (time2-start))--- print_ (show (n+1))- loop start time2 (n+1) (n+1) t- else do- loop start time lastN (n+1) t----- | Use the keyboard to interactively browse through stream elements.-browseStream :: Show a => Stream a -> IO ()-browseStream strm = - do putStrLn$ "[browseStream] Beginning interactive stream browser, press enter for more elements:"- ls <- toListSpin strm- loop 0 ls- where - loop n ls = - do putStr$ show n ++ "# "- hFlush stdout- c <- getChar - if c == '\EOT' -- User presses ctrl D to exit.- then putStrLn$ "[browseStream] Ctrl-D pressed, exiting."- else case ls of - [] -> putStrLn$ "[browseStream] Reached end of stream after "++show n++" elements."- (h:t) -> do print h- loop (n+1) t-------------------------------------------------------------------------------------- Conversion:---- Convert a stream to a lazy list. Spin wait (with yield) until stream elements are available.-toListSpin :: Stream a -> IO [a]-toListSpin strm = - do x <- pollIVar strm- case x of- Nothing -> do Conc.yield -- run other GHC threads- toListSpin strm -- spin wait- Just (ils) -> - case ils of - Null -> return []- Cons h t -> return (h : unsafePerformIO (unsafeInterleaveIO (toListSpin t)))----- TODO: If it is unavailable we should help run the computation and then try again.--- This version will do runParAsync itself:---- Run a Par computation to produce a stream. Convert that stream to a lazy list.-runParList :: Par (Stream a) -> [a]-runParList = - undefined--- runForList parcomp = loop (runParAsync parcomp) --- where --- loop strm = --- do x <- pollIVar strm--- case x of--- Nothing -> --- -- For now we just spin:--- do yield -- run other GHC threads--- loop strm--- Just (ils) -> --- case ils of --- Null -> return []--- Cons h t -> return (h : unsafePerformIO (unsafeInterleaveIO (loop t)))---------------------------------------------------------------------------------------- Helpers and Scrap:--print_ msg = trace msg $ return ()--_unsafe_io :: IO a -> Par a-_unsafe_io io = let x = unsafePerformIO io in- x `seq` return x--_unsafe_dupable :: IO a -> Par a-_unsafe_dupable io = - let x = unsafeDupablePerformIO io in - x `seq` return x---- This version simply busy-waits to stay on the same core:-measure_freq2 :: IO Word64-measure_freq2 = do --- let second = 1000 * 1000 * 1000 * 1000 -- picoseconds are annoying- let tenth = 100 * 1000 * 1000 * 1000 -- picoseconds are annoying - coef = 10- t1 <- rdtsc - start <- getCPUTime- let loop !n !last = - do t2 <- rdtsc - when (t2 < last) $- putStrLn$ "WARNING, measure_freq2: COUNTERS WRAPPED "++ show (last,t2) - cput <- getCPUTime --- if (cput - start < second) - if (cput - start < tenth)- then loop (n+1) t2- else return (n,t2)- (n,t2) <- loop 0 t1- putStrLn$ " Approx getCPUTime calls per second: "++ commaint (coef * n)- when (t2 < t1) $ - putStrLn$ "WARNING: rdtsc not monotonically increasing, first "++show t1++" then "++show t2++" on the same OS thread"-- return$ coef * fromIntegral (t2 - t1)--commaint :: Integral a => a -> String-commaint n = - reverse $- concat $- intersperse "," $ - chunk 3 $ - reverse (show n)---- Having trouble with this:--- getTime = getCPUTime--- one_second = 1000000000000 -- picoseconds-getTime = rdtsc-one_second = unsafePerformIO$ measure_freq2---instance NFData (U.UArray a b) where - rnf !arr = ()--instance NFData (C.CArray a b) where - rnf !arr = ()
− examples/Makefile
@@ -1,33 +0,0 @@-include common.mk--BENCHMARKS= queens.hs mandel.hs blackscholes.hs nbody.hs parfib.hs primes.hs \- cholesky.hs parfib.hs coins.hs--# binomial_lattice.hs-EXES= $(BENCHMARKS:.hs=.exe)--OTHEREXES= matmult/matmult.exe minimax/minimax.exe sumeuler/sumeuler.exe \- stream/simple1_measureSrc.exe--ALLEXES= $(EXES) $(OTHEREXES)--all: $(EXES)- (cd sumeuler; $(MAKE))- (cd matmult; $(MAKE))- (cd minimax; $(MAKE))- (cd stream; $(MAKE))- (cd partree; $(MAKE))--%.exe : %.hs $(ALLPARSRC)- $(GHC) -O2 --make -i.. $< -o $@ -threaded -rtsopts--runtests: - ./run_tests.sh $(ALLEXES) --clean:- rm -f $(ALLEXES) *.o *.hi - (cd sumeuler; $(MAKE) clean)- (cd matmult; $(MAKE) clean)- (cd minimax; $(MAKE) clean)- (cd stream; $(MAKE) clean)- (cd partree; $(MAKE) clean)
− examples/PortablePixmap.lhs
@@ -1,127 +0,0 @@--\begin{verbatim}-ppm(5) FILE FORMATS ppm(5)--NAME- ppm - portable pixmap file format--DESCRIPTION- The portable pixmap format is a lowest common denominator- color image file format. The definition is as follows:-- - A "magic number" for identifying the file type. A ppm- file's magic number is the two characters "P3".-- - Whitespace (blanks, TABs, CRs, LFs).-- - A width, formatted as ASCII characters in decimal.-- - Whitespace.-- - A height, again in ASCII decimal.-- - Whitespace.-- - The maximum color-component value, again in ASCII decimal.-- - Whitespace.-- - Width * height pixels, each three ASCII decimal values- between 0 and the specified maximum value, starting at the- top-left corner of the pixmap, proceding in normal English- reading order. The three values for each pixel represent- red, green, and blue, respectively; a value of 0 means- that color is off, and the maximum value means that color- is maxxed out.-- - Characters from a "#" to the next end-of-line are ignored- (comments).-- - No line should be longer than 70 characters.-- Here is an example of a small pixmap in this format:- P3- # feep.ppm- 4 4- 15- 0 0 0 0 0 0 0 0 0 15 0 15- 0 0 0 0 15 7 0 0 0 0 0 0- 0 0 0 0 0 0 0 15 7 0 0 0- 15 0 15 0 0 0 0 0 0 0 0 0-- Programs that read this format should be as lenient as pos-- sible, accepting anything that looks remotely like a pixmap.-- There is also a variant on the format, available by setting- the RAWBITS option at compile time. This variant is--Sun Release 4.1 Last change: 15 September 1990 1--ppm(5) FILE FORMATS ppm(5)-- different in the following ways:-- - The "magic number" is "P6" instead of "P3".-- - The pixel values are stored as plain bytes, instead of- ASCII decimal.-- - Whitespace is not allowed in the pixels area, and only a- single character of whitespace (typically a newline) is- allowed after the maxval.-- - The files are smaller and many times faster to read and- write.-- Note that this raw format can only be used for maxvals less- than or equal to 255. If you use the ppm library and try to- write a file with a larger maxval, it will automatically- fall back on the slower but more general plain format.--SEE ALSO- giftoppm(1), gouldtoppm(1), ilbmtoppm(1), imgtoppm(1),- mtvtoppm(1), pcxtoppm(1), pgmtoppm(1), pi1toppm(1), pict-- toppm(1), qrttoppm(1), rawtoppm(1), rgb3toppm(1),- spctoppm(1), sputoppm(1), tgatoppm(1), ximtoppm(1),- xpmtoppm(1), ppmtogif(1), ppmtoicr(1), ppmtoilbm(1),- ppmtopcx(1), ppmtopgm(1), ppmtopi1(1), ppmtopict(1),- ppmtops(1), ppmtopuzz(1), ppmtorgb3(1), ppmtouil(1),- ppmtoxpm(1), ppmhist(1), ppmmake(1), ppmpat(1), ppmquant(1),- ppmquantall(1), ppmrelief(1), pnm(5), pgm(5), pbm(5)--AUTHOR- Copyright (C) 1989, 1991 by Jef Poskanzer.--Sun Release 4.1 Last change: 15 September 1990 2-\end{verbatim}-\begin{code}-module PortablePixmap where--data PixMap = Pixmap Integer Integer Int [(Int,Int,Int)]--createPixmap::Integer -> Integer -> Int -> [(Int,Int,Int)] -> PixMap-createPixmap width height max colours = Pixmap width height max colours--instance Show PixMap where- showsPrec prec (Pixmap x y z rgbs) = showHeader x y z . showRGB rgbs---showHeader::Integer -> Integer -> Int -> ShowS-showHeader x y z = showString "P6\n" . showBanner .- shows x . showReturn .- shows y . showReturn .- shows z . showReturn--showRGB::[(Int,Int,Int)] -> ShowS-showRGB [] = id-showRGB ((r,g,b):rest) = showChar (toEnum r) .- showChar (toEnum g) .- showChar (toEnum b) .- showRGB rest--showSpace = showChar ' '-showReturn = showChar '\n'--showBanner = showString "# Portable pixmap created by Haskell Program :\n" .- showString "#\tPortablePixmap.lhs (Jon.Hill 28/5/92)\n"-\end{code}
− examples/benchlist.txt
@@ -1,27 +0,0 @@-# This is a default set of benchmarks reasonable for a powerful four core machine.--parfib monad 36-parfib sparks 36--blackscholes 10000 15000000--cholesky 1000 50 cholesky_matrix1000.dat--nbody 13000--# mandel 300 300 4000-mandel 2000 2000 3000000--coins 8 1250--stream/disjoint_working_sets_pipeline monad 4 256 10 10000-stream/disjoint_working_sets_pipeline sparks 4 256 10 10000--partree/partree 600 20--# What should the arguments be here:-# minimax/minimax ? ? --# These don't match the naming convention at the moment.-matmult/matmult 768 0 64-sumeuler/sumeuler 38 8000 100
− examples/benchmark.sh
@@ -1,226 +0,0 @@-#!/bin/bash--# Runs benchmarks. Simon Marlow has his own setup. This is just temporary.--# ----------------------------------------------------------------------------# Usage: [set env vars] ./benchmark.sh--# Call it with environment variable SHORTRUN=1 to get a shorter run for-# testing rather than benchmarking.--# Call it with THREADSETTINGS="1 2 4" to run with # threads = 1, 2, or 4.--# Call it with KEEPGOING=1 to keep going after the first error.--# Call it with TRIALS=N to control the number of times each benchmark is run.-# ------------------------------------------------------------------------------# Settings:-# ------------------------------------------if [ "$THREADSETTINGS" == "" ] -then THREADSETTINGS="4"-#then THREADSETTINGS="0 1 2 3 4"-fi--if [ "$GHC" == "" ]; then GHC=ghc; fi--# HACK: with all the intermachine syncing and different version control systems I run into permissions problems sometimes.-chmod +x ./ntime* ./*.sh---# Where to put the timing results:-RESULTS=results.dat-if [ -e $RESULTS ];-then BAK="$RESULTS".bak.`date +%s`- echo "Backing up old results to $BAK"- mv $RESULTS $BAK-fi--# How many times to run a process before taking the best time:-if [ "$TRIALS" == "" ]; then - TRIALS=1-fi--# Determine number of hardware threads on the machine:- if [ -d /sys/devices/system/cpu/ ]; # linux- then - MAXTHREADS=`ls /sys/devices/system/cpu/ | grep "cpu[0123456789]*$" | wc -l`- echo "Detected the number of CPUs on the machine to be $MAXTHREADS"- elif [ `uname` == "Darwin" ];- then MAXTHREADS=`sysctl -n hw.ncpu`- else MAXTHREADS=2- fi --GHC_FLAGS="$GHC_FLAGS -O2 -rtsopts"-GHC_RTS="$GHC_RTS -qa"--# ================================================================================-echo "# TestName Variant NumThreads MinTime MedianTime MaxTime" > $RESULTS-echo "# "`date` >> $RESULTS-echo "# "`uname -a` >> $RESULTS-echo "# "`$GHC -V` >> $RESULTS-echo "# "-echo "# Running each test for $TRIALS trials." >> $RESULTS-echo "# ... with default compiler options: $GHC_FLAGS" >> $RESULTS-echo "# ... with default runtime options: $GHC_RTS" >> $RESULTS--cnt=0--function check_error() -{- CODE=$1- MSG=$2- # Error code 143 was a timeout- if [ "$CODE" == "143" ]- then echo " # Return code $CODE Params: $GHC_FLAGS, RTS $GHC_RTS " | tee -a $RESULTS- echo " # Process TIMED OUT!!" | tee -a $RESULTS- elif [ "$CODE" != "0" ]- then echo " # $MSG" | tee -a $RESULTS- echo " # Error code $CODE Params: $GHC_FLAGS, RTS $GHC_RTS " | tee -a $RESULTS- echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"- if [ "$KEEPGOING" == "" ];- then exit $CODE- fi- fi-}---function runit() -{- cnt=$((cnt+1))- echo - echo "--------------------------------------------------------------------------------"- echo " Running Config $cnt: $test variant threads $NUMTHREADS "- echo "--------------------------------------------------------------------------------"- echo - echo "(In directory `pwd`)"- if [ "$NUMTHREADS" != "0" ] && [ "$NUMTHREADS" != "" ]- then export RTS=" $GHC_RTS -s -N$NUMTHREADS "- export FLAGS=" $GHC_FLAGS -threaded "- else export RTS=""- export FLAGS=" $GHC_FLAGS "- fi-- CONTAININGDIR=`dirname $test`-- # We compile the test case using runcnc:- if [ -e "$test".hs ]; then - FINALARGS="-i../ -i`dirname $test` $FLAGS $test.hs -o $test.exe"- echo "Compiling with a single GHC command: "- echo " $GHC $FINALARGS"- $GHC $FINALARGS- check_error $? "ERROR: compilation failed."-- elif [ -d "$CONTAININGDIR" ] && - [ "$CONTAININGDIR" != "." ] && - [ -e "$CONTAININGDIR/Makefile" ]; then- echo " ** Benchmark appears in a subdirectory with Makefile. Using it."- echo " ** WARNING: Can't currently control compiler options for this benchmark!"- (cd "$CONTAININGDIR/"; make)-- else- echo "ERROR: File does not exist: $test.hs"- exit 1- fi--- echo "Executing $NTIMES $TRIALS $test.exe $ARGS +RTS $RTS -RTS "- if [ "$SHORTRUN" != "" ]; then export HIDEOUTPUT=1; fi-- # One option woud be dynamic feedback where if the first one- # takes a long time we don't bother doing more trials.-- times=`$NTIMES "$TRIALS" ./$test.exe $ARGS +RTS $RTS -RTS`- CODE=$?-- echo " >>> MIN/MEDIAN/MAX TIMES $times"-- check_error $CODE "ERROR: run_all_tests this test failed completely: $test.exe"-- set -- $ARGS-- if [ "$CODE" == "143" ];- then echo "$test.exe" $1 "$NUMTHREADS" "TIMEOUT TIMEOUT TIMEOUT" >> $RESULTS- elif [ "$CODE" != "0" ] ;- then echo "$test.exe" $1 "$NUMTHREADS" "ERR ERR ERR" >> $RESULTS- else - echo "$test.exe" $1 "$NUMTHREADS" "$times" >> $RESULTS- fi-}---echo "Running all tests, for THREADSETTINGS in {$THREADSETTINGS}"-echo--# Hygiene:-make clean-echo; echo;--#====================================================================================================--function run_benchmark() -{- set -- $line- test=$1; shift-- if [ "$SHORTRUN" == "" ];- # If we're in SHORTRUN mode we run each executable with no- # arguments causing it to go to its default (small) problem size.- then ARGS=$*- else ARGS=- fi-- echo "================================================================================"- echo " Running Test: $test.exe $ARGS "- echo "================================================================================"-- echo "# *** Config [$cnt ..], testing with command/args: $test.exe $ARGS " >> $RESULTS--- for NUMTHREADS in $THREADSETTINGS; do- runit- echo >> $RESULTS;- done # threads-- export NUMTHREADS=0-- echo >> $RESULTS;- echo >> $RESULTS;-}--# Read $line and do the benchmark with ntimes_binsearch.sh-function run_binsearch_benchmark() -{- NTIMES=./ntimes_binsearch.sh- run_benchmark- NTIMES=UNSET-}--# Read $line and do the benchmark with ntimes_minmedmax-function run_normal_benchmark() -{- NTIMES=./ntimes_minmedmax- run_benchmark- NTIMES=UNSET-}---#====================================================================================================---if [ "$BENCHLIST" == "" ];-then BENCHLIST="./benchlist.txt"-fi--echo "Reading benchmarks from $BENCHLIST ..."-cat $BENCHLIST | grep -v "\#" | -while read line-do- if [ "$line" == "" ]; then continue; fi- echo RUNNING BENCH: $line- run_normal_benchmark-done--echo "Finished with all test configurations."
− examples/blackscholes.hs
@@ -1,153 +0,0 @@-{-# LANGUAGE RecordWildCards, CPP, ScopedTypeVariables, FlexibleInstances #-}---- Ported from CnC/C++ program by Ryan Newton--- Then ported again from the Haskell-CnC interface to monad-par. [2011.02.16]---- Description--- ===========---- The Black-Scholes equation is a differential equation that describes how,--- under a certain set of assumptions, the value of an option changes as the --- price of the underlying asset changes.---- The formula for a put option is similar. The cumulative normal distribution --- function, CND(x), gives the probability that normally distributed random--- variable will have a value less than x. There is no closed form expression for--- this function, and as such it must be evaluated numerically. The other --- parameters are as follows: S underlying asset's current price, --- X the strike price, T time to the expiration date, r risk-less rate of return,--- and v stock's volatility.---- Usage--- =====---- The command line is:---- blackscholes b n--- b : positive integer for the size of blocks--- n : positive integer for the number of options --- e.g.--- blackscholes 100000 100 4--import Control.Seq-import Control.Monad-import Control.DeepSeq-import Control.Exception--import Control.Monad.Par-import Control.Monad.Par.AList--import Data.Array-import Data.List-import qualified Data.Array.Unboxed as U-import System.Environment------------------------------------------------------------------------------------type FpType = Float---- This tuple contains the inputs for one invocation of our kernel-data ParameterSet = ParameterSet {- sptprice :: FpType,- strike :: FpType,- rate :: FpType,- volatility :: FpType ,- otime :: FpType,- otype :: Bool-} deriving Show--data_init :: Array Int ParameterSet---- This defines some hard coded data as a big constant array:-#include "blackscholes_data.hs"-size_init = let (s,e) = bounds data_init in e - s + 1--inv_sqrt_2xPI = 0.39894228040143270286------------------------------------------------------------------------------------- Scalar code follows:--cndf :: FpType -> FpType-cndf inputX = if sign then 1.0 - xLocal else xLocal- where - sign = inputX < 0.0- inputX' = if sign then -inputX else inputX- - -- Compute NPrimeX term common to both four & six decimal accuracy calcs- xNPrimeofX = inv_sqrt_2xPI * exp(-0.5 * inputX * inputX);-- xK2 = 1.0 / (0.2316419 * inputX + 1.0); - xK2_2 = xK2 * xK2; -- Need all powers of xK2 from ^1 to ^5:- xK2_3 = xK2_2 * xK2;- xK2_4 = xK2_3 * xK2;- xK2_5 = xK2_4 * xK2;- - xLocal = 1.0 - xLocal_1 * xNPrimeofX;- xLocal_1 = xK2 * 0.319381530 + xLocal_2;- xLocal_2 = xK2_2 * (-0.356563782) + xLocal_3 + xLocal_3' + xLocal_3'';- xLocal_3 = xK2_3 * 1.781477937;- xLocal_3' = xK2_4 * (-1.821255978);- xLocal_3'' = xK2_5 * 1.330274429;---blkSchlsEqEuroNoDiv :: FpType -> FpType -> FpType -> FpType -> FpType -> Bool -> Float -> FpType-blkSchlsEqEuroNoDiv sptprice strike rate volatility time otype timet =- if not otype- then (sptprice * nofXd1) - (futureValueX * nofXd2)- else let negNofXd1 = 1.0 - nofXd1- negNofXd2 = 1.0 - nofXd2- in (futureValueX * negNofXd2) - (sptprice * negNofXd1)- where - logValues = log( sptprice / strike ) - xPowerTerm = 0.5 * volatility * volatility- xDen = volatility * sqrt(time)- xD1 = (((rate + xPowerTerm) * time) + logValues) / xDen- xD2 = xD1 - xDen-- nofXd1 = cndf xD1 - nofXd2 = cndf xD1 - futureValueX = strike * exp ( -(rate) * (time) )-------------------------------------------------------------------------------------computeSegment :: Int -> Int -> U.UArray Int FpType-computeSegment granularity t = arr- where - arr = U.listArray (0, granularity-1) $- Prelude.map fn [0 .. granularity-1]- fn i = let ParameterSet { .. } = data_init U.! ((t+i) `mod` size_init)- in blkSchlsEqEuroNoDiv sptprice strike rate volatility otime otype 0-------------------------------------------------------------------------------------- No need to go deeper here because its unboxed, right?-instance NFData (U.UArray Int FpType) where--main = do args <- getArgs - let (numOptions, granularity) =- case args of - [] -> (10000, 1000)- [b] -> (10, read b)- [b,n] -> (read n, read b)-- if granularity > numOptions- then error "Granularity must be bigger than numOptions!!"- else return ()-- putStrLn$ "Running blackscholes, numOptions "++ show numOptions ++ " and block size " ++ show granularity-- let numChunks = numOptions `quot` granularity--- results = runPar$ parMap (computeSegment granularity . (* granularity)) [0..numChunks-1]--#if 1- results = runPar$ parMap (computeSegment granularity) [0, granularity .. numOptions-1]-#else--- Not working right yet [2011.02.18]- results = toList$ runPar$ - parBuild 1 0 (numChunks-1) - (computeSegment granularity . (* granularity))-#endif- sum = foldl1' (+) $ map (U.! 0) results-- putStrLn$ "Final checksum: "++ show sum
− examples/blackscholes_data.hs
@@ -1,1006 +0,0 @@--- #include file of test data inpout params and DerivaGem control reference value------ S, K, r, q, vol, T, P/C, Divs, DG RefValue--data_init = listArray (0,999) [ - ParameterSet { sptprice=42.00, strike=40.00, rate=0.1000, volatility=0.20, otime=0.50, otype=True},- ParameterSet {sptprice=42.00, strike=40.00, rate=0.1000, volatility=0.20, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.15, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.15, otime=1.00, otype=True},- ParameterSet {sptprice=60.00, strike=65.00, rate=0.0800, volatility=0.30, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.10, otime=0.10, otype=True},- ParameterSet{sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.10, otime=0.50, otype=True},- ParameterSet{sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.10, otime=1.00, otype=True},- ParameterSet{sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.10, otime=0.10, otype=True},- ParameterSet{sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.10, otime=0.50, otype=True},- ParameterSet{sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.10, otime=1.00, otype=True},- ParameterSet{sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.10, otime=0.10, otype=True},- ParameterSet{sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.10, otime=0.50, otype=True},- ParameterSet{sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.10, otime=1.00, otype=True},- ParameterSet{sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.25, otime=0.10, otype=True},- ParameterSet{sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.25, otime=0.50, otype=True},- ParameterSet{sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.25, otime=1.00, otype=True},- ParameterSet{sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.25, otime=0.10, otype=True},- ParameterSet{sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.25, otime=0.50, otype=True},- ParameterSet{sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.25, otime=1.00, otype=True},- ParameterSet{sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.25, otime=0.10, otype=True},- ParameterSet{sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.25, otime=0.50, otype=True},- ParameterSet{sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.25, otime=1.00, otype=True},- ParameterSet{sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.50, otime=0.10, otype=True},- ParameterSet{sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.50, otime=0.50, otype=True},- ParameterSet{sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.50, otime=1.00, otype=True},- ParameterSet{sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.50, otime=0.10, otype=True},- ParameterSet{sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.50, otime=0.50, otype=True},- ParameterSet{sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.50, otime=1.00, otype=True},- ParameterSet{sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.50, otime=0.10, otype=True},- ParameterSet{sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.50, otime=0.50, otype=True},- ParameterSet{sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.50, otime=1.00, otype=True},- ParameterSet{sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.10, otime=0.10, otype=False},- ParameterSet{sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.10, otime=0.50, otype=False},- ParameterSet{sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.10, otime=1.00, otype=False},- ParameterSet{sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.10, otime=0.10, otype=False},- ParameterSet{sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.10, otime=0.50, otype=False},- ParameterSet{sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.10, otime=1.00, otype=False},- ParameterSet{sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.10, otime=0.10, otype=False},- ParameterSet{sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.10, otime=0.50, otype=False},- ParameterSet{sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.10, otime=1.00, otype=False},- ParameterSet{sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.25, otime=0.10, otype=False},- ParameterSet{sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.25, otime=0.50, otype=False},- ParameterSet{sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.25, otime=1.00, otype=False},- ParameterSet{sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.25, otime=0.10, otype=False},- ParameterSet{sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.25, otime=0.50, otype=False},- ParameterSet{sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.25, otime=1.00, otype=False},- ParameterSet{sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.25, otime=0.10, otype=False},- ParameterSet{sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.1000, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.1000, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.1000, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0500, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0500, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0500, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0500, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0500, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0500, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0725, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0725, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0725, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0725, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0725, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0725, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0825, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0825, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0825, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.10, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.10, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.10, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.25, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.25, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.25, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.25, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0825, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0825, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.50, otime=0.10, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.50, otime=0.50, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0825, volatility=0.50, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.10, otime=0.75, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.10, otime=0.75, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.10, otime=0.75, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.75, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.75, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.75, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.50, otime=0.75, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.50, otime=0.75, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.50, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.10, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.10, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.10, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.50, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.50, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.50, otime=0.75, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.05, otime=0.05, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.15, otime=0.15, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.25, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.35, otime=0.35, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.45, otime=0.40, otype=True},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.65, otime=0.75, otype=True},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=41.25, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=50.00, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.05, otime=0.05, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.15, otime=0.15, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.65, otime=0.75, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.25, otime=0.25, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.35, otime=0.35, otype=False},- ParameterSet {sptprice=50.00, strike=60.75, rate=0.0275, volatility=0.45, otime=0.40, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.25, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.25, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.50, otime=0.10, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.50, otime=0.50, otype=True},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.50, otime=1.00, otype=True},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=90.00, rate=0.1000, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=100.00, rate=0.1000, volatility=0.10, otime=1.00, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.10, otime=0.10, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.10, otime=0.50, otype=False},- ParameterSet {sptprice=100.00, strike=110.00, rate=0.1000, volatility=0.10, otime=1.00, otype=False}- ]
− examples/cholesky.hs
@@ -1,321 +0,0 @@-{-- - Intel Concurrent Collections for Haskell- - Copyright (c) 2010, Intel Corporation.- -- - This program is free software; you can redistribute it and/or modify it- - under the terms and conditions of the GNU Lesser General Public License,- - version 2.1, as published by the Free Software Foundation.- -- - This program is distributed in the hope it will be useful, but WITHOUT- - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or- - FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for- - more details.- -- - You should have received a copy of the GNU Lesser General Public License along with- - this program; if not, write to the Free Software Foundation, Inc., - - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.- -- -}-{-# LANGUAGE ExistentialQuantification- , ScopedTypeVariables- , BangPatterns- , NamedFieldPuns - , RecordWildCards- , FlexibleInstances- , DeriveDataTypeable- , TypeSynonymInstances- , CPP- #-}---- Author: Chih-Ping Chen--- Modified by Ryan Newton.---- This program uses monad-par to do cholesky transformation. ---- Description--- -------------- Given a symmetric positive definite matrix A, the Cholesky decomposition is--- a lower triangular matrix L such that A=L.L^(T). ---- Usage--- --------- The command line is:---- cholesky n b filename--- n : input SPD matrix size--- b : block/tile size--- filename: input matrix file name---- Several sample input files are provided. m6.in is a 6x6 matrix (n=6).--- Input_matrix.zip contains the files m50.in, m100.in, m500.in, and m1000.in with--- corresponding 'n' of 50, 100, 500, and 1000.---- e.g.--- cholesky 1000 50 m1000.in 4--- cholesky v 6 2 m6.in---- The input SPD matrix is read from the file specified. The output will be a--- lower triangular matrix. --import Data.Int-import qualified Data.List as List-import qualified Data.Array.Unboxed as Array-import Data.Array.IO-import Data.Array.MArray-import Debug.Trace-import System.Posix.Files-import System.Environment-import System.IO-import System.IO.Unsafe-import Data.Map-import Data.IORef-import qualified Data.ByteString.Char8 as B--import Control.DeepSeq-import Control.Exception-import Data.Time.Clock -- Not in 6.10--import Control.Monad-import Control.Monad.Par--timeit io = - do strt <- getCurrentTime- io - end <- getCurrentTime- return (diffUTCTime end strt)---- The type of the input/output array.-type Matrix = Array.UArray (Int, Int) Float--instance NFData Matrix---- A matrix is divided into "Tile"s, and carries intermediate results--- of the computation.-type Tile = IOUArray (Int, Int) Float---- Tile3D allows us to refer to a IVar associated with a tile. The first--- two dimensions of the index are the coordinates of the tile in the matrix.--- The last dimension is the "generation" dimension. I.e., a (IVar Tile) mapped--- by (i, j, k+1) is the next generation of the (IVar Tile) mapped by (i, j, k).-type Tiles3D = Map (Int, Int, Int) (IVar Tile)--instance NFData Tile where--- SDM: use the default. All we require is that the IOUArray is evaluated,--- since all its contents are unboxed.--- rnf x = unsafePerformIO $--- do bounds <- getBounds x--- elems <- getElems x--- _ <- return $ rnf (bounds, elems)--- return ()--parMap_ :: (a -> Par ()) -> [a] -> Par ()-parMap_ f xs = mapM (spawn . f) xs >> return ()--getTileV :: (Int, Int, Int) -> Tiles3D -> IVar Tile-getTileV triplet tiles =- findWithDefault (error "This can't be happening...") triplet tiles---- This kicks off cholesky factorization on the diagonal tiles.-s0Compute :: IVar Tiles3D -> Int -> Int -> Par ()-s0Compute lkjiv p b =- do lkji <- get lkjiv- parMap_ (s1Compute lkji p b) [0..p-1]---- This does the cholesky factorization on the a diagonal tile, and--- kicks off triangular system solve on the tiles that are below and --- on the same column as the diagonal tile.-s1Compute :: Tiles3D -> Int -> Int -> Int -> Par ()-s1Compute lkji p b k = - do- -- Read the tile:- aBlock <- get $ getTileV (k, k, k) lkji- -- Write an output tile:- put (getTileV (k, k, k+1) lkji) (s1Core aBlock b)- -- Do triangular solves on the tiles with the same column number- parMap_ (s2Compute lkji b) [(k,j) | j <- [k+1..p-1]]- where s1Core aBlock b = unsafePerformIO $ - do lBlock <- newArray ((0,0), (b-1,b-1)) 0.0- forM_ [0..b-1] (outer aBlock lBlock b)- return lBlock- outer aBlock lBlock b kb = do base <- readArray aBlock (kb,kb)- writeArray lBlock (kb,kb) (sqrt base)- forM_ [kb+1 .. b-1] (inner1 aBlock lBlock kb)- forM_ [kb+1 .. b-1] (inner2 aBlock lBlock kb b)- inner1 aBlock lBlock kb jb = do base1 <- readArray aBlock (jb,kb)- base2 <- readArray lBlock (kb,kb)- writeArray lBlock (jb,kb) (base1 /base2)- inner2 aBlock lBlock kb b jbb = do forM_ [kb+1 .. b-1] (inner3 aBlock lBlock jbb kb)- inner3 aBlock lBlock jbb kb ib = do base1 <- readArray aBlock (ib, jbb)- base2 <- readArray lBlock (ib, kb)- base3 <- readArray lBlock (jbb, kb)- writeArray aBlock (ib,jbb) (base1 - base2 * base3)---- This does the triangular system solve on a tile T, and--- kicks off the symmetric rank-k update on the tiles that --- are to the right and on the same row as T. -s2Compute :: Tiles3D -> Int -> (Int, Int) -> Par ()-s2Compute lkji b (k, j) =- do - aBlock <- get $ getTileV (j,k,k) lkji- liBlock <- get $ getTileV (k,k,k+1) lkji- put (getTileV (j,k,k+1) lkji) (s2Core aBlock liBlock b)- parMap_ (s3Compute lkji b) [(k, j, i) | i <- [k+1..j]]- where s2Core aBlock liBlock b = unsafePerformIO $- do loBlock <- newArray ((0,0),(b-1,b-1)) 0.0- forM_ [0..b-1] (outer aBlock liBlock loBlock b)- return loBlock- outer aBlock liBlock loBlock b kb = do forM_ [0..b-1] (inner1 aBlock liBlock loBlock kb)- forM_ [kb+1..b-1] (inner2 aBlock liBlock loBlock b kb)- inner1 aBlock liBlock loBlock kb ib = do base1 <- readArray aBlock (ib,kb)- base2 <- readArray liBlock (kb,kb)- writeArray loBlock (ib,kb) (base1 / base2)- inner2 aBlock liBlock loBlock b kb jb = do forM_ [0..b-1] (inner3 aBlock liBlock loBlock kb jb)- inner3 aBlock liBlock loBlock kb jb ib = do base1 <- readArray aBlock (ib,jb)- base2 <- readArray liBlock (jb,kb)- base3 <- readArray loBlock (ib,kb)- writeArray aBlock (ib,jb) (base1 - (base2 * base3))- ---- This computes the symmetric rank-k update on a tile.-s3Compute :: Tiles3D -> Int -> (Int, Int, Int) -> Par ()-s3Compute lkji b (k,j,i) | i == j =- do - aBlock <- get $ getTileV (j,i,k) lkji- l2Block <- get $ getTileV (j,k,k+1) lkji- put (getTileV (j,i,k+1) lkji) (s3Core aBlock l2Block b)--- pval lkji- return ()- where s3Core aBlock l2Block b = unsafePerformIO $- do forM_ [0..b-1] (outer aBlock l2Block b)- return aBlock- outer aBlock l2Block b jb = do forM_ [0..b-1] (inner1 aBlock l2Block b jb)- inner1 aBlock l2Block b jb kb = do base <- readArray l2Block (jb,kb) - forM_ [jb..b-1] (inner2 aBlock l2Block jb kb (-base))- inner2 aBlock l2Block jb kb temp ib = do base1 <- readArray aBlock (ib,jb)- base2 <- readArray l2Block (ib,kb)- writeArray aBlock (ib,jb) (base1 + temp * base2)- -s3Compute lkji b (k,j,i) | otherwise =- do - aBlock <- get $ getTileV (j,i,k) lkji- l2Block <- get $ getTileV (i,k,k+1) lkji- l1Block <- get $ getTileV (j,k,k+1) lkji- put (getTileV (j,i,k+1) lkji) (s3Core aBlock l1Block l2Block b)- return ()- where s3Core aBlock l1Block l2Block b = unsafePerformIO $- do forM_ [0..b-1] (outer aBlock l1Block l2Block b)- return aBlock- outer aBlock l1Block l2Block b jb = do forM_ [0..b-1] (inner1 aBlock l1Block l2Block b jb)- inner1 aBlock l1Block l2Block b jb kb = do base <- readArray l2Block (jb,kb) - forM_ [0..b-1] (inner2 aBlock l1Block jb kb (-base))- inner2 aBlock l1Block jb kb temp ib = do base1 <- readArray aBlock (ib,jb)- base2 <- readArray l1Block (ib,kb)- writeArray aBlock (ib,jb) (base1 + temp * base2)---- initLkji initialize the (IVar Tile) map using the input array.-initLkji :: Matrix -> Int -> Int -> Int -> Par (IVar Tiles3D) -initLkji arrA n p b = - let tile i j = unsafePerformIO $ newListArray ((0,0),(b-1,b-1)) (tileList i j)- tileList i j = [ arrA Array.! (i * b + ii, j * b + jj) | ii <- [0..b-1], jj <-[0..b-1]]- fn c (i, j, k) | k == 0 = - do mv <- c- m <- get mv- tv <- pval $ tile i j- pval $ insert (i, j, k) tv m- fn c (i, j, k) | otherwise = - do mv <- c- m <- get mv- tv <- new- pval $ insert (i, j, k) tv m- in foldl fn (pval empty) [(i, j, k) | i <- [0..p-1], j <- [0..i], k <- [0..j+1]] - ---- composeResult collect the tiles with the final results back into one single matrix. -composeResult :: Tiles3D -> Int -> Int -> Int -> Par Matrix -composeResult lkji n p b =- do assocs <- sequence [ grab i ib j | i <- [0..p-1], ib <- [0..b-1], j <- [0..i]]- return $ Array.array ((0,0),(n-1,n-1)) (concat assocs)- where grab i ib j = if (i == j) then- do matOut <- get $ getTileV (i,j,j+1) lkji- compose1 matOut - else- do matOut <- get $ getTileV (i,j,j+1) lkji- compose2 matOut- where compose1 matOut = do forM [0..ib] (compose11 matOut)- compose11 matOut jb = let elem = unsafePerformIO $- do readArray matOut (ib,jb)- in return ((i*b+ib,j*b+jb),elem)- compose2 matOut = do forM [0..b-1] (compose11 matOut) --{-# INLINE for_ #-} -for_ start end fn | start > end = error "for_: start is greater than end"-for_ start end fn = loop start- where - loop !i | i == end = return () - | otherwise = do fn i; loop (i+1)--run :: Int -> Int -> Matrix -> Matrix-run n b arrA = - let p = n `div` b- in - runPar $- do - lkjiv <- initLkji arrA n p b- _ <- s0Compute lkjiv p b- lkji' <- get lkjiv- composeResult lkji' n p b--main = - do ls <- getArgs - let (n, b, fname) =- case ls of - [] -> (6, 2, "cholesky_matrix6.dat")-- -- To get more data try this:- -- wget http://people.csail.mit.edu/newton/haskell-cnc/datasets/cholesky_matrix_data.tbz-- ["medium"] -> (500, 50, "cholesky_matrix500.dat")- ["big"] -> (1000, 50, "cholesky_matrix1000.dat")- [a,b,c] -> (read a, read b, c)-- bool <- fileExist fname- let fname' = if bool then fname else "examples/"++fname- - ref <- newIORef undefined- let meaningless_write !val = writeIORef ref val-- t1 <- getCurrentTime- putStrLn "Begin reading from disk..."- arrA <- initMatrix n fname'- evaluate arrA- t2 <- getCurrentTime- putStrLn $" ... ArrA read from disk: time " ++ show (diffUTCTime t2 t1)- hFlush stdout-- arrB <- return $ run n b arrA- --putStrLn $ show $ [((i,j),arrB Array.! (i,j)) | i <-[0..n-1], j<-[0..i]]-- putStrLn "Making sure evaluation of arrB is forced..."- evaluate arrB- --putStrLn $ show $ [((i,j),arrB Array.! (i,j)) | i <-[0..n-1], j<-[0..i]]- t3 <- getCurrentTime---- FIXME: Using deepseq here seems to delay the evaluation to the reference of--- t3 <- case deepseq arrB () of _ -> getCurrentTime--- t3 <- arrB `deepseq` getCurrentTime- putStrLn$ "Finished: eval time "++ show (diffUTCTime t3 t2)-- putStrLn$ "SELFTIMED " ++ show ((fromRational $ toRational $ diffUTCTime t3 t2) :: Double)- t4 <- getCurrentTime- val <- readIORef ref- putStrLn$ "Last value: " ++ show (arrB Array.! (n-1, n-1))- t5 <- getCurrentTime- putStrLn$ "SELFTIMED' " ++ show ((fromRational $ toRational $ diffUTCTime t5 t4) :: Double) --initMatrix :: Int -> [Char] -> IO Matrix-initMatrix n fname = - do fs <- B.readFile fname- return $! Array.listArray ((0,0), (n-1, n-1))- (List.cycle $ List.map (read . B.unpack) (B.words fs))-
− examples/cholesky_matrix6.dat
@@ -1,1 +0,0 @@-4 -2 6 8 6 10 -2 10 3 -4 15 1 6 3 14 11 19 22 8 -4 11 33 2 21 6 15 19 2 62 28 10 1 22 21 28 73
− examples/coins.hs
@@ -1,240 +0,0 @@-{-# LANGUAGE BangPatterns #-}--import Data.List-import System.Environment-import Control.Parallel-import Control.Parallel.Strategies-import Control.Applicative-import Control.Monad.Par---- Rough results, GHC 6.13: (val=777)--- V1 (SDM): 2.2s--- V2 (SDM): 2.7s--- V3 (SDM, parallel): 1.0s on 7 cores--- V4 (original): got bored waiting--- V5 (HWL assoc): 5.2s--- V6 (SDM, Int result): 0.9s--- V7 (SDM, parallel): 0.2s on 7 cores---------------------------------------------------------------------------------- Version 1: returns results as a list of list of coins--payL :: Int -> [(Int,Int)] -> [Int] -> [[Int]]-payL 0 coins acc = [acc]-payL _ [] acc = []-payL val ((c,q):coins) acc- | c > val = payL val coins acc- | otherwise = left ++ right- where- left = payL (val - c) coins' (c:acc)- right = payL val coins acc-- coins' | q == 1 = coins- | otherwise = (c,q-1) : coins---------------------------------------------------------------------------------- Version 2: uses a custom AList type to avoid repeated appends---- The idea here is that by avoiding the append we might be able to--- parallelise this more easily by just forcing evaluation to WHNF at--- each level. I haven't parallelised this version yet, though (V5--- below is much easier) --SDM--data AList a = ANil | ASing a | Append (AList a) (AList a)--lenA :: AList a -> Int-lenA ANil = 0-lenA (ASing _) = 1-lenA (Append l r) = lenA l + lenA r--append ANil r = r-append l ANil = l -- **-append l r = Append l r-- -- making append less strict (omit ** above) can make the algorithm- -- faster in sequential mode, because it runs in constant space.- -- However, ** helps parallelism.--payA :: Int -> [(Int,Int)] -> [Int] -> AList [Int]-payA 0 coins acc = ASing acc-payA _ [] acc = ANil-payA val ((c,q):coins) acc- | c > val = payA val coins acc- | otherwise = append left right -- strict in l, maybe strict in r- where- left = payA (val - c) coins' (c:acc)- right = payA val coins acc- coins' | q == 1 = coins- | otherwise = (c,q-1) : coins---------------------------------------------------------------------------------- Version 3: parallel version of V2--payA_par :: Int -> Int -> [(Int,Int)] -> [Int] -> AList [Int]-payA_par 0 val coins acc = payA val coins acc-payA_par _ 0 coins acc = ASing acc-payA_par _ _ [] acc = ANil-payA_par depth val ((c,q):coins) acc- | c > val = payA_par depth val coins acc- | otherwise = res- - where- res = unEval $ pure append <*> rpar left <*> rwhnf right-- left = payA_par (if q == 1 then (depth-1) else depth) (val - c) coins' (c:acc)- right = payA_par (depth-1) val coins acc-- coins' | q == 1 = coins- | otherwise = (c,q-1) : coins---------------------------------------------------------------------------------- Version 4: original list-of-list version (very slow)--pay :: Int -> Int -> [Int] -> [Int] -> [[Int]]-pay _ 0 coins accum = [accum]-pay _ val [] _ = []-pay pri val coins accum = - res - where -- - coins' = dropWhile (>val) coins- coin_vals = nub coins' - res = concat ( map- ( \ c -> let - new_coins = - ((dropWhile (>c) coins')\\[c])- in - pay (pri-1)- (val-c) - new_coins- (c:accum)- )- coin_vals )----------------------------------------------------------------------------------- Version 5: assoc-list version (by HWL?)---- assoc-list-based version; still multiple list traversals-pay1 :: Int -> Int -> [(Int,Int)] -> [(Int,Int)] -> [[(Int,Int)]]-pay1 _ 0 coins accum = [accum]-pay1 _ val [] _ = []-pay1 pri val coins accum = res- where --- coins' = dropWhile ((>val) . fst) coins- res = concat ( - map- ( \ (c,q) -> let - -- several traversals - new_coins = - filter (not . (==0) . snd) $- map (\ x'@(c',q') -> if c==c' then (c',q'-1) else x') $- dropWhile ((>c) . fst) $- coins'- new_accum = - map (\ x'@(c',q') -> if c==c' then (c',q'+1) else x') accum- in - pay1 (pri-1)- (val-c) - new_coins- new_accum- )- coins' )---------------------------------------------------------------------------------- Version 6: just return the number of results, not the results themselves--payN :: Int -> [(Int,Int)] -> Int-payN 0 coins = 1-payN _ [] = 0-payN val ((c,q):coins)- | c > val = payN val coins- | otherwise = left + right- where- left = payN (val - c) coins'- right = payN val coins-- coins' | q == 1 = coins- | otherwise = (c,q-1) : coins---------------------------------------------------------------------------------- Version 7: parallel version of payN--payN_par :: Int -> Int -> [(Int,Int)] -> Int-payN_par 0 val coins = payN val coins-payN_par _ 0 coins = 1-payN_par _ _ [] = 0-payN_par depth val ((c,q):coins)- | c > val = payN_par depth val coins- | otherwise = res- - where- res = right `par` left `pseq` left + right-- left = payN_par (if q == 1 then (depth-1) else depth) (val - c) coins'- right = payN_par (depth-1) val coins-- coins' | q == 1 = coins- | otherwise = (c,q-1) : coins----------------------------------------------------------------------------------------------------------------------------------------------------------------- Version 8: monad-par version of payN--- Competitive with Version 7.--payN_mp :: Int -> Int -> [(Int,Int)] -> Int-payN_mp depth val coins = - runPar $ - payN_mpM depth val coins --payN_mpM :: Int -> Int -> [(Int,Int)] -> Par Int-payN_mpM 0 val coins = return $ payN val coins-payN_mpM _ 0 coins = return 1-payN_mpM _ _ [] = return 0-payN_mpM depth val ((c,q):coins)- | c > val = payN_mpM depth val coins- | otherwise = res- - where- res = - do lv <- spawn $ left- r <- right- l <- get lv- return (l + r)-- left = payN_mpM (if q == 1 then (depth-1) else depth) (val - c) coins'- right = payN_mpM (depth-1) val coins-- coins' | q == 1 = coins- | otherwise = (c,q-1) : coins------------------------------------------------------------------------------------ driver--main = do- let vals = [250, 100, 25, 10, 5, 1] - -- let quants = [1, 3, 2, 5, 7, 12] -- small setup- -- let quants = [5, 8, 8, 9, 12, 17] -- std setup- let quants = [55, 88, 88, 99, 122, 177] -- large setup-- let coins = concat (zipWith replicate quants vals)- coins1 = zip vals quants-- [n, arg] <- fmap (fmap read) getArgs-- case n of- -- sequential, list of results- 1 -> print $ length $ payL arg coins1 []- -- sequential, append-list of results- 2 -> print $ lenA $ payA arg coins1 []- -- parallel, append-list of results- 3 -> print $ lenA $ payA_par 4 arg coins1 []-- 4 -> print $ length (pay 0 arg coins [])- 5 -> print $ length (pay1 0 arg coins1 (map (\(c,q) -> (c,0)) coins1))- 6 -> print $ payN arg coins1- 7 -> print $ payN_par 4 arg coins1- 8 -> print $ payN_mp 4 arg coins1-
− examples/common.mk
@@ -1,10 +0,0 @@--# RRN: allow setting it via the command line. (I don't have a ghc-testing2 ;-). )-ifeq (,$(GHC))- GHC = ghc- # GHC = ghc-testing2- # GHC = ghc-stable-nightly2-endif--ALLPARSRC= ../Control/Monad/Par.hs ../Control/Monad/Par/AList.hs ../Control/Monad/Par/OpenList.hs \- ../Control/Monad/Par/IList.hs ../Control/Monad/Par/Stream.hs ../Control/Monad/Par/Logging.hs
− examples/get_cholesky_data.sh
@@ -1,2 +0,0 @@-#!/bin/bash-wget http://people.csail.mit.edu/~newton/haskell-cnc/datasets/cholesky_matrix_data.tbz
− examples/mandel.hs
@@ -1,96 +0,0 @@-{-# LANGUAGE BangPatterns, CPP #-}-import System.Environment-import Control.Monad-import Control.Seq-import Data.Complex-import System.IO-import Debug.Trace-import Control.DeepSeq-import Control.Monad.Par-import Control.Exception--import PortablePixmap-import Control.Monad.Par.AList as A--mandel :: Int -> Complex Double -> Int-mandel max_depth c = loop 0 0- where - fn = magnitude- loop i !z- | i == max_depth = i- | fn(z) >= 2.0 = i- | otherwise = loop (i+1) (z*z + c)---threshold = 1--runMandel :: Double -> Double -> Double -> Double -> Int -> Int -> Int -> Par (AList [Int])-runMandel minX minY maxX maxY winX winY max_depth = do-- parBuildThreshM threshold (InclusiveRange 0 (winY-1)) $ \y -> - do- let l = [ mandelStep y x | x <- [0.. winX-1] ]- deepseq l (return l)-- where- mandelStep i j = mandel max_depth z- where z = ((fromIntegral j * r_scale) / fromIntegral winY + minY) :+- ((fromIntegral i * c_scale) / fromIntegral winX + minX)-- r_scale = maxY - minY :: Double- c_scale = maxX - minX :: Double---makeImage :: Integer -> Integer -> Int -> AList [Int] -> PixMap-makeImage x y depth ls =- createPixmap x y depth - (map prettyRGB (concat (toList ls)))- where - prettyRGB :: Int -> (Int,Int,Int)- prettyRGB s = let t = (depth - s) in (s,t,t)--simple x y depth = - runMandel 0 0 x' y' x y depth- where - x' = fromIntegral x- y' = fromIntegral y -------------------------------------------------------------------------------------- A meaningless checksum.-mandelCheck :: AList [Int] -> Int -> Int -> Int-mandelCheck als max_col max_depth = loop 0 als 0- where - loop i als !sum | A.null als = sum- loop i als !sum = loop (i+1) (A.tail als)- (loop2 i 0 (A.head als) sum)- loop2 i j [] !sum = sum- loop2 i j (h:t) !sum | h == max_depth = loop2 i (j+1) t (sum + i*max_col + j)- | otherwise = loop2 i (j+1) t sum- -main = do args <- getArgs-- let (x,y,depth) = - case args of- [] -> - -- runPar $ simple 3 3 3- (3,3,3)-- [x,y,depth] -> - -- simple (read x) (read y) (read depth)- (read x, read y, read depth)-- -- [minX,minY,maxX,maxY,winX,winY,depth] ->- -- runPar $ - -- runMandel (read minX) (read minY)- -- (read maxX) (read maxY)- -- (read winX) (read winY) (read depth)-- let ls = runPar$ simple x y depth- when (False) $ do - hnd <- openFile "mandel_image.ppm" WriteMode- hSetBinaryMode hnd True- hPrint hnd (makeImage (fromIntegral x) (fromIntegral y) depth ls)- hClose hnd-- putStrLn$ "Spot check: " ++ show (mandelCheck ls y depth)
− examples/matmult/ListAux.hs
@@ -1,41 +0,0 @@-module ListAux where--import Data.List----- splitting into n parts, and its inverse:--splitIntoN :: Int -> [a] -> [[a]]-splitIntoN n xs = takeIter parts xs- where l = length xs- parts = zipWith (+) ((replicate (l `mod` n) 1) ++ repeat 0)- (replicate n (l `div` n))-takeIter :: [Int] -> [a] -> [[a]]-takeIter [] [] = []-takeIter [] _ = error "elements left over"-takeIter (t:ts) xs = hs : takeIter ts rest- where (hs,rest) = splitAt t xs--unSplit :: [[a]] -> [a]-unSplit = concat---- splitting into parts of same size. Inverse is concat again.--splitAtN :: Int -> [a] -> [[a]]-splitAtN n [] = []-splitAtN n xs = ys : splitAtN n zs- where (ys,zs) = splitAt n xs---------------------------------------------- splitting round-robin until list runs empty, and its inverse:--unshuffle :: Int -> [a] -> [[a]]-unshuffle n xs = [takeEach n (drop i xs) | i <- [0..n-1]]- where takeEach n [] = []- takeEach n (x:xs) = x : takeEach n (drop (n-1) xs)---- inverse to unshuffle-shuffle :: [[a]] -> [a]-shuffle = concat . transpose-
− examples/matmult/Makefile
@@ -1,4 +0,0 @@-include ../common.mk--matmult.exe : $(wildcard *.hs) ../../Control/Monad/Par.hs- $(GHC) -O2 -cpp --make -i../.. MatMult.hs -o $@ -threaded -rtsopts
− examples/matmult/MatMult.hs
@@ -1,215 +0,0 @@-{-# OPTIONS -cpp #-}-{-# LANGUAGE BangPatterns #-}--{- Matrix multiplication using a torus (gentleman algorithm) -- FR10 -- -}--{--RL/JB ParCo2005: eliminate result communication (Maybe-Type)--JB PhD2008: adapt for simple PhD skeleton tests--JB MSR07/2008: modified to use all available toroid skeletons.--JB MSR07/2008: derived a straight-forward GpH program using identical- helpers and strategies--JB optimised prodEscalar--JB for ghc-6.9: replaced Control.Parallel.Strategies by a workaround- (reexporting what should work)---}- -module Main(main) where--import System.Environment-import Data.List hiding (foldl', foldl1')--import ListAux-import Control.DeepSeq--import Control.Monad.Par-----------------------------------------type Vector = [Int]-type Matrix = [Vector]---- main computation, different versions:-mult :: Int -> Matrix -> Matrix -> Int -> [[Maybe Matrix]]-mult 0 m1 m2 _ = -#ifdef OUTPUT- [[Just $ multMatricesTr m1 (transpose m2)]]-#else- rnf (multMatricesTr m1 (transpose m2)) `seq` [[Nothing]]-#endif-mult v m1 m2 c = results- where results :: [[Maybe Matrix]]-#ifdef OUTPUT- results = [[Just computed]]-#else- results = (rnf computed `seq` [[Nothing]])-#endif- computed = multMatricesTr m1 m2Tr--- strats' = strats ++ repeat undef- m2Tr = transpose m2--prMM' :: (Matrix,Matrix) -> Matrix-prMM' (c,mt) = [[prVV f c | c <- mt]|f <-c]-prVV :: Vector -> Vector -> Int-prVV f c = sum (zipWith (*) f c)- -shiftRight c [] = []-shiftRight c (xs:xss) = (xs2++xs1):shiftRight (c-1) xss- where (xs1,xs2) = splitAt c xs--shiftDown c xss = transpose (shiftRight c (transpose xss))--join2 :: Matrix -> Matrix -> Matrix-join2 xs ys = zipWith (++) xs ys-join :: [Matrix] -> Matrix-join xss = foldr join2 (repeat []) xss- -splitIntoClusters :: Int -> Matrix -> [[Matrix]]-splitIntoClusters c m | c < 1 = splitIntoClusters 1 m-splitIntoClusters c m1 = mss- where bh = kPartition (length m1) c- bhsplit [] [] = []- bhsplit [] _ = error "some elements left over"- bhsplit (t:ts) xs = hs : (bhsplit ts rest)- where (hs,rest) = splitAt t xs - ms = bhsplit bh m1 -- blocks of rows - mss = map (colsplit bh) ms- colsplit [] _ = []- colsplit (t:ts) rs- | head rs == [] = []- | otherwise = (cab:colsplit ts resto)- where (cab,resto) = unzip (map (splitAt t) rs)- --- mss = map (repartir (length m1 `div` c)) ms--- repartir c xs--- | head xs == [] = []--- | otherwise = (cab:repartir c resto)--- where (cab,resto) = unzip (map (splitAt c) xs)---- helper for splitIntoClusters (formerly bresenham)-kPartition :: Int -> Int -> [Int]-kPartition n k = zipWith (+) ((replicate (n `mod` k) 1) ++ repeat 0)- (replicate k (n `div` k))-- -mult' :: Int -> Int -> ((Matrix,Matrix),[Matrix],[Matrix]) -> (Maybe Matrix,[Matrix],[Matrix])-mult' nc nr ((sm1,sm2),sm1s,sm2s) -#ifdef OUTPUT- = (Just result,toRight,toDown)-#else- = (rnf result `seq` Nothing ,toRight,toDown)-#endif- where toRight = take (nc-1) (sm1:sm1s)- toDown = take (nr-1) (sm2':sm2s)- sm2' = transpose sm2- sms = zipWith multMatricesTr (sm1:sm1s) (sm2':sm2s)- result = foldl1' addMatrices sms -- foldr1: not enough demand??-- -addMatrices :: Matrix -> Matrix -> Matrix-addMatrices m1 m2 = zipWith addVectors m1 m2- where addVectors :: Vector -> Vector -> Vector- addVectors v1 v2 = zipWith (+) v1 v2---- Assumes the second matrix has already been transposed -multMatricesTr :: Matrix -> Matrix -> Matrix-multMatricesTr m1 m2 =- runPar $ parMap (\row -> [prodEscalar2 row col | col <- m2]) m1---- JB 2008: a lot faster, directly consuming lists, and tail-recursive (optimised with -O2)-prodEscalar2JB :: Vector -> Vector -> Int-prodEscalar2JB v1 v2 = addProd v1 v2 0- where addProd :: Vector -> Vector -> Int -> Int- addProd (v:vs) (w:ws) acc = addProd vs ws (acc + v*w)- addProd [] [] n = n- addProd _ _ _ = error "addProd: length does not match"---- JB 2008: identical when using ghc-6.8.3, avoids bug in ghc-HEAD. Version suggested by SM-prodEscalar2 :: Vector -> Vector -> Int-prodEscalar2 v1 v2 = addProd v1 v2 0-addProd :: Vector -> Vector -> Int -> Int-addProd (v:vs) (w:ws) !acc = addProd vs ws (acc + v*w)-addProd _ _ !n = n---prodEscalar :: Vector -> Vector -> Int-prodEscalar v1 v2 = sum (zipWith (*) v1 v2)---------- foldl, strict in head element-foldl1' :: NFData a => (a->a->a) -> [a] -> a-foldl1' f (x:xs) = foldl' f x xs--foldl' :: NFData a => (a -> b -> a) -> a -> [b] -> a-foldl' f a [] = a-foldl' f a (x:xs) = -- whnf, not enough( (foldl' f) $! (f a x)) xs- let first = f a x - in rnf first `seq` foldl' f first xs---usage :: String -> String-usage name = "Cannon's algorithm: Usage:\n\t "++- name ++ " <matrix size> <version> <blocksPerRow> \n" ++- "Version selects from " -- ++ show (zip [0..] names)--main = do - args <- getArgs- let l = length args- if l == 0 then do n <- getProgName- putStrLn (usage n)- putStrLn "\n *** defaults: size 100, seq. computation ***"- else return () --putStrLn "Cannon's algorithm"-- let size = if null args then 100 else read (head args)- opt = if length args < 2 then 0 else read (args!!1)- chunk = if length args < 3 then 1 - else read (args!!2)- a = "Matrices of size " ++ show size ++ --- " with skeleton " ++ ((names++repeat "UNDEF")!!opt) ++- " using chunk parameter " ++ show chunk ++ "\n"- res = mult opt (mA size) (mB size) chunk- b = multMatricesTr (mA size) (transpose (mB size))- -- putStrLn a-#ifdef OUTPUT- putStrLn "Output wanted, checking result for correctness..."- let computed = map (map fromJust) res- computed' = concat (map join computed)- printMat computed'- if (b == computed') - then putStrLn "Correct!"- else do putStrLn "WRONG RESULT! Should be"- printMat b-#else- -- putStrLn "No Output, matrix stays distributed."- putStrLn (show res)-#endif --- -m1 size = replicate size [1..size]-m2 size = listToListList size [1..size*size]-mA size = if size <= 4000 then m1 size else listToListList size (concat (take 20 (repeat [1..(size*size `div` 20)])))-mB size = if size <= 4000 then m1 size else listToListList size (concat (take 20 (repeat [0,2.. ((size*size) `div` 20)-2])))-listToListList c m - | length m <= c = [m]- | otherwise = c1 : listToListList c resto- where (c1,resto) = splitAt c m---printMat :: Matrix -> IO ()-printMat m = putStrLn ("Matrix: " ++ (show (length (head m))) - ++ " x " ++ (show $ length m) ++ "\n" - ++ (showMat m))---- instance Show a => Show (Matrix a) where-showMat m_ = "<<" ++ unlines (map (concatMap (\ x -> show x ++ " ")) m_) ++ ">>"--fromJust :: Maybe a -> a-fromJust (Just x) = x-fromJust Nothing = error "fromJust"
− examples/matmult/matmult.stdout
@@ -1,1 +0,0 @@-[[Nothing]]
− examples/minimax/Board.hs
@@ -1,121 +0,0 @@-{-# LANGUAGE BangPatterns #-}-module Board where--import Wins--import Data.List-import Control.Parallel-import Control.Parallel.Strategies-import Control.DeepSeq--boardDim = 4--type Board = [Row] -type Row = [Piece]-data Piece = X | O | Empty deriving (Eq,Show)--isEmpty Empty = True-isEmpty _ = False--showBoard :: Board -> String-showBoard board = intercalate "\n--------\n" (map showRow board) ++ "\n"- where showRow r = intercalate "|" (map showPiece r)--showPiece :: Piece -> String-showPiece X = "X"-showPiece O = "O"-showPiece Empty = " "--placePiece :: Piece -> Board -> (Int,Int) -> Board-placePiece new board pos- = [[ if (x,y) == pos then new else old- | (x,old) <- zip [1..] row ]- | (y,row) <- zip [1..] board ]--empty :: (Int,Int) -> Board -> Bool-empty (x,y) board = isEmpty ((board !! (y-1)) !! (x-1))--fullBoard b = all (not.isEmpty) (concat b)--newPositions :: Piece -> Board -> [Board]-newPositions piece board = --- [ placePiece piece board (x,y) | (x,y) <- empties board ]- goRows piece id board--goRows p rowsL [] = []-goRows p rowsL (row:rowsR) - = goRow p rowsL id row rowsR ++ goRows p (rowsL . (row:)) rowsR--goRow p rowsL psL [] rowsR = []-goRow p rowsL psL (Empty:psR) rowsR- = (rowsL $ (psL $ (p:psR)) : rowsR) : goRow p rowsL (psL . (Empty:)) psR rowsR-goRow p rowsL psL (p':psR) rowsR = goRow p rowsL (psL . (p':)) psR rowsR--empties board = [ (x,y) | (y,row) <- zip [1..] board,- (x,Empty) <- zip [1..] row ]---initialBoard :: Board-initialBoard = replicate boardDim (replicate boardDim Empty)--data Evaluation = OWin | Score {-# UNPACK #-}!Int | XWin- -- higher scores denote a board in X's favour- deriving (Show,Eq)--instance NFData Evaluation where- rnf x = x `seq` ()--maxE :: Evaluation -> Evaluation -> Evaluation-maxE XWin _ = XWin-maxE _ XWin = XWin-maxE b OWin = b-maxE OWin b = b-maxE a@(Score x) b@(Score y) | x>y = a- | otherwise = b--minE :: Evaluation -> Evaluation -> Evaluation-minE OWin _ = OWin-minE _ OWin = OWin-minE b XWin = b-minE XWin b = b-minE a@(Score x) b@(Score y) | x<y = a- | otherwise = b--eval n | n == boardDim = XWin- | -n == boardDim = OWin- | otherwise = Score n--static :: Board -> Evaluation-static board = interpret 0 (score board)--interpret :: Int -> [Evaluation] -> Evaluation-interpret x [] = (Score x)-interpret x (Score y:l) = interpret (x+y) l-interpret x (XWin:l) = XWin-interpret x (OWin:l) = OWin--scorePiece X = 1-scorePiece O = -1-scorePiece Empty = 0--scoreString !n [] = n-scoreString !n (X:ps) = scoreString (n+1) ps-scoreString !n (O:ps) = scoreString (n-1) ps-scoreString !n (Empty:ps) = scoreString n ps--score :: Board -> [Evaluation]-score board = - [ eval (scoreString 0 row) | row <- board ] ++- [ eval (scoreString 0 col) | col <- transpose board ] ++- [ eval (scoreString 0 (zipWith (!!) board [0..])),- eval (scoreString 0 (zipWith (!!) board [boardDim-1,boardDim-2 ..])) ]--{--#if 0--- This looks very much like a zipWith f to me-map2 :: (a -> b -> c) -> [a] -> [b] -> [c]-map2 f [] x = []-map2 f x [] = []-map2 f (x:xs) (y:ys) = f x y:map2 f xs ys-#endif--}
− examples/minimax/Game.hs
@@ -1,67 +0,0 @@--- Time-stamp: <2011-02-12 21:11:31 simonmar>--------------------------------------------------------------------------------module Game where--import Board-import Tree--import Control.Parallel-import Control.Parallel.Strategies hiding (parMap)-import Debug.Trace--import Control.Monad.Par--type Player = Evaluation -> Evaluation -> Evaluation-type Move = (Board,Evaluation)--alternate :: Int -> Piece -> Player -> Player -> Board -> [Move]-alternate _ _ _ _ b | fullBoard b = []-alternate _ _ _ _ b | static b == XWin = []-alternate _ _ _ _ b | static b == OWin = []-alternate depth player f g board = move : alternate depth opponent g f board'- where- move@(board',eval) = best f possibles scores- scores = runPar $ parMapM (bestMove depth opponent g f) possibles- possibles = newPositions player board- opponent = opposite player--opposite :: Piece -> Piece-opposite X = O-opposite O = X---best :: Player -> [Board] -> [Evaluation] -> Move-best f (b:bs) (s:ss) = best' b s bs ss- where- best' b s [] [] = (b,s)- best' b s (b':bs) (s':ss) | s==(f s s') = best' b s bs ss- | otherwise = best' b' s' bs ss--showMove :: Move -> String-showMove (b,e) = show e ++ "\n" ++ showBoard b--bestMove :: Int -> Piece -> Player -> Player -> Board -> Par Evaluation-bestMove depth p f g board- = do- let tree = cropTree $ mapTree static $ prune depth $ searchTree p $ board- parMise 2 f g tree--cropTree :: (Tree Evaluation) -> (Tree Evaluation)-cropTree (Branch a []) = (Branch a [])-cropTree (Branch (Score x) l) = Branch (Score x) (map cropTree l)-cropTree (Branch x l) = Branch x []--searchTree :: Piece -> Board -> (Tree Board)-searchTree p board = repTree (newPositions p) (newPositions (opposite p)) board--mise :: Player -> Player -> (Tree Evaluation) -> Evaluation-mise f g (Branch a []) = a-mise f g (Branch _ l) = foldr f (g OWin XWin) (map (mise g f) l)--parMise :: Int -> Player -> Player -> (Tree Evaluation) -> Par Evaluation-parMise 0 f g t = return (mise f g t)-parMise n f g (Branch a []) = return a-parMise n f g (Branch _ l) = do- es <- parMapM (parMise (n-1) g f) l- return (foldr f (g OWin XWin) es)
− examples/minimax/Main.hs
@@ -1,20 +0,0 @@--- Time-stamp: <2009-05-06 13:54:34 simonmar>--------------------------------------------------------------------------------module Main where--import System.Environment-import Prog-import Board-import System.Random--main = do- args <- getArgs- let [n, depth] = case args of - [n, depth] -> [read n, read depth]- _ -> [10,10]- - setStdGen (mkStdGen 99999)- b <- randomBoard n- putStrLn $ showBoard b- putStrLn $ solve depth b
− examples/minimax/Makefile
@@ -1,4 +0,0 @@-include ../common.mk--minimax.exe : $(wildcard *.hs) ../../Control/Monad/Par.hs- $(GHC) -O2 -cpp --make -i../.. Main.hs -o $@ -threaded -rtsopts
− examples/minimax/Prog.hs
@@ -1,47 +0,0 @@--- Time-stamp: <2009-05-06 13:55:20 simonmar>--------------------------------------------------------------------------------module Prog(prog,randomBoard,solve) where--import Board-import Wins-import Game-import Tree-import System.Random-import Data.List---- First arg decaffinates game-prog :: Int -> String-prog decaf = showMove (head game)- --"OXO\n" ++- --concat (map showMove game)- where- game = if decaf == 0 - then error "Decaffination error\n"- else alternate decaf X maxE minE testBoard---- X to play: find the best move-solve :: Int -> Board -> String-solve depth board- = unlines- . map showMove- . take 1- . alternate depth X maxE minE $ board--testBoard = [[Empty,O,Empty,Empty],[Empty,X,Empty,Empty],[Empty,Empty,Empty,Empty],[Empty,Empty,Empty,Empty]]--randomBoard :: Int -> IO Board-randomBoard moves = do- g <- newStdGen- let (g1,g2) = split g- xs = randomRs (1,boardDim) g1- ys = randomRs (1,boardDim) g2-- let- play 0 _ _ board = board- play n (pos:poss) (p:ps) board- | not (empty pos board) = play n poss (p:ps) board- | otherwise = play (n-1) poss ps (placePiece p board pos)-- return $ play moves (zip xs ys) (cycle [X,O]) initialBoard-
− examples/minimax/Tree.hs
@@ -1,41 +0,0 @@-{-# LANGUAGE CPP #-}-module Tree where--import Control.Parallel-import Control.Parallel.Strategies--data Tree a = Branch a [Tree a] deriving Show--repTree :: (a->[a]) -> (a->[a])-> a -> (Tree a)-repTree f g a = Branch a (map (repTree g f) (f a))--#define SEQ--#ifndef SEQ--mapTree :: (a -> b) -> Tree a -> Tree b-mapTree f (Branch a l) - = fa `par` Branch fa (map (mapTree f) l `using` myParList)- where fa = f a--#else {- SEQ -}--mapTree :: (a -> b) -> (Tree a) -> (Tree b)-mapTree f (Branch a l) = Branch (f a) (map (mapTree f) l)--#endif--myParList [] = ()-myParList (x:xs) = x `par` myParList xs--mySeqList [] = ()-mySeqList (x:xs) = x `seq` mySeqList xs--parTree :: Int -> Tree a -> ()-parTree 0 (Branch a xs) = ()-parTree n (Branch a xs) = a `par` mySeqList (map (parTree (n-1)) xs)--prune :: Int -> (Tree a) -> (Tree a)-prune 0 (Branch a l) = Branch a []-prune n (Branch a l) = Branch a (map (prune (n-1)) l)-
− examples/minimax/Wins.hs
@@ -1,39 +0,0 @@-module Wins where--type Win = [[Int]]--wins :: [Win] -wins = [win1,win2,win3,win4,win5,win6,win7,win8]--win1,win2,win3,win4,win5,win6,win7,win8 :: Win -win1 = [[1,1,1],- [0,0,0],- [0,0,0]]- -win2 = [[0,0,0],- [1,1,1],- [0,0,0]]- -win3 = [[0,0,0],- [0,0,0],- [1,1,1]]- -win4 = [[1,0,0],- [1,0,0],- [1,0,0]]- -win5 = [[0,1,0],- [0,1,0],- [0,1,0]]- -win6 = [[0,0,1],- [0,0,1],- [0,0,1]]- -win7 = [[1,0,0],- [0,1,0],- [0,0,1]]- -win8 = [[0,0,1],- [0,1,0],- [1,0,0]]
− examples/minimax/minimax.stdout
@@ -1,18 +0,0 @@- |X| | ---------- | | | ---------- |O| | ----------O| | |X--Score 2-X|X| | ---------- | | | ---------- |O| | ----------O| | |X--
− examples/nbody.hs
@@ -1,123 +0,0 @@-{-- - Modified from code released with:- - Intel Concurrent Collections for Haskell- - Copyright (c) 2010, Intel Corporation.- -}-{-# OPTIONS -fglasgow-exts #-}-{-# LANGUAGE ExistentialQuantification- , ScopedTypeVariables- , BangPatterns- , NamedFieldPuns - , RecordWildCards- , FlexibleInstances- , DeriveDataTypeable- , MagicHash - , CPP- #-}--- This is INCOMPATIBLE with CncPure..---- Author: Chih-Ping Chen--- Ported to Monad-par by Ryan Newton.---- This program uses CnC to calculate the accelerations of the bodies in a 3D system. - -import Control.Monad.Par-import Control.Monad-import Data.Int-import qualified Data.List as List-import qualified Data.Array as A-import GHC.Exts-import System.Environment--type Float3D = (Float, Float, Float)-type UFloat3D = (# Float#, Float#, Float# #)----- This step generates the bodies in the system.-genVector tag = (tag' * 1.0, tag' * 0.2, tag' * 30.0)- where tag' = fromIntegral tag---- We are keeping the idiomatic Haskell version around as well for comparison: --- #define IDIOMATIC_VER---- Only doing the O(N^2) part in parallel:--- This step computes the accelerations of the bodies. -compute :: A.Array Int Float3D -> A.Array Int (IVar Float3D) -> Int -> Par ()-compute vecList accels tag =- do - let myvector = vecList A.! (tag-1)- put (accels A.! tag) (accel myvector vecList)- where - g = 9.8-- multTriple :: Float -> Float3D -> Float3D- multTriple c ( x,y,z ) = ( c*x,c*y,c*z )-- pairWiseAccel :: Float3D -> Float3D -> Float3D- pairWiseAccel (x,y,z) (x',y',z') = let dx = x'-x- dy = y'-y- dz = z'-z- eps = 0.005- -- Performance degredation here:- distanceSq = dx*dx + dy*dy + dz*dz + eps- factor = 1/sqrt(distanceSq * distanceSq * distanceSq)---- in multTriple factor (dx,dy,dz)- in multTriple factor (dx,dy,dz)-#ifdef IDIOMATIC_VER- sumTriples = foldr (\(x,y,z) (x',y',z') -> (x+x',y+y',z+z')) (0,0,0)- accel vector vecList = multTriple g $ sumTriples $ List.map (pairWiseAccel vector) vecList-#else--- Making this much less idiomatic to avoid allocation:- (strt,end) = A.bounds vecList-- accel :: Float3D -> (A.Array Int Float3D) -> Float3D- accel vector vecList = -- -- Manually inlining to see if the tuples unbox:- let (# sx,sy,sz #) = loop strt 0 0 0- loop !i !ax !ay !az- | i == end = (# ax,ay,az #)- | otherwise = - let ( x,y,z ) = vector- ( x',y',z' ) = vecList A.! i-- (# dx,dy,dz #) = (# x'-x, y'-y, z'-z #)- eps = 0.005- distanceSq = dx*dx + dy*dy + dz*dz + eps- factor = 1/sqrt(distanceSq * distanceSq * distanceSq)-- (# px,py,pz #) = (# factor * dx, factor * dy, factor *dz #)-- in loop (i+1) (ax+px) (ay+py) (az+pz)- in ( g*sx, g*sy, g*sz )-#endif---run :: Int -> [Float3D]-run n = runPar $ - do - vars <- sequence$ take n $ repeat new--- accels <- A.array (0,n-1) [ (i,) | i <- [0..n-1]]- -- Is there a better way to make an array of pvars?- let accels = A.array (1,n) (zip [1..n] vars)--#ifdef IDIOMATIC_VER- let initVecs = List.map genVector [1..n]-#else- let initVecs = A.array (0,n-1) [ (i, genVector i) | i <- [0..n-1] ]-#endif- - forM_ [1..n] $ \ t -> fork (compute initVecs accels t)-- sequence (List.map (\i -> get (accels A.! i)) [1..n])-- -main = - do args <- getArgs - let accList = case args of - [] -> run (3::Int)- [s] -> run (read s)- putStrLn $ show (foldl (\sum (x,y,z) -> if x>0 then sum+1 else sum) 0 accList)--
− examples/ntimes
@@ -1,153 +0,0 @@-#!/bin/bash-# ----------------------------------------------------------------------------# Intel Concurrent Collections for Haskell-# Copyright (c) 2010, Intel Corporation.-# -# This program is free software; you can redistribute it and/or modify it-# under the terms and conditions of the GNU Lesser General Public License,-# version 2.1, as published by the Free Software Foundation.-# -# This program is distributed in the hope it will be useful, but WITHOUT-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for-# more details.-# -# You should have received a copy of the GNU Lesser General Public License along with-# this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.-# ------------------------------------------------------------------------------# Usage: ntimes <N> cmd args ...--# Takes the best time out of N.-# Returns that best time in seconds to stdout.--# This script writes a bunch of stuff to stderr, but only one thing to-# stdout. The one thing, the "return value" of this process is the-# best time in seconds.--# Responds to the environment variable HIDEOUTPUT, which, if non-empty-# suppresses echoing of the child command's output.--# Also responds to NOTIME which turns off the timing.---# Time out processes after three minutes.-TIMEOUT=1000--# Unfortunately 'tempfile' is not a standard command:-function mytempfile {- date=`date +"%Y.%m.%d"`- secs=`date +"%s"`- #index=$(($index+1))- index=$1- file=./runs/"$date"_"$base"_"$CNC_VARIANT"_"$CNC_SCHEDULER"_"$NUMTHREADS"_"$secs"_"$index".log- touch $file- echo $file-}--N=$1-shift-CMD=$*--if [ "$CMD" == "" ];-then echo Usage: "ntimes <trials> <cmd> <cmdargs> ..."- exit 1-fi-base=`basename $1`--if [ ! -d "./runs" ]; then mkdir ./runs; fi --CAT=/bin/cat-- # This serves as the log- TMP1=`mytempfile 1`- echo "Execution log file: " >> /dev/stderr- echo " $TMP1" >> /dev/stderr-- #echo "=================== ASYNCHRONOUS TEST OUTPUT TO FOLLOW ======================" > $TMP1-- # if [ "$HIDEOUTPUT" == "" ];- # then (tail -f $TMP1 >> /dev/stderr) &- # fi--EXITCODE=0-- for ((i=1; i <= $N; i++)); do- # Stores just this one executable's output:- TMP2=`mytempfile 2`--# [2009.12.17] I need to get a good cross-platform process time-out system:- # HACK: Sometimes I run this on systems WITHOUT a working GHC:- if [ -e ./timeout.sh ];- then TIMEOUTRUN="./timeout.sh -t $TIMEOUT"- elif [ -e ./timeout ];- # [2010.06.03] --RTS is a hack for working around a problem with +RTS flags:- then TIMEOUTRUN="./timeout $TIMEOUT --RTS "- else TIMEOUTRUN=- fi-- if [ "$HIDEOUTPUT" == "" ];- then MYOUT=/dev/stderr- else MYOUT=/dev/null- fi-- echo | tee -a $TMP2 >> $MYOUT- echo "Running trial $i of $N:" | tee -a $TMP2 >> $MYOUT- echo "------------------------------------------------------------" | tee -a $TMP2 >> $MYOUT-- # This is hackish, it depends on the program output not containing- # the string "real". (Aside from the timing results.)-- if [ "$NOTIME" != "" ];- then ($TIMEOUTRUN $CMD) &> /dev/stdout | tee -a $TMP2 >> $MYOUT; CODE=${PIPESTATUS[0]}- elif [ `uname` == "Linux" ];- then (/usr/bin/time --format="%e real" $TIMEOUTRUN $CMD) &> /dev/stdout | tee -a $TMP2 >> $MYOUT; CODE=${PIPESTATUS[0]}- else (/usr/bin/time $TIMEOUTRUN $CMD) &> /dev/stdout | tee -a $TMP2 >> $MYOUT; CODE=${PIPESTATUS[0]}- fi-- # If there was an error, we don't commit the output to $TMP1:- if [ "$CODE" == "0" ];- then echo " Run $i of command succeeded" >> /dev/stderr-- # SUPERHACK terrain... Here's a special symbol that the script can- # use to override the external timing and use internal timing- # mechinasms.- selftime=`grep SELFTIME $TMP2`- if [ "$selftime" != "" ]; then - echo " +++ Executable appears self-timed!!:" >> $MYOUT- echo "$selftime" >> $MYOUT- cat $TMP2 | grep -v "real" | sed 's/SELFTIMED/real/' >> $TMP1- else- cat $TMP2 >> $TMP1- fi--- # [2010.05.11] I used to just give warnings when not ALL of the trials failed:- # This was for timing the nondeterministic hashtable hack:- #else echo "Warning: run $i of command failed with code $CODE: $CMD" >> /dev/stderr- else echo "ERROR run $i of command failed with code $CODE: $CMD" >> /dev/stderr- #exit $CODE- EXITCODE=$CODE- fi-- rm -f $TMP2-done;-- # Stores the times:- TMP3=`mytempfile 3`-- # HACK HACK: this assumes the string "real" doesn't occur in the test output.- grep real $TMP1 | awk '{ print $1" "$2 }' | sort -n > $TMP3-- # Echo the final output to stdout:-- echo "Final Timings: " > /dev/stderr-- cat $TMP3 | sed 's/real //' | sed 's/ real//' -- # Leave behind only $TMP1- rm -f $TMP3--exit $EXITCODE
− examples/ntimes_minmedmax
@@ -1,38 +0,0 @@-#!/bin/bash-# ----------------------------------------------------------------------------# Intel Concurrent Collections for Haskell-# Copyright (c) 2010, Intel Corporation.-# -# This program is free software; you can redistribute it and/or modify it-# under the terms and conditions of the GNU Lesser General Public License,-# version 2.1, as published by the Free Software Foundation.-# -# This program is distributed in the hope it will be useful, but WITHOUT-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for-# more details.-# -# You should have received a copy of the GNU Lesser General Public License along with-# this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.-# -----------------------------------------------------------------------------ntimes=`dirname $0`/ntimes--times=`$ntimes $*`-CODE=$?-if [ "$CODE" != "0" ];-then exit $CODE-fi--lines=`echo $times | xargs -n1 echo | wc -l`-half=$((($lines+1)/2))--echo "Median time (of $lines): " >> /dev/stderr-#echo "Median time of: $times" >> /dev/stderr--MIN=`echo $times | xargs -n1 echo | sort -n | head -n1`-MED=`echo $times | xargs -n1 echo | sort -n | head -n$half | tail -n1`-MAX=`echo $times | xargs -n1 echo | sort -n | tail -n1`--echo $MIN $MED $MAX
− examples/parfib.hs
@@ -1,74 +0,0 @@--import Data.Int-import System.Environment--- import Control.Monad.Par-import Control.Monad.ParElision-import GHC.Conc--type FibType = Int64---- sequential version of the code-fib :: FibType -> FibType-fib 0 = 1-fib 1 = 1-fib x = fib (x-2) + fib (x-1) + 1----- Basic, non-monadic parallel-fib:-parfib0 :: FibType -> FibType-parfib0 n | n < 2 = 1 -parfib0 n = x `par` y `pseq` (x+y)- where - x = parfib0 (n-1)- y = parfib0 (n-2) ----parfib1 :: FibType -> Par FibType-parfib1 n | n < 2 = return 1 -parfib1 n = - do - xf <- spawn_$ parfib1 (n-1)- y <- parfib1 (n-2) - x <- get xf- return (x+y)--main = do args <- getArgs - let (version,size) = - case args of - [] -> ("monad",10)- [v,n] -> (v,read n)-- case version of - "monad" -> do - putStrLn "Monad-par based version:"- print$ runPar$ parfib1 size- "sparks" -> do - putStrLn "Sparks-based, Non-monadic version:"- print$ parfib0 size- _ -> error$ "unknown version: "++version---{- On 4-core nehalem, 3.33ghz:-- Non-monadic version, real/user time:- fib(40) 4 threads: 1.1s 4.4s- fib(42) 4 threads: 2.9s 11.6s 17GB allocated- - SPARKS: 433784785 (290 converted, 280395620 pruned)-- Monad-par version:- fib(38) non-threaded: 23.3s 23.1s- fib(38) 1 thread : 24.7s 24.5s- fib(38) 4 threads: 8.2s 31.3s-- fib(40) 4 threads: 20.6s 78.6s 240GB allocated---For comparison, Cilkarts Cilk++:- fib(42) 4 threads: 3.029s 23.610s--Intel Cilk Plus:- fib(42) 4 threads: 4.212s 16.770s---}
− examples/partree/Makefile
@@ -1,4 +0,0 @@-include ../common.mk--partree.exe : $(wildcard *.hs) ../../Control/Monad/Par.hs- $(GHC) -O2 -cpp --make -i../.. partree.hs -o $@ -threaded -rtsopts
− examples/partree/Tree.hs
@@ -1,146 +0,0 @@--- -*- 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--}
− examples/partree/partree.hs
@@ -1,34 +0,0 @@--- -*- haskell -*---- partree--- parallel map over a tree --------------------------------------------------------------------------------module Main where--import System.Environment(getArgs)-import Control.Parallel-import Tree--main = do [arg1,arg2] <- getArgs- let - n = read arg1 :: Int -- size of tree in nodes- c = read arg2 :: Int -- work per node- res = partree c n- putStrLn ("partree " ++ unwords [arg1,arg2] ++ " = " ++ show res)---- worker function to be mapped over the tree; heavily allocating!-bar :: Int -> Int -> Int-bar c n = tree_fold (\x y -> (x+y) `quot` 2) 0 t - where forest = [ let - l = take n (iterate (+i) i)- in- list2tree l - | i <- [1..c + n `mod` 15] ]- t = foldl1 (^:) forest---- generate a tree with n nodes;--- then map and fold 2 functions over it-partree :: Int -> Int -> Int-partree c n = (force_tree t) `seq` (tree_fold max 0 t)- where t = par_tree_map (bar c) (list2tree [1..n])-
− examples/plot_scaling.hs
@@ -1,355 +0,0 @@-#!/usr/bin/env runhaskell-{-# LANGUAGE NamedFieldPuns- #-}---- This script generates gnuplot plots.--- Give it a .dat file as input... (or it will try to open results.dat)---import Text.PrettyPrint.HughesPJClass-import Text.Regex-import Data.List-import Data.Function-import Control.Monad-import System-import System.IO-import System.FilePath -import System.Environment--import HSH-import Data.Array (listArray, )-import Data.Monoid (mappend, )-import Debug.Trace---linewidth = "5.0"---- Schedulers that we don't care to graph right now.--- This happens BEFORE rename---scheduler_MASK = [5,6,99,10]-scheduler_MASK = []---- Ok, gunplot line type 6 is YELLOW... that's not to smart:-line_types = [0..5] ++ [7..]--round_2digits :: Double -> Double-round_2digits n = (fromIntegral $round (n * 100)) / 100----x11 = terminal Terminal.X11.cons---x11 = terminal cons---x11 = terminal Graphics.Gnuplot.Terminal.X11.cons---x11 = terminal X11.cons---- Split -parse [a,b,c,d,e,f] =- Entry { name = a, - variant = b,- sched = "trace",- threads = read c,- tmin = read d,- tmed = read e,- tmax = read f,- normfactor = 1.0- }----parse [a,b,c,d,e,f,g,h,i] = --- trace ("Got line with norm factor: "++ show [a,b,c,d,e,f,g,h,i])--- (parse [a,b,c,d,e,f,g,h]) { normfactor = read i }--parse other = error$ "Cannot parse, wrong number of fields, "++ show (length other) ++" expected 8 or 9: "++ show other-------------------------------------------------------------------------------------- Let's take a particular interpretation of Enum for pairs:-instance (Enum t1, Enum t2) => Enum (t1,t2) where - succ (a,b) = (succ a, succ b)- pred (a,b) = (pred a, pred b)- toEnum n = (toEnum n, toEnum n)- fromEnum (a,b) = case (fromEnum a, fromEnum b) of- (x,y) | x == y -> x- (x,y) -> error$ "fromEnum of pair: nonmatching numbers: " ++ show x ++" and "++ show y----- Removes single blanks and separates lines into groups based on double blanks.-sepDoubleBlanks :: [String] -> [[String]]-sepDoubleBlanks ls = loop [] ls - where - loop acc [] = [reverse acc]- loop acc ("":"":t) = reverse acc : loop [] (stripLeadingBlanks t)- loop acc ("":t) = loop acc t- loop acc (h :t) = loop (h:acc) t - stripLeadingBlanks [] = [] - stripLeadingBlanks ("":t) = stripLeadingBlanks t- stripLeadingBlanks ls = ls---remComments :: String -> [String] -> [String]-remComments commentchars ls = filter (pred . stripLeadingWhitespace) ls- where - pred str = not (take (length commentchars) str == commentchars) - stripLeadingWhitespace [] = [] - stripLeadingWhitespace (' ':t) = stripLeadingWhitespace t- stripLeadingWhitespace ls = ls-------------------------------------------------------------------------------------- Here's the schema for the data from my timing tests:-data Entry = Entry { - name :: String,- variant :: String,- sched :: String,- threads :: Int, - tmin :: Double,- tmed :: Double,- tmax :: Double,- normfactor :: Double-}- deriving Show--instance Pretty Entry where- --pPrint x = pPrint$ show x- pPrint Entry { name, sched, variant, threads, tmin, tmed, tmax, normfactor } = - pPrint ("ENTRY", name, sched, variant, threads, (tmin, tmed, tmax), normfactor )--- pPrint ("ENTRY", name, variant, sched, threads, tmin, tmed, tmax, normfactor)---groupSort fn = - (groupBy ((==) `on` fn)) . - (sortBy (compare `on` fn))---- Add three more levels of list nesting to organize the data:---organize_data :: [Entry] -> [[[[Entry]]]]-organize_data :: [Entry] -> [[[[Entry]]]]-organize_data = - (map (map (groupSort sched))) . - (map (groupSort variant)) .- (groupSort name)---newtype Mystr = Mystr String--instance Show Mystr where- show (Mystr s) = s--{---- I ended up giving up on using the gnuplot package on hackage:--- mypath :: Graph2D.T ---Plot2D.T---plot_benchmark :: [[[Entry]]] -> IO ()---plot_benchmark :: [[[Entry]]] -> Plot2D.T-plot_benchmark [io, pure] = - --Plot.plot (X11.title "foobar" X11.cons) $- Plot.plot X11.cons $- Frame.cons (Opts.title ("Benchmark: " ++ benchname ++ " normalized to time " ++ show basetime) $ Opts.deflt) plots- where - benchname = name $ head $ head io - plots = foldl1 mappend (map persched io ++ map persched pure)- basetime = foldl1 min $ map tmed $- filter ((== 0) . threads) $- (concat io ++ concat pure)- persched :: [Entry] -> Plot2D.T- persched dat = - let - schd = sched$ head dat- var = variant$ head dat- mins = map tmin dat- meds = map tmed dat- maxs = map tmax dat- --zip4 = map$ \ a b c d -> (a,b,c,d)- zip4 s1 s2 s3 s4 = map (\ ((a,b), (c,d)) -> (a,b,c,d))- (zip (zip s1 s2) (zip s3 s4))- pairs = zip4 (map (fromIntegral . threads) dat) - (map (basetime / ) meds)- (map (basetime / ) mins)- (map (basetime / ) maxs)- quads = map (\ (a,b,c,d) -> Mystr (show a ++" "++ show b ++" "++ show d ++" "++ show c))- pairs - in - fmap (Graph2D.lineSpec $ - LineSpec.title (var ++"/"++ show schd) $ - LineSpec.lineWidth 3.0 $ - LineSpec.pointSize 3.0 $ - LineSpec.deflt) $ - fmap (Graph2D.typ Graph2D.linesPoints) $- --Plot2D.path pairs- --Plot2D.path (map ( \ (a,b,c,d) -> (a,b)) pairs)- --fmap (Graph2D.typ Graph2D.errorBars) $- Plot2D.list quads--}---- Name, Scheduler, Threads, BestTime, Speedup-data Best = Best (String, String, String, Int, Double, Double)---- Plot a single benchmark as a gnuplot script:-plot_benchmark2 root [io, pure] = - do action $ filter goodSched (io ++ pure)- return$ Best (benchname, bestvariant, - bestsched, bestthreads, best, basetime / best)- where - benchname = name $ head $ head io - -- What was the best single-threaded execution time across variants/schedulers:-- goodSched [] = error "Empty block of data entries..."- goodSched (h:t) = not $ (sched h) `elem` scheduler_MASK-- cat = concat io ++ concat pure- threads0 = filter ((== 0) . threads) cat- threads1 = filter ((== 1) . threads) cat-- map_normalized_time = map (\x -> tmed x / normfactor x)-- times0 = map_normalized_time threads0- times1 = map_normalized_time threads1-- basetime = if not$ null times0 - then foldl1 min times0- else if not$ null times1 - then foldl1 min times1- else error$ "\nFor benchmark "++ show benchname ++ " could not find either 1-thread or 0-thread run.\n" ++- --"ALL entries: "++ show (pPrint cat) ++"\n"- "\nALL entries threads: "++ show (map threads cat)-- best = foldl1 min $ map_normalized_time cat- Just best_index = elemIndex best $ map_normalized_time cat- bestsched = sched$ cat !! best_index- bestvariant = variant$ cat !! best_index- bestthreads = threads$ cat !! best_index-- (filebase,_) = break (== '.') $ basename benchname -- -- If all normfactors are the default 1.0 we print a different message:- --let is_norm = not$ all (== 1.0) $ map normfactor ponits- norms = map normfactor (concat io ++ concat pure)- default_norms = all (== 1.0) $ norms- max_norm = foldl1 max norms-- scrub '_' = ' '- scrub x = x- -- scrub [] = []- -- scrub ('_':t) = "\\_"++ scrub t- -- scrub (h:t) = h : scrub t-- action lines = - do - let scriptfile = root ++ filebase ++ ".gp"- putStrLn$ " Dumping gnuplot script to: "++ scriptfile-- putStrLn$ " NORM FACTORS "++ show norms--- runIO$ echo "set terminal postscript enhanced color\n" -|- appendTo scriptfile- runIO$ echo ("set output \""++filebase++".eps\"\n") -|- appendTo scriptfile- runIO$ echo ("set title \"Benchmark: "++ map scrub filebase ++- ", speedup relative to serial time " ++ show (round_2digits $ basetime * max_norm) ++" seconds "++ --- "for input size " ++ show (round_2digits max_norm)- (if default_norms then "" else "for input size " ++ show (round max_norm))- --if is_norm then "normalized to work unit"- --if default_norms then "" else " per unit benchmark input"- ++"\"\n") -|- appendTo scriptfile- runIO$ echo ("set xlabel \"Number of Threads\"\n") -|- appendTo scriptfile- runIO$ echo ("set ylabel \"Parallel Speedup\"\n") -|- appendTo scriptfile--- runIO$ echo ("set xrange [1:]\n") -|- appendTo scriptfile- runIO$ echo ("set key left top\n") -|- appendTo scriptfile- runIO$ echo ("plot \\\n") -|- appendTo scriptfile-- -- In this loop lets do the errorbars:- forM_ (zip [1..] lines) $ \(i,points) -> do - let datfile = root ++ filebase ++ show i ++".dat"- runIO$ echo (" \""++ basename datfile ++"\" using 1:2:3:4 with errorbars lt "++- show (line_types !! i) - ++" title \"\", \\\n") -|- appendTo scriptfile-- -- Now a second loop for the lines themselves and to dump the actual data to the .dat file:- forM_ (zip [1..] lines) $ \(i,points) -> do - let datfile = root ++ filebase ++ show i ++".dat" - let schd = sched$ head points -- should be the same across all point- let var = variant$ head points -- should be the same across all point- let nickname = var ++"/"++ schd- runIO$ echo ("# Data for variant "++ nickname ++"\n") -|- appendTo datfile- forM_ points $ \x -> do -- -- Here we print a line of output:- runIO$ echo (show (fromIntegral (threads x)) ++" "++- show (basetime / (tmed x / normfactor x)) ++" "++- show (basetime / (tmax x / normfactor x)) ++" "++ - show (basetime / (tmin x / normfactor x)) ++" \n") -|- appendTo datfile-- let comma = if i == length lines then "" else ",\\"- runIO$ echo (" \""++ basename datfile ++- "\" using 1:2 with lines linewidth "++linewidth++" lt "++ - show (line_types !! i) ++" title \""++nickname++"\" "++comma++"\n")- -|- appendTo scriptfile-- --putStrLn$ "Finally, running gnuplot..."- --runIO$ "(cd "++root++"; gnuplot "++basename scriptfile++")"- --runIO$ "(cd "++root++"; ps2pdf "++ filebase ++".eps )"-----plot_benchmark2 root ls = putStrLn$ "plot_benchmark2: Unexpected input, list len: "++ show (length ls)-plot_benchmark2 root [io] = plot_benchmark2 root [io,[]]----isMatch rg str = case matchRegex rg str of { Nothing -> False; _ -> True }--main = do - args <- getArgs - let file = case args of - [f] -> f - [] -> "results.dat"- dat <- run$ catFrom [file] -|- remComments "#" -- let parsed = map (parse . filter (not . (== "")) . splitRegex (mkRegex "[ \t]+")) - (filter (not . isMatch (mkRegex "ERR")) $- filter (not . isMatch (mkRegex "TIMEOUT")) $- filter (not . null) dat)- let organized = organize_data$ - -- filter ((`elem` ["io","pure"]) . variant) parsed- parsed-- putStrLn$ "Parsed "++show (length parsed)++" lines containing data."- print organized-- let root = "./" ++ dropExtension file ++ "_graphs/"- -- For hygiene, completely anhilate output directory:- system$ "rm -rf " ++root ++"/"- system$ "mkdir -p "++root- bests <- - forM organized $ \ perbenchmark -> do - best <- plot_benchmark2 root perbenchmark- forM_ perbenchmark $ \ pervariant -> - forM_ pervariant $ \ persched -> - do let mins = map tmin persched- let pairs = (zip (map (fromIntegral . threads) persched) mins)- --putStrLn$ show pairs- --plot Graphics.Gnuplot.Terminal.X11.cons (path pairs)- --System.exitWith ExitSuccess- --plot x11 (path pairs)- return ()-- return best-- putStrLn$ "Now generating final plot files...\n\n"-- let summarize hnd = do - hPutStrLn hnd $ "# Benchmark, scheduler, best #threads, best median time, max parallel speedup: "- hPutStrLn hnd $ "# Summary for " ++ file-- let pads n s = take (n - length s) $ repeat ' '- let pad n x = " " ++ (pads n (show x))-- forM_ bests $ \ (Best(name, variant, sched, threads, best, speed)) ->- hPutStrLn hnd$ " "++ name++ (pad 25 name) ++- show variant++ (pad 10 variant)++- show sched++ (pad 5 sched) ++- show threads++ (pad 5 threads)++ - show best ++ (pad 15 best) ++- show speed - hPutStrLn hnd$ "\n\n"-- putStrLn$ "Done."- summarize stdout- withFile (dropExtension file `addExtension` "summary") WriteMode $ summarize -
− examples/primes.hs
@@ -1,52 +0,0 @@------ This is a simplistic benchmark but is included just for comparison with Haskell CnC---- Author: Ryan Newton --import System.Environment-import Control.Monad.Par-import Control.Monad.Par.AList as A-import Debug.Trace----- First a naive serial test for primality:-isPrime :: Int -> Bool-isPrime 2 = True-isPrime n = (prmlp 3 == n)- where prmlp :: Int -> Int- prmlp i = if (rem n i) == 0- then i else prmlp (i + 2)---------------------------------------------- Next, a CnC program that calls the serial test in parallel.--primes :: Int -> Int -> Par (AList Int)-primes start end = --- parMapReduceRange (InclusiveRange start end)- parMapReduceRangeThresh 100 (InclusiveRange start end)- (\n -> if - -- TEMP: Need a strided range here:- (rem n 2 /= 0) && isPrime n - then return$ singleton n- else return$ empty)- (\ a b -> return (append a b))- empty---- This version never builds up the list, it simply counts:--- countprimes :: Int -> Int -> Par Int--- countprimes start end = - --main = do args <- getArgs - let size = case args of - [] -> 1000 -- Should output 168- [n] -> (read n)-- ls = runPar $ primes 3 size- --- putStrLn (show ls)- putStrLn (show (1 + A.length ls)) -- Add one to include '2'.- return ()
− examples/queens.hs
@@ -1,32 +0,0 @@-{-# LANGUAGE BangPatterns #-}-import System.Environment-import Control.Monad-import Control.Seq--import Control.Monad.Par--- import Control.Monad.Par_Strawman--nqueens :: Int -> Par [[Int]]-nqueens nq = step 0 []- where- threshold = 5-- step :: Int -> [Int] -> Par [[Int]]- step !n b- | n >= threshold = return (iterate gen [b] !! (nq - n))- | otherwise = do- rs <- parMapM (step (n+1)) (gen [b])- return (concat rs)-- safe :: Int -> Int -> [Int] -> Bool- safe x d [] = True- safe x d (q:l) = x /= q && x /= q+d && x /= q-d && safe x (d+1) l-- gen :: [[Int]] -> [[Int]]- gen bs = [ (q:b) | b <- bs, q <- [1..nq], safe q 1 b ]---main = do- args <- fmap (fmap read) getArgs- let n = case args of [] -> 8; [n] -> n- print (length (runPar (nqueens n)))
− examples/run_tests.sh
@@ -1,19 +0,0 @@-#!/bin/bash--# set -e -# set -o errexit--for file in "$@"; do- echo Running test $file- ./$file &> $file".out"-# echo "Return code: $?"- code=$?- if [ "$code" != 0 ]; then - echo- echo " ERROR, output was:"- cat $file".out"- echo- echo " ERROR: exit code $code"- exit $code- fi-done
− examples/stream/DEVLOG.txt
@@ -1,141 +0,0 @@--Notes on development of monad-par streaming framework and benchmarks.------------------------------------------------------------------------[2011.03.19] Right now I'm seeing a weird behavior where when run--threaded it prints many of the messages before "new"' in the filter-stage, but it doesn't print the messages after "put" in that same-stage.--This system allows self-stealing, correct? --[2011.03.19] -- Quick measurements on wasp:- ---------------------------- Throughput of just countupWindowed + measureRate ...- 2 threads is 8600 * 1024 = 8,806,400 = 8.8mHz.-- * With -N4 it uses ~234% CPU and gets sligthly confused, lowering- throughput to 5800-6100 windows/sec from 8600-- * It actually does work (e.g. doesn't deadlock) to run it with -N1- because there's only one kernel. The throughput is much more- variable. From 4800-8500 win/sec. GC time is tiny in this- case, 0.5%.- ---------------------------- Throughput of a single amap (+100) kernel = -- * Gets stuck waiting for first kernel -N1 as expected (and fills memory).-- * on -N2 it gets a rate of between 7937 and 8200 wins/sec but then- it gets stuck after about 10 seconds. I don't fully understand- this. The two threads should be enough for the two kernels- right? Currently Par.hs forks a "replacement thread" to continue- working on the queue when runParAsync returns. Therefore there- should be enough haskell threads, even if there are only two Par- scheduler threads. Those two par workers should be preemptable by- the measureRate thread....-- * on -N3 it works, and gives 6200-7100 wins/sec throughput. Uses- ~245% CPU. Presumably the two par worker threads are hammering- away and the measureRate one is less busy. But if I leave it- running for a while it grew up to 79% (of 16gb) mem usage.- Strange, -s claims the following. How can max resdency be so low!?-- 2,993,287,338,808 bytes allocated in the heap- 17,134,304,736 bytes copied during GC- 3,744,408 bytes maximum residency (152145 sample(s))- 1,870,240 bytes maximum slop- 14 MB total memory in use (3 MB lost due to fragmentation)-- Generation 0: 4961153 collections, 4961152 parallel, 696.02s, 63.29s elapsed- Generation 1: 152145 collections, 152145 parallel, 115.00s, 22.66s elapsed-- Parallel GC work balance: 1.08 (2102121164 / 1946757116, ideal 3)-- MUT time (elapsed) GC time (elapsed)- Task 0 (worker) : 0.02s ( 0.00s) 0.00s ( 0.00s)- Task 1 (worker) : 1927.40s (742.55s) 0.00s ( 0.00s)- Task 2 (worker) : 1927.40s (742.55s) 0.00s ( 0.00s)- Task 3 (worker) : 1928.34s (743.40s) 0.00s ( 0.00s)- Task 4 (worker) : 1928.34s (743.40s) 0.00s ( 0.00s)- Task 5 (bound) : 0.00s ( 0.00s) 0.11s ( 0.02s)- Task 6 (worker) : 1928.34s (743.40s) 0.00s ( 0.00s)- Task 7 (worker) : 1117.43s (743.40s) 810.91s ( 85.93s)-- SPARKS: 0 (0 converted, 0 pruned)-- INIT time 0.00s ( 0.00s elapsed)- MUT time 1117.32s (743.40s elapsed)- GC time 811.02s ( 85.95s elapsed)- EXIT time 0.00s ( 0.01s elapsed)- Total time 1928.34s (829.36s elapsed)-- %GC time 42.1% (10.4% elapsed)-- Alloc rate 2,678,988,417 bytes per MUT second-- Productivity 57.9% of total user, 134.7% of total elapsed-- gc_alloc_block_sync: 6092257- whitehole_spin: 0- gen[0].sync_large_objects: 190255- gen[1].sync_large_objects: 267-- Oh, maybe because of the CArray's all the real storage is outside haskell's heap.-- There must be a memory leak in streamMap. Trying to fix it:-- (1) Factored out 'loop'. I need to try to ensure that no closure- holds onto the original head of the stream. Wow! That- lowered throughput a lot (-N3) and drove cpu usage up! 3500- wins/sec declining to 300. And it still leaks.- The key difference seems to be passing the extra "fn" argument to loop.-- (2) Hmm... I went back to what I *thought* was the previous form- above (that leaked). But now it's getting the good >6000- throughput and doesn't seem to be leaking. It gives memory- back to the system and goes up and down in mem footprint.- But now it uses 300% cpu. The only difference I can see is- that I changed the module export decl. How could this matter- if compiling into an executable? Nevertheless maybe this- helps it inline.... Now I can run it for 10 min with minimal- memory usage.-- -qa seems to help the variance on -N4, i.e. with more workers- than kernels.-- ---------------------------- Throughput of a single FFT kernel.-- * Oops, maybe this accounts for the difference above between- leaking/non-leaking. The FFT version maintains a high >7000- wins/sec throughput. But it leaks memory. Maybe it's not- really doing the FFT and is leaking suspensions?-- * Nope... I tried forcing the FFT by inspecting one element of the- output. Still leaks. Well, the answer is simple. It just- can't keep up with a source that has no backpressure. To- confirm this hypothesis, I ran it with -N1 (with the new- yielding source operator). NOPE, it still leaks.---[2011.03.20] {Added disjoint_working_sets_pipeline}--Ok, first try. Not only has this not demonstrated the benefit of-pipeline parallelism, right now it isn't showing much of a speedup at-all. Right now I'm running with default parameters (4 256 10 20000)--Running with "-N4 -qa" I see large variance. Between 1.0 and 3.3-seconds. Seeing the same without -qa:--Running without no extra runtime flags (no -qa):- nothreads: 2.18s- 1thread: 2.3s- 4threads: 1-3 seconds.--The big difference is running with N>1 it can spend a lot of time in-GC (e.g. 84%!!). But I need to stop running on wasp for actual-parallel speedup measurements -- I seem to have problems using wasp-for this purpose.
− examples/stream/Makefile
@@ -1,32 +0,0 @@-include ../common.mk--SRC= simple1_measureSrc.hs \- disjoint_working_sets_pipeline.hs \- fft_pipeline.hs-EXES= $(SRC:.hs=.exe)--NOTHREAD= $(SRC:.hs=.nothread.exe)--# Par source code with relative paths updated for this deeper directory:-RELPARSRC= $(subst ../,../../,$(ALLPARSRC))--all: $(EXES)--%.exe : %.hs $(RELPARSRC)- $(GHC) -O2 --make -i../../ $< -o $@ -threaded -rtsopts---#-------------------------------------------------------------# Build the non-threaded versions.--nothread: $(NOTHREAD)--%.nothread.exe: %.hs $(RELPARSRC)- $(GHC) -O2 --make -i../../ $< -o $@ -rtsopts--#-------------------------------------------------------------runtests: - ../run_tests.sh $(EXES) --clean:- rm -f $(EXES) *.o *.hi
− examples/stream/disjoint_working_sets_pipeline.hs
@@ -1,276 +0,0 @@-{-# LANGUAGE BangPatterns, ScopedTypeVariables, CPP #-}-{-# OPTIONS_GHC -fwarn-unused-imports #-}---- The goal of this benchmark is to demonstrate kernels that have private--- state which has to be read from memory on each invocation. Further,--- the state forms the majority of the working set -- it's larger than--- the streaming input.---- In theory this means that keeping a kernel on one core and--- exploiting pipeline parallelism is better than following the data--- through the stream graph in a depth first traversal.-----module Main(main) where-module Main where--import Control.Monad as C-import Control.Monad.Par -import Control.Monad.Par.Stream as S-import Control.Monad.Par.OpenList-import Control.DeepSeq-import Control.Exception-import Control.Parallel.Strategies as Strat---- import Data.Array.Unboxed as U-import Data.Complex-import Data.Int-import Data.Word-import Data.List (intersperse) -import Data.List.Split (chunk)--import Prelude as P-import System.Environment-import System.Exit-import System.CPUTime-import System.CPUTime.Rdtsc-import GHC.Conc as Conc-import GHC.IO (unsafePerformIO, unsafeDupablePerformIO, unsafeInterleaveIO)--import Debug.Trace-import Control.Monad.Par.Logging--import qualified Data.Vector.Unboxed as UV-import Data.Vector.Unboxed hiding ((++))---- Performs some (presently meaningless) computation on a state & a--- window (stream element) to compute a new state and new window.------ Assumes statesize is a multiple of bufsize:-statefulKern :: Vector Double -> Vector Double -> (Vector Double, Vector Double)-statefulKern state buf = (newstate, newelem)- where - -- We could probably test the memory behavior we're interested in- -- better with inplace update here... but for now, this:- newstate = UV.map (\d -> d/sum + 2) state- newelem = UV.map (+sum) buf-- sum = P.sum partialSums- partialSums = [ sumslice (cutslice n) | n <- [0..factor-1] ] -- cutslice n = UV.slice (n*blen) blen state- sumslice slce = UV.sum (UV.zipWith (+) buf slce)-- factor = slen `quot` blen- slen = UV.length state- blen = UV.length buf------------------------------------------------------------------------------------monadpar_version (_,numfilters, bufsize, statecoef, numwins) = do - putStrLn$ "Running monad-par version."-- let statesize = bufsize * statecoef- results <- evaluate $ runPar$ do - strm1 :: Stream (UV.Vector Double) <- S.generate numwins (\n -> UV.replicate bufsize 0)- -- Make a pipeline of numfilters stages:- let initstate = UV.generate statesize fromIntegral- pipe_end <- C.foldM (\s _ -> streamScan statefulKern initstate s) strm1 [1..numfilters]-- sums <- streamMap UV.sum pipe_end-#if 0- return sums-- -- This is tricky, but two different consumers shouldn't prevent- -- garbage collection.- ls <- toListSpin results--- Just (Cons h _) <- pollIVar results- putStrLn$ "Sum of first window: " ++ show (P.head ls)- forkIO$ measureRateList ls- putStrLn$ "Final sum = "++ show (P.sum ls)-#else-- streamFold (+) 0 sums-- putStrLn$ "Final sum = "++ show results-#endif-------------------------------------------------------------------------------------sparks_version (_,numfilters, bufsize, statecoef, numwins) = do - putStrLn$ "Running sparks version."-- -- Here we represent the stream as a plain list.- let - statesize = bufsize * statecoef- strm1 :: [UV.Vector Double] = P.replicate numwins $ UV.replicate bufsize 0- initstate = UV.generate statesize fromIntegral- applyKern = scan statefulKern initstate---- This one has the problem that it fully evaluates the stream for the--- first kernel before moving on to the second:--- strm_last = (parRepeatFun numfilters applyKern) strm1-- pipe_end = applyNKernels statefulKern numfilters initstate strm1-- sums = P.map UV.sum pipe_end--- #define SERIAL-#ifndef SERIAL- `using` (Strat.parBuffer numCapabilities rwhnf) -#endif-- putStrLn$ "Sum of first window: "++ show (P.head sums)- measureRateList (sums)--- measureRateList (strm_last)--- measureRateList (forceList strm_last)- putStrLn$ "Final Sum = " ++ show (P.sum sums)---- Make sure the cars of a list are evaluated before following each cdr:-forceList [] = []-forceList (h:t) = rnf h `seq` forceList t---- A slightly different version of Data.List.scanl-scan :: (a -> b -> (a,c)) -> a -> [b] -> [c]-scan f q [] = []-scan f q (h:t) = h' : scan f q t- where - (q',h') = f q h--type StatefulKernel s a b = s -> a -> (s,b)---- applyNKernels _ _ _ [] = []-applyNKernels :: NFData a => StatefulKernel s a a -> Int -> s -> [a] -> [a]-applyNKernels _ 0 _ ls = ls-applyNKernels kern n init ls = - applyNKernels kern (n-1) init (loop init ls)- where - loop st [] = []- loop st (h:t) = - let (st', x) = kern st h in-#ifndef SERIAL- rnf x `par` -#endif- x : loop st' t- --- Compose two stateful kernels in parallel.-composeStatefulKernels :: (NFData b, NFData s1) => - StatefulKernel s1 a b -> StatefulKernel s2 b c - -> StatefulKernel (s1,s2) a c--- composeStatefulKernels (f1,f2) (s1,s2) x = -composeStatefulKernels f1 f2 (s1,s2) x = - rnf pr1 `par` (newstate, snd pr2)- where - pr1 = f1 s1 x- pr2 = f2 s2 (snd pr1)- newstate = (fst pr1, fst pr2)---parRepeatFun n f = --- P.foldr (.) id (P.replicate n f)- P.foldr (.|| rdeepseq) id (P.replicate n f)-------------------------------------------------------------------------------------- Main script--default_version = "monad"-default_numfilters = 4-default_bufsize = 256-default_statecoef = 10 -- in MULTIPLES of bufsize-default_numwins = 10 * 1000---main = do- args <- getArgs- arg_tup@(version,_,_,_,_) <- - case args of - [] -> return (default_version, default_numfilters, default_bufsize, default_statecoef, default_numwins)- [a,b,c,d,e] -> return (a, read b, read c, read d, read e)- _ -> do - putStrLn$ "ERROR: Invalid arguments, must take 0 or 5 args."- putStrLn$ " Expected args: (version='monad'|'sparks' #filters, bufsize, stateSizeMultiplier, #bufsToProcess)"- putStrLn$ " Received args: "++ show args- exitFailure -- putStrLn$ "numCapabilities: "++ show numCapabilities- putStrLn$ " Frequency in measurable ticks: "++ commaint one_second ++ "\n"-- case version of - "monad" -> monadpar_version arg_tup- "sparks" -> sparks_version arg_tup- _ -> error$ "unknown version: "++version-- putStrLn$ "Finally, dumping all logs:"- printAllLogs------ It is not necessary to evaluate every element in the case of an unboxed vector.-instance NFData a => NFData (UV.Vector a) where- rnf !vec = ()---print_ msg = trace msg $ return ()---- work pop 1 peek N push 1 --- float->float filter --- firFilter n coefs = --- {---- float sum = 0;--- for (int i = 0; i < N; i++)--- sum += peek(i) * COEFF[N-1-i];--- pop();--- push(sum);--- }--- }---{- --Here's what cachegrind says (on 4 core nehalem):-- $ valgrind --tool=cachegrind ./stream/disjoint_working_sets_pipeline monad 4 768 10 1000 +RTS -N4- .....- [measureRate] current rate: 58 Total elems&time 916 181,988,055,721- [measureRate] Hit end of stream after 1000 elements.- Final sum = 1.560518243231086e22- ==21202== - ==21202== I refs: 7,111,462,273- ==21202== I1 misses: 374,190- ==21202== L2i misses: 298,364- ==21202== I1 miss rate: 0.00%- ==21202== L2i miss rate: 0.00%- ==21202== - ==21202== D refs: 3,882,935,974 (3,542,949,529 rd + 339,986,445 wr)- ==21202== D1 misses: 14,606,684 ( 9,824,455 rd + 4,782,229 wr)- ==21202== L2d misses: 6,774,479 ( 2,088,565 rd + 4,685,914 wr)- ==21202== D1 miss rate: 0.3% ( 0.2% + 1.4% )- ==21202== L2d miss rate: 0.1% ( 0.0% + 1.3% )- ==21202== - ==21202== L2 refs: 14,980,874 ( 10,198,645 rd + 4,782,229 wr)- ==21202== L2 misses: 7,072,843 ( 2,386,929 rd + 4,685,914 wr)- ==21202== L2 miss rate: 0.0% ( 0.0% + 1.3% )---Sparks version:- Final Sum = 1.560518243231086e22- ==21226== - ==21226== I refs: 5,898,314,238- ==21226== I1 misses: 291,271- ==21226== L2i misses: 246,518- ==21226== I1 miss rate: 0.00%- ==21226== L2i miss rate: 0.00%- ==21226== - ==21226== D refs: 3,264,359,909 (3,206,394,437 rd + 57,965,472 wr)- ==21226== D1 misses: 16,003,068 ( 10,905,138 rd + 5,097,930 wr)- ==21226== L2d misses: 9,177,043 ( 4,207,106 rd + 4,969,937 wr)- ==21226== D1 miss rate: 0.4% ( 0.3% + 8.7% )- ==21226== L2d miss rate: 0.2% ( 0.1% + 8.5% )- ==21226== - ==21226== L2 refs: 16,294,339 ( 11,196,409 rd + 5,097,930 wr)- ==21226== L2 misses: 9,423,561 ( 4,453,624 rd + 4,969,937 wr)- ==21226== L2 miss rate: 0.1% ( 0.0% + 8.5% )-- -}
− examples/stream/fft_pipeline.hs
@@ -1,75 +0,0 @@-{-# OPTIONS_GHC -fwarn-unused-imports #-}--module Main(main) where--import Control.Monad.Par -import Control.Monad.Par.Stream as S-import Control.Exception-import Data.Complex-import GHC.Conc as Conc-import Debug.Trace-import Math.FFT (dft)--type Elt = Complex Double--fft_kern :: Window Elt -> Window Elt-fft_kern arr = dft arr---- -- TEMP, evaluate one element to make sure the fft really gets called:--- -- trace ("One elt sample: "++ show (arr!10)) $--- case arr2 ! 10 of _ -> arr2--- where arr2 = dft arr------------------------------------------------------------------------------------- Main script---- target = maxBound-target = 10 * 1000 * 1000-bufsize = 1024--main = do- putStrLn$ "numCapabilities: "++ show numCapabilities- putStrLn$ " Frequency in measurable ticks: "++ commaint one_second ++ "\n"--- putStrLn$ "Performing FFT of "++ commaint target ++" numbers windowed into buffers of size "++ show bufsize ++"\n"-- results <- evaluate $ runParAsync$ do -- strm1 <- countupWin bufsize target :: Par (WStream Elt)-- print_$ "\n Next, applying FFT filter... "- strm2 <- streamMap fft_kern strm1 ---- Make a pipeline of 10 stages:--- strm2 <- foldl (\ s _ -> streamMap kern0) strm1 [1..10]-- print_$ "\n Stream graph constructed, returning from Par computation... "- return strm2-- measureRate results- putStrLn$ "End of stream reached. All done."---print_ msg = trace msg $ return ()---- work pop 1 peek N push 1 --- float->float filter --- firFilter n coefs = --- {---- float sum = 0;--- for (int i = 0; i < N; i++)--- sum += peek(i) * COEFF[N-1-i];--- pop();--- push(sum);--- }--- }---{-- Notes:---- -}
− examples/stream/simple1_measureSrc.hs
@@ -1,35 +0,0 @@-{-# OPTIONS_GHC -fwarn-unused-imports #-}--module Main(main) where--import Control.Monad-import Control.Monad.Par -import Control.Monad.Par.Stream as S-import Control.Monad.Par.OpenList-import Control.DeepSeq-import Control.Exception---- import Data.Array.Unboxed as U-import Data.Array.CArray as C-import Data.Complex-import Data.Int-import Data.Word-import Data.List (intersperse)-import Data.List.Split (chunk)--import System.CPUTime-import System.CPUTime.Rdtsc-import GHC.Conc as Conc-import GHC.IO (unsafePerformIO, unsafeDupablePerformIO, unsafeInterleaveIO)-import Debug.Trace------------------------------------------------------------------------------------- Main script--main = do-- -- Generate 20 million elements:- let s = countupWin 1024 (20 * 1000 * 1000) :: Par (WStream Int)- measureRate $ runParAsync s- - putStrLn$ "Done with 5 million elements."
− examples/sumeuler/ListAux.hs
@@ -1,41 +0,0 @@-module ListAux where--import Data.List----- splitting into n parts, and its inverse:--splitIntoN :: Int -> [a] -> [[a]]-splitIntoN n xs = takeIter parts xs- where l = length xs- parts = zipWith (+) ((replicate (l `mod` n) 1) ++ repeat 0)- (replicate n (l `div` n))-takeIter :: [Int] -> [a] -> [[a]]-takeIter [] [] = []-takeIter [] _ = error "elements left over"-takeIter (t:ts) xs = hs : takeIter ts rest- where (hs,rest) = splitAt t xs--unSplit :: [[a]] -> [a]-unSplit = concat---- splitting into parts of same size. Inverse is concat again.--splitAtN :: Int -> [a] -> [[a]]-splitAtN n [] = []-splitAtN n xs = ys : splitAtN n zs- where (ys,zs) = splitAt n xs---------------------------------------------- splitting round-robin until list runs empty, and its inverse:--unshuffle :: Int -> [a] -> [[a]]-unshuffle n xs = [takeEach n (drop i xs) | i <- [0..n-1]]- where takeEach n [] = []- takeEach n (x:xs) = x : takeEach n (drop (n-1) xs)---- inverse to unshuffle-shuffle :: [[a]] -> [a]-shuffle = concat . transpose-
− examples/sumeuler/Makefile
@@ -1,7 +0,0 @@-include ../common.mk--sumeuler.exe : $(wildcard *.hs) ../../Control/Monad/Par.hs- $(GHC) -O2 -cpp --make -i../.. SumEuler.hs -o $@ -threaded -rtsopts--clean:- rm -f *.exe *.hi *.o
− examples/sumeuler/SumEuler.hs
@@ -1,287 +0,0 @@-{-# OPTIONS -Wall #-}------ Euler totient function (strategic version).--- Orig taken from "Research Directions in Parallel Functional Programming",--- Chapter "Performance Monitoring", Nathan Charles and Colin Runciman.------ (c) 2001 Hans-Wolfgang Loidl------ modifications by Jost Berthold, 07/2008:--- ported to current GHC = hierarchical libraries--- removed some dead (unused) code--- simplified/secured usage--- included a reference computation (using prime numbers)--- tested best version (JFP_Final) against two "equivalents" using--- strategies---------------------------------------------------------------------------------module Main where--import System.Environment (getArgs)--import Control.Monad.Par--import Control.Monad (when)--import ListAux -- split/join functions, put in new module-import SumEulerPrimes-------------------------------------------------------------------------------- Generic clustering routines---- Classes--- maybe: class (Functor c) => MMonad c where { ... mmap = fmap } -class MMonad c where- munit :: a -> c a- mjoin :: c (c a) -> c a- mmap :: (a -> b) -> c a -> c b--class (MMonad c) => MMonadPlus c where- mzero :: c a- mplus :: c a -> c a -> c a--class (MMonad c) => Cluster c where- cluster :: Int -> c a -> c (c a)- decluster :: c (c a) -> c a- lift :: (c a -> b) -> (c (c a) -> (c b))- -- default defs- --cluster = ???- decluster = mjoin- lift = mmap---- Instances-instance MMonad [] where- munit x = [x]- mjoin = concat- mmap = map--instance Cluster [] where- cluster = splitAtN-------------------------------------------------------------------------------usage :: String-usage = "Usage: <program> version size chunksize"- ++"\nFor versions see source code."--main :: IO ()-main = do args <- getArgs- let - lenArgs = length args- when (lenArgs < 3) - (putStrLn (usage ++ "\n(using defaults: 38,5000,100)"))- let - argDef :: Read a => Int -> a -> a- argDef m defVal | m < lenArgs = read (args!!m)- | otherwise = defVal- x, n, c :: Int- x = argDef 0 38 -- which sumEuler to use- n = argDef 1 5000 -- size of the interval- c = argDef 2 100 -- chunksize- -- parallel computation- (res, _str) = case x of-- _ -> (sumEuler_monadpar c n, "monad-par version")-#if 0- ------------------- -- BEST VERSION:- 38 -> (sumEulerJFP_Final c n, "JFP_Final paper version (splitAtN)")- -- VERSIONS TO TEST ADDITIONALLY:--- 48 -> (sumEulerS8 c n, "parallel w/ parChunkFoldMap strategy")--- 58 -> (sumEulerS8' c n, "parallel w/ parChunkFold'Map strategy") - 8 -> (sumEulerJFP c n, "JFP paper version (splitAtN)")- ------------------- 0 -> (sumEuler_seq n, "sequential")- 1 -> (sumEulerS1 n, "parallel w/ parList strategy")- -- not bad:- 2 -> (sumEulerS2 c n, "parallel w/ parListChunk")- 3 -> (sumEulerChunk c n,"parallel w/ chunkify")- 4 -> (sumEulerShuffle c n,"parallel w/ shuffle")- 5 -> (sumEulerCluster c n,"parallel w/ generic clustering")- -- not bad:- 6 -> (sumEulerS6 c n, "parallel w/ parListChunk over reversed list")--- 7 -> (sumEulerS7 c n, "parallel w/ parChunkFoldMap strategy")- 18 -> (sumEulerJFP1 c n, "JFP1 paper version (splitIntoChunks)")- 28 -> (sumEulerJFP0 c n, "JFP0 paper version (explicit list comprh)")--- 9 -> (sumEulerStepList c n, "parallel w/ seqStepList for strategic shuffling")- _ -> error "undefined version."-#endif-- putStrLn ("sumEuler [" ++ show base ++ ".." ++ show (base+n) ++ "] = " ++ show res)-- -- reference implementation (which is rather fast)- let expected = sumPhi n- when False $ putStrLn ("Expected result: " ++ show expected)-------------------------------------------------------------------------------- main computation function in many variants---- HERE: best versions in contrast--#if 0-sumEulerJFP :: Int -> Int -> Int-sumEulerJFP c n = sum (map (sum . map euler) (splitAtN c (mkList n))- `using` parList rdeepseq) --sumEulerJFP_Final :: Int -> Int -> Int-sumEulerJFP_Final c n = sum ([(sum . map euler) x | x <- splitAtN c [n,n-1..0]]- `using` parList rdeepseq) -#endif--sumEuler_monadpar :: Int -> Int -> Int-sumEuler_monadpar c n = runPar $--- sum `fmap` parMap (sum . map euler) (splitAtN c [n,n-1..0])- sum `fmap` parMap euler [n,n-1..0]----- -- using a fold-of-map strategy w/ folding inside a chunk--- sumEulerS8 :: Int -> Int -> Int--- sumEulerS8 c n = parChunkFoldMap c rnf (+) euler (mkList n)--- --- -- using a fold-of-map strategy w/ STRICT LEFT-folding inside a chunk--- sumEulerS8' :: Int -> Int -> Int--- sumEulerS8' c n = parChunkFoldMap' c rnf (+) euler (mkList n)--- --- -- parallel fold-of-map with chunking over fold and map--- parChunkFoldMap :: (NFData b) => Int -> Strategy b -> --- (b -> b -> b) -> (a -> b) -> [a] -> b--- parChunkFoldMap c s f g xs = foldl1 f (map (foldl1 f . map g) --- (splitAtN c xs)--- `using` parList s) --- --- -- parallel fold-of-map with chunking over fold and map--- parChunkFoldMap' :: (NFData b) => Int -> Strategy b -> --- (b -> b -> b) -> (a -> b) -> [a] -> b--- parChunkFoldMap' c s f g xs = foldl1' f (map (foldl1' f . map g) --- (splitAtN c xs)--- `using` parList s) --#if 0--------------------------------------------------------------------------- OTHER VARIANTS---- strategic function application-sumEulerS1 :: Int -> Int-sumEulerS1 n = sum ( map euler (mkList n)- `using` - parList rdeepseq )---- NUKED:--- sumEulerS1 c n = sum $|| (parListChunk c rnf) $ map euler $ mkList $ n---- naive parallel version w/ parList-sumEulerS2 :: Int -> Int -> Int-sumEulerS2 c n = sum ( map euler (mkList n)- `using` - parListChunk c rdeepseq )---- using a parallel fold over a chunkified list-sumEulerS6 :: Int -> Int -> Int-sumEulerS6 c n = sum (map (sum . map euler) (splitAtN c (mkList n))- `using` parList rdeepseq) ---- -- using a fold-of-map strategy over a chunkified list--- sumEulerS7 :: Int -> Int -> Int--- sumEulerS7 c n = parFoldChunkMap c rnf (+) euler (mkList n)---- explicit restructuring-sumEulerChunk :: Int -> Int -> Int-sumEulerChunk c n = sum (parMap rdeepseq ( \ xs -> sum (map euler xs)) - (splitAtN c (mkList n)))---- using generic clustering functions-sumEulerCluster :: Int -> Int -> Int-sumEulerCluster c n = sum ((lift worker) (cluster c (mkList n)) - `using` parList rdeepseq)- where worker = sum . map euler---- using a shuffling to improve load balance-sumEulerShuffle :: Int -> Int -> Int-sumEulerShuffle c n = sum ((map worker) (unshuffle (noFromSize c n) (mkList n))- `using` parList rdeepseq)- where worker = sum . map euler--noFromSize :: Int -> Int -> Int-noFromSize c n | n `mod` c == 0 = n `div` c - | otherwise = n `div` c + 1---- -- Evaluates every n-th element in the list starting with the first elem--- seqStepList :: Int -> Strategy a -> Strategy [a]--- seqStepList _ _strat [] = ()--- seqStepList n strat (x:xs) = strat x `pseq` (seqStepList n strat (drop (n-1) xs))--- --- seqStepList' :: Int -> Strategy a -> Strategy [a]--- -- seqStepList' _ strat [] = ()--- seqStepList' n strat xs = parList (\ i -> seqStepList n strat (drop i xs)) [0..n-1]--- --- sumEulerStepList :: Int -> Int -> Int--- sumEulerStepList c n = sum ( map euler (mkList n)--- `using` --- seqStepList' n' rnf )--- where --worker = sum . map euler--- n' = if n `mod` c == 0 then n `div` c else (n `div` c)+1---- ------------------------------------------------------------------------------ Variants of the code for the JFP paper--- -----------------------------------------------------------------------------sumEulerJFP0 :: Int -> Int -> Int-sumEulerJFP0 c n = sum ([ (sum . map euler) [ c*i+j | j <- [0..c-1], c*i+j<=n ]- | i <- [0..(n+c-1) `div` c - 1] ]- `using` parList rdeepseq) --sumEulerJFP1 :: Int -> Int -> Int-sumEulerJFP1 c n = sum (map (sum . map euler) (splitIntoChunks c n)- `using` parList rdeepseq) --#endif--splitIntoChunks :: Int -> Int -> [[Int]]-splitIntoChunks c n = [ [ c*i+j | j <- [0..c-1], c*i+j<=n ]- | i <- [0..(n+c-1) `div` c - 1] ]---- boring sequential version-sumEuler_seq :: Int -> Int-sumEuler_seq = sum . map euler . mkList -------------------------------------------------------------------------------- smallest input for euler-base :: Int-base = 0---- produce a list of input values-mkList :: Int -> [Int]-mkList = reverse . enumFromTo base . (+ base)--- random numbers--- mkList seed n = take n (randoms seed)-------------------------------------------------------------------------------- main fct--euler :: Int -> Int-euler n = length (filter (relprime n) [1..(n-1)])-------------------------------------------------------------------------------- orig code from Nathan-{--euler :: Int -> Int-euler n = let- relPrimes = let- numbers = [1..(n-1)]- in- numbers `par` (filter (relprime n) numbers)- in- (spine relPrimes) `par` (length relPrimes)--}-------------------------------------------------------------------------------- aux fcts--hcf :: Int -> Int -> Int-hcf x 0 = x-hcf x y = hcf y (rem x y)--relprime :: Int -> Int -> Bool-relprime x y = hcf x y == 1-
− examples/sumeuler/SumEulerPrimes.hs
@@ -1,36 +0,0 @@-module SumEulerPrimes where--import Data.List--sumPhi n = sum (map phiOpt [1..n])--phiOpt :: Int -> Int-phiOpt 1 = 0-phiOpt n = foldl (*) 1 [ (p-1)*p^(k-1)- | (p,k) <- primefactors n ]---- factorise n to a list of (prime, multiplicity)-primefactors :: Int -> [(Int,Int)]-primefactors n | n <= 1 = []- | otherwise = primeList (primesIn primes n)---- gather identical primes in the list-primeList :: [Int] -> [(Int,Int)]-primeList ps = [ (x, length (filter (==x) ps))- | x <- nub ps ]---- brute-force factorisation, using precomputed prime list-primesIn :: [Int] -> Int -> [Int]-primesIn [] _ = error "no primes left!"-primesIn ps@(p:rest) n | p > n = []- | n `mod` p == 0 = p:primesIn ps (n `div` p)- | otherwise = primesIn rest n---- prime numbers, by sieve of Eratosthenes-primes :: [Int]-primes = sieve [2..]-sieve :: [Int] -> [Int]-sieve [] = []-sieve (x:xs) = x: (sieve (filter (not . multiple) xs))- where multiple y = rem y x == 0-
− examples/timeout.sh
@@ -1,91 +0,0 @@-#!/bin/bash-#-# The Bash shell script executes a command with a time-out.-# Upon time-out expiration SIGTERM (15) is sent to the process. If the signal-# is blocked, then the subsequent SIGKILL (9) terminates it.-#-# Based on the Bash documentation example.--# Hello Chet,-# please find attached a "little easier" :-) to comprehend-# time-out example. If you find it suitable, feel free to include-# anywhere: the very same logic as in the original examples/scripts, a-# little more transparent implementation to my taste.-#-# Dmitry V Golovashkin <Dmitry.Golovashkin@sas.com>--scriptName="${0##*/}"--declare -i DEFAULT_TIMEOUT=9-declare -i DEFAULT_INTERVAL=1-declare -i DEFAULT_DELAY=1--# Timeout.-declare -i timeout=DEFAULT_TIMEOUT-# Interval between checks if the process is still alive.-declare -i interval=DEFAULT_INTERVAL-# Delay between posting the SIGTERM signal and destroying the process by SIGKILL.-declare -i delay=DEFAULT_DELAY--function printUsage() {- cat <<EOF--Synopsis- $scriptName [-t timeout] [-i interval] [-d delay] command- Execute a command with a time-out.- Upon time-out expiration SIGTERM (15) is sent to the process. If SIGTERM- signal is blocked, then the subsequent SIGKILL (9) terminates it.-- -t timeout- Number of seconds to wait for command completion.- Default value: $DEFAULT_TIMEOUT seconds.-- -i interval- Interval between checks if the process is still alive.- Positive integer, default value: $DEFAULT_INTERVAL seconds.-- -d delay- Delay between posting the SIGTERM signal and destroying the- process by SIGKILL. Default value: $DEFAULT_DELAY seconds.--As of today, Bash does not support floating point arithmetic (sleep does),-therefore all delay/time values must be integers.-EOF-}--# Options.-while getopts ":t:i:d:" option; do- case "$option" in- t) timeout=$OPTARG ;;- i) interval=$OPTARG ;;- d) delay=$OPTARG ;;- *) printUsage; exit 1 ;;- esac-done-shift $((OPTIND - 1))--# $# should be at least 1 (the command to execute), however it may be strictly-# greater than 1 if the command itself has options.-if (($# == 0 || interval <= 0)); then- printUsage- exit 1-fi--# kill -0 pid Exit code indicates if a signal may be sent to $pid process.-(- ((t = timeout))-- while ((t > 0)); do- sleep $interval- kill -0 $$ || exit 0- ((t -= interval))- done-- # Be nice, post SIGTERM first.- # The 'exit 0' below will be executed if any preceeding command fails.- kill -s SIGTERM $$ && kill -0 $$ || exit 0- sleep $delay- kill -s SIGKILL $$-) 2> /dev/null &--exec "$@"
monad-par.cabal view
@@ -1,24 +1,49 @@ Name: monad-par-Version: 0.1.0.3+Version: 0.3 Synopsis: A library for parallel programming based on a monad ++-- Version history:+-- 0.1 : First release+-- 0.1.0.1 : +-- 0.1.0.2 : +-- 0.1.1.0 : module reorganization, moving ParClass++-- 0.2 : Bumped for new class-based API+-- 0.2.1 : Bumped for change AList+-- 0.2.2 : incorporation of real deque package+-- 0.2.3 : Restricted module export for 0.2 release.++-- 0.3 : Factored/reorganized modules and packages. +-- *This* package is the original, core monad-par.++ Description: This library offers an alternative parallel programming API to that provided by the @parallel@ package. - The 'Par' monad allows the simple description of+ A 'Par' monad allows the simple description of parallel computations, and can be used to add parallelism to pure Haskell code. The basic API is straightforward: the monad supports forking and simple communication in terms of 'IVar's. - The library comes with an efficient work-stealing+ The library comes with a work-stealing implementation, but the internals are also exposed so that you can build your own scheduler if necessary. + Examples of use can be found in the examples/ directory of the source package. ++ The modules below provide additionaly schedulers,+ data structures, and other added capabilities+ layered on top of the 'Par' monad.++-- * Finish These+-- * Module Descriptions+ Homepage: https://github.com/simonmar/monad-par License: BSD3 License-file: LICENSE@@ -28,66 +53,93 @@ Stability: Experimental Category: Control,Parallelism,Monads Build-type: Simple-Cabal-version: >=1.2+Cabal-version: >=1.8 + extra-source-files:- examples/benchlist.txt- examples/benchmark.sh- examples/blackscholes_data.hs- examples/blackscholes.hs- examples/cholesky.hs- examples/cholesky_matrix6.dat- examples/coins.hs- examples/common.mk- examples/get_cholesky_data.sh- examples/Makefile- examples/mandel.hs- examples/matmult/ListAux.hs- examples/matmult/Makefile- examples/matmult/MatMult.hs- examples/matmult/matmult.stdout- examples/minimax/Board.hs- examples/minimax/Game.hs- examples/minimax/Main.hs- examples/minimax/Makefile- examples/minimax/minimax.stdout- examples/minimax/Prog.hs- examples/minimax/Tree.hs- examples/minimax/Wins.hs- examples/nbody.hs- examples/ntimes- examples/ntimes_minmedmax- examples/parfib.hs- examples/partree/Makefile- examples/partree/partree.hs- examples/partree/Tree.hs- examples/plot_scaling.hs- examples/PortablePixmap.lhs- examples/primes.hs- examples/queens.hs- examples/run_tests.sh- examples/stream/DEVLOG.txt- examples/stream/disjoint_working_sets_pipeline.hs- examples/stream/fft_pipeline.hs- examples/stream/Makefile- examples/stream/simple1_measureSrc.hs- examples/sumeuler/ListAux.hs- examples/sumeuler/Makefile- examples/sumeuler/SumEuler.hs- examples/sumeuler/SumEulerPrimes.hs- examples/timeout.sh tests/AListTest.hs- tests/Test.hs- Control/Monad/Par/Stream.hs+ tests/AllTests.hs+ tests/AsyncTest.hs+ tests/Makefile+ tests/ParTests.hs+ tests/TestHelpers.hs+ tests/TestParDist.hs+ tests/Test_ContReaderT.hs+ tests/Test_ReaderContT.hs+ tests/hs_cassandra_microbench.hs+ tests/hs_cassandra_microbench2.hs Library- Exposed-modules: Control.Monad.Par- , Control.Monad.Par.OpenList- , Control.Monad.Par.AList- , Control.Monad.Par.IList- , Control.Monad.Par.Internal- Build-depends: base >= 4 && < 5,- deepseq >= 1.1 && < 1.4,- HUnit >= 1.2+ Exposed-modules: + -- The classic, simple monad-par interface:+ Control.Monad.Par++ -- This is the default scheduler:+ , Control.Monad.Par.Scheds.Trace+ , Control.Monad.Par.Scheds.TraceInternal++ -- Replacement scheduler for Trace:+ , Control.Monad.Par.Scheds.Direct++ -- This scheduler uses sparks rather than IO threads.+ -- It only supports Futures, not full IVars:+ , Control.Monad.Par.Scheds.Sparks++ Build-depends: base >= 4 && < 5+ -- This provides the interface which monad-par implements:+ , abstract-par + , abstract-deque >= 0.1.4+ -- Extras such as parMap, RNG, State+ , monad-par-extras == 0.3.*+ , deepseq >= 1.1+ , array >= 0.3+ , mwc-random >= 0.11+ , containers+ , parallel >= 3.1+ , mtl >= 2.0.1.0+ ghc-options: -O2 Other-modules:+ ------------------------------------------------------------+ -- Schedulers & Infrastructure --+ ------------------------------------------------------------++ -- Strawman scheduler that forks IO threads:+ -- Control.Monad.Par.Scheds.ContFree,++ -- Internal logging framework:+ -- Control.Monad.Par.Logging,++ -- Serial Elision is currently experimental:+ -- Control.Monad.Par.Scheds.SerialElision++ ------------------------------------------------------------+ -- Data Structures -- + ------------------------------------------------------------++ -- ILists are internal:+ -- , Control.Monad.Par.IList++ -- RRN: Not exposing Streams or OpenLists yet. Need to improve performance.+ -- We have some ideas for enabling bounded chans while preventing deadlock:+ -- , Control.Monad.Par.OpenList+ -- , Control.Monad.Par.Stream+++Test-Suite test-monad-par+ type: exitcode-stdio-1.0+ main-is: tests/AllTests.hs+ ghc-options: -itests -rtsopts -threaded+ build-depends: base >= 4 && < 5+ , abstract-par, monad-par-extras+ , array >= 0.3+ , deepseq >= 1.2+ , time+ , QuickCheck, HUnit+ , test-framework-hunit, test-framework-quickcheck2+ , test-framework, test-framework-th+ -- , binary++++
tests/AListTest.hs view
@@ -1,10 +1,47 @@ -import Control.Monad.Par.AList+module AListTest ( tests ) where +import Test.Framework (defaultMain, testGroup)+import Test.Framework.Providers.HUnit+import Test.Framework.Providers.QuickCheck2 (testProperty)+import Test.HUnit+import Test.QuickCheck++import Control.Monad.Par.AList as A+import Prelude hiding (tail, length, map, filter)+import qualified Prelude as P+++ ----------------------------------------------------------------------------------- Testing+-- QuickCheck properties --- For testing:+prop_tofrom :: [Int] -> Bool +prop_tofrom xs = toList (fromList xs) == xs++prop_tofromB :: [Int] -> Bool +prop_tofromB xs = toList (fromListBalanced xs) == xs++prop_balance :: [Int] -> Bool+prop_balance xs = toList (balance (fromList xs)) == xs++prop_map :: [Int] -> Bool+prop_map ls = map (+1) (fromList ls) == fromList (P.map (+1) ls)++prop_filter :: [Int] -> Bool+prop_filter ls = filter odd (fromList ls) == fromList (P.filter odd ls)++-- | All QuickCheck tests together:+test = mapM_ quickCheck [ prop_tofrom + , prop_tofromB+ , prop_balance+ , prop_map+ , prop_filter+ ]++--------------------------------------------------------------------------------+-- Testing Utils:+ bintree 0 x = x bintree n x = Append sub sub where sub = bintree (n-1) x@@ -14,24 +51,29 @@ showDbg (Append l r) = "("++showDbg l++" | "++showDbg r++")" showDbg (AList l) = show l -alist_tests :: Test-alist_tests = - TestList - [-- 8 ~=? (length$ tail$ tail$ fromList [1..10])- , 1 ~=? (length$ tail$tail$ cons 1$ cons 2$ cons 3 empty)-- , 253 ~=? (length$ tail$tail$tail$ bintree 8 $ singleton 'a')- , 0 ~=? (length$ bintree 8 $ empty)+-------------------------------------------------------------------------------- - , "((1 | 1) | (1 | 1))" ~=? (showDbg$ bintree 2 $ singleton 1)- , "((_ | 1) | (1 | 1))" ~=? (showDbg$ tail$ bintree 2 $ singleton 1)- , "(_ | (1 | 1))" ~=? (showDbg$ tail$tail$ bintree 2 $ singleton 1)+tests = [+ -- testGroup "AList HUnit Tests" (hUnitTestToTests alist_tests), - ]+ testGroup "AList HUnit Tests" [+ testCase "fromList1" $ 8 @=? (length$ tail$ tail$ fromList [1..10])+ , testCase "cons X3" $ 1 @=? (length$ tail$tail$ cons 1$ cons 2$ cons 3 empty)+ , testCase "tail X3" $ 253 @=? (length$ tail$tail$tail$ bintree 8 $ singleton 'a')+ , testCase "len bintree"$ 0 @=? (length$ bintree 8 $ empty) -t = runTestTT alist_tests+ , testCase "inspect tree1"$ "((1 | 1) | (1 | 1))" @=? (showDbg$ bintree 2 $ singleton 1)+ , testCase "inspect tree2"$ "((_ | 1) | (1 | 1))" @=? (showDbg$ tail$ bintree 2 $ singleton 1)+ , testCase "inspect tree3"$ "(_ | (1 | 1))" @=? (showDbg$ tail$tail$ bintree 2 $ singleton 1)+ ], + testGroup "AList QuickCheck Tests " [+ testProperty "map" prop_map+ , testProperty "filter" prop_filter+ , testProperty "tofrom" prop_tofrom+ , testProperty "tofromB" prop_tofromB+ , testProperty "balance" prop_balance+ ]+ ] --- TODO: Quickcheck.+-- main = defaultMain tests
+ tests/AllTests.hs view
@@ -0,0 +1,18 @@++-- | Combine individual test modules into a single module.++module Main where ++import Test.Framework (defaultMain, testGroup)+import qualified AListTest +import qualified ParTests+import qualified AsyncTest++main = defaultMain $ concat $ + [ AListTest.tests+ , ParTests.tests+-- Not working right now:+-- , AsyncTests.tests+ ]++-- main = AsyncTests.manual_main
+ tests/AsyncTest.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE TemplateHaskell #-}++module AsyncTest (tests, manual_main) where++import Control.Exception +import Control.Monad.Par.Scheds.Trace+import Control.Monad.Par.Scheds.TraceInternal (Par(..),Trace(Fork),runCont,runParAsync)+import Test.Framework.TH (testGroupGenerator)+import Test.Framework (defaultMain, testGroup)+import Test.Framework.Providers.HUnit++import TestHelpers++--------------------------------------------------------------------------------++-- A D E or A D B E but no C+--+-- ODD -- this passes when run manually (compiled or interpreted) but+-- fails when run through the test framework [2011.10.25].+case_async_test2 = + do x <- async2+ case words x of + ["A","D","E"] -> return ()+ ["A","D","B","E"] -> return ()+ _ -> error$ "async_test2: Bad output: "++ show (words x)++async2 = collectOutput $ \ r -> do + prnt r "A"+ evaluate$ runParAsync $+ do + fork $ do _prnt r "B"+ x <- _unsafeio$ waste_time 0.5+ _prnt r$ "C "++ show x+-- _prnt r$ "C "++ show (_waste_time awhile)+ _prnt r "D"+ prnt r "E"++--------------------------------------------------------------------------------++tests = [ $(testGroupGenerator) ]++-- It works fine when run like this:+manual_main = do x <- async2; putStrLn x+ case_async_test2+-- case_async_test1
+ tests/Makefile view
@@ -0,0 +1,32 @@++# NOTE!! THIS IS REDUNDANT WITH THE CABAL TEST-SUITE IN monad-par.cabal+#+# This is simply an alternative way to run the tests.+++# These are HUnit/QuickCheck tests, factored out of their respective files:+SRC = ParTests.hs AListTest.hs AsyncTests.hs TestHelpers.hs Makefile+TESTS= AllTests.hs+EXES= $(TESTS:.hs=.exe)++all: $(EXES) test++.SUFFIXES: .hs .exe++.hs.exe: $< $(SRC)+ ghc -i.. --make $< -o $@ -rtsopts -threaded++deps:+ cabal install QuickCheck HUnit test-framework test-framework-hunit test-framework-quickcheck2 test-framework-th++test:+ @echo+ @echo "Running tests:"+ @echo "=================================="+ ./AllTests.exe +RTS -N2+# "for t in $(EXES); do $t; done"+# ./ParTests.exe+# ./AListTest.exe++clean:+ rm -f *.hi *.exe *.o
+ tests/ParTests.hs view
@@ -0,0 +1,119 @@+{-# LANGUAGE TemplateHaskell, BangPatterns #-}++module ParTests (tests) where++import Control.Monad.Par.Combinator ++import Control.Monad.Par.Scheds.Trace+import Control.Monad.Par.Scheds.TraceInternal (Par(..),Trace(Fork),runCont,runParAsync)++-- import Control.Monad.Par.Scheds.Direct++import Control.Concurrent.Chan+import Control.Exception +import System.IO.Unsafe+import Data.IORef+import Test.HUnit+import Test.Framework.TH (testGroupGenerator)+import Test.Framework (defaultMain, testGroup)+import Test.Framework.Providers.HUnit+-- import Test.Framework.Providers.QuickCheck2 (testProperty)+import System.Timeout++import TestHelpers++-- -----------------------------------------------------------------------------++-- Testing++three = (3::Int)+par res m = res @=? runPar m++case_justReturn = par three (return 3)+case_oneIVar = par three (do r <- new; put r 3; get r)+++-- [2012.01.02] Apparently observing divergences here too:+case_forkNFill = par three (do r <- new; fork (put r 3); get r)++-- [2012.05.02] The nested Trace implementation sometimes fails to+-- throw this exception, so we expect either the exception or a+-- timeout. This is reasonable since we might expect a deadlock in a+-- non-Trace scheduler. --ACF+case_getEmpty = do+ _ <- timeout 100000 $ assertException "no result" $ + runPar $ do r <- new; get r+ return ()+++-- [2012.01.02] Observed a blocked-indef-on-MVar failure here on+-- master branch with 16 threads:+-- +-- | Simple diamond test.+case_test_diamond = 9 @=? (m :: Int)+ where + m = runPar $ do+ [a,b,c,d] <- sequence [new,new,new,new]+ fork $ do x <- get a; put b (x+1)+ fork $ do x <- get a; put c (x+2)+ fork $ do x <- get b; y <- get c; put d (x+y)+ fork $ do put a 3+ get d++-- | Violate IVar single-assignment:+--+-- NOTE: presently observing termination problems here.+-- runPar is failing to exist after the exception?+disabled_case_multiput = assertException "multiple put" $ + runPar $ do+ a <- new+ put a (3::Int)+ put a (4::Int)+ return ()+++-- disabled_test3 = assertException "multiple put" $ +-- runPar $ do+-- a <- new+-- put a (3::Int)+-- both (return 1) (return 2)+-- where +-- -- both a b >> c == both (a >> c) (b >> c)+-- -- Duplicate the continuation: is this useful for anything?+-- both :: Par a -> Par a -> Par a+-- both a b = Par $ \c -> Fork (runCont a c) (runCont b c)++case_test_pmrr1 = + par 5050 $ parMapReduceRangeThresh 1 (InclusiveRange 1 100)+ (return) (return `bincomp` (+)) 0+ where bincomp unary bin a b = unary (bin a b)+++------------------------------------------------------------++-- Observe the real time ordering of events:++-- A D B <pause> C E +case_async_test1 = + do x <- res+ case words x of + ["A","D","B","C",_,"E"] -> return ()+ _ -> error$ "Bad output: "++ show (words x)+ where + res = collectOutput $ \ r -> do+ prnt r "A"+ evaluate$ runPar $+ do + fork $ do _prnt r "B"+ x <- _unsafeio$ waste_time 0.5+ _prnt r$ "C "++ show x+-- _prnt r$ "C "++ show (_waste_time awhile)+ _prnt r "D"+ prnt r$ "E"++++------------------------------------------------------------++tests = [ $(testGroupGenerator) ]+
− tests/Test.hs
@@ -1,74 +0,0 @@-module Main where--import Test.HUnit---- --------------------------------------------------------------------------------- Testing--_test :: IO ()-_test = do- print ((runPar $ return 3) :: Int)- print (runPar $ do r <- new; put r (3 :: Int); get r)- print (runPar $ do r <- new; fork (put r (3::Int)); get r)- print ((runPar $ do r <- new; get r) :: Int)--_test2 :: Int-_test2 = runPar $ do- [a,b,c,d] <- sequence [new,new,new,new]- fork $ do x <- get a; put b (x+1)- fork $ do x <- get a; put c (x+2)- fork $ do x <- get b; y <- get c; put d (x+y)- fork $ do put a 3- get d--_test3 :: Int-_test3 = runPar $ do- a <- new- put a (3::Int)- both (return 1) (return 2)---- is there a standard lib thing for this?--_test_pmrr1 :: Int-_test_pmrr1 = runPar$ parMapReduceRangeThresh 1 (InclusiveRange 1 100) - (return) (return `bincomp` (+)) 0- where bincomp unary bin a b = unary (bin a b)--_unsafeio :: IO a -> Par a-_unsafeio io = let x = unsafePerformIO io in- x `seq` return x--_print :: String -> Par ()-_print = _unsafeio . putStrLn--_waste_time :: Int -> Double-_waste_time n = loop n 1.00111- where - loop 0 !x = x- loop !n !x | x > 100.0 = loop (n-1) (x / 2)- loop !n !x = loop (n-1) (x + x * 0.5011)---_async_test1 = do -- A D B <pause> C E - putStrLn "A"- evaluate$ runPar $- do - fork $ do _print "B"- _print$ "C "++ show (_waste_time 300000000)- _print "D"- putStrLn$ "E"--_async_test2 = do -- A D E or A D B E but no C- putStrLn "A"- evaluate$ runParAsync $- do - fork $ do _print "B"- _print$ "C "++ show (_waste_time 300000000)- _print "D"- putStrLn$ "E"----- TODO: add the async_tests above to the test list.-_par_tests :: Test-_par_tests = TestList []
+ tests/TestHelpers.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE BangPatterns #-}++module TestHelpers where++import Data.List+import Prelude hiding (catch)+import Control.Exception +import System.IO.Unsafe (unsafePerformIO)+import Data.IORef+import Data.Time.Clock++-- import Control.Monad.Par.Unsafe+import Control.Monad.Par.Scheds.Trace+import Control.Monad.Par.Scheds.TraceInternal (Par(..),Trace(Fork),runCont,runParAsync)++------------------------------------------------------------+-- Helpers++_unsafeio :: IO a -> Par a+_unsafeio io = let x = unsafePerformIO io in+ x `seq` return x++_waste_time :: Int -> Double+_waste_time n = loop n 1.00111+ where + loop 0 !x = x+ loop !n !x | x > 100.0 = loop (n-1) (x / 2)+ loop !n !x = loop (n-1) (x + x * 0.5011)++-- This version watches the clock so it uses a constant amount of time+-- regadless of compile/interpret mode an opt lvl.+waste_time :: Double -> IO Double+waste_time seconds = + do strt <- getCurrentTime+ let loop !x | x > 100.0 = chk (x / 2)+ loop !x = chk (x + x * 0.5011)+ chk !x = do t <- getCurrentTime+ if diffUTCTime t strt >= realToFrac seconds+ then return x+ else loop x+ loop 1.00111++-- Obviously this takes a lot longer if it's interpreted:+--awhile = 300000000+awhile = 3 * 1000 * 1000+-- awhile = 300000++atomicModifyIORef_ rf fn = atomicModifyIORef rf (\x -> (fn x, ()))+++-- Haskell doesn't offer a way to create a Handle for in-memory output.+-- So here we use IORefs instead+collectOutput :: (IORef [String] -> IO ()) -> IO String+collectOutput fn = + do c <- newIORef []+ fn c+ ls <- readIORef c+ return (unlines (reverse ls))++prnt :: IORef [String] -> String -> IO ()+prnt ref str = atomicModifyIORef_ ref (str:)++_prnt :: IORef [String] -> String -> Par ()+_prnt ref = _unsafeio . prnt ref+ +++-- -----------------------------------------------------------------------------++-- assertException :: (Exception e, Eq e) => e -> IO a -> IO ()+-- assertException ex action =+-- handleJust isWanted (const $ return ()) $ do+-- action+-- assertFailure $ "Expected exception: " ++ show ex+-- where isWanted = guard . (== ex)++-- Ensure that evaluating an expression returns an exception+assertException :: String -> a -> IO ()+assertException msg val = do+ x <- catch (do evaluate val; return Nothing) + (\e -> do putStrLn$ "Good. Caught exception: " ++ show (e :: SomeException)+ return (Just$ show e))+ case x of + Nothing -> error "Failed to get an exception!"+ Just s -> + if isInfixOf msg s + then return () + else error$ "Got the wrong exception, expected to see the text: "++ show msg + ++ "\nInstead got this exception:\n " ++ show s+
+ tests/TestParDist.hs view
@@ -0,0 +1,115 @@+{-# LANGUAGE TemplateHaskell, DeriveDataTypeable #-}+{-# OPTIONS_GHC -O2 -ddump-splices #-}++-- Simple tests of distributed work stealing.+----------------------------------------------++import System.Environment (getArgs)+import qualified Control.Monad.Par.Meta.Dist as D++import Control.Monad.IO.Class (liftIO)+import Control.Monad (mapM_)+-- Tweaked version of CloudHaskell's closures:+import Remote2.Call (mkClosureRec, remotable)++import Control.Concurrent (myThreadId, threadDelay)+import System.Process (readProcess)+import System.Posix.Process (getProcessID)+import Data.Char (isSpace)+import Data.Typeable+import Data.Binary ++import qualified Data.ByteString.Char8 as BS++-- import qualified Data.IntMap as M+-- import qualified Data.Set as M+--------------------------------------------------------------------------------+++-- A description of a fake work topology which is executed by sleeping+-- (threadDelay) different amounts at different points.+-- Presently this describes futures-only work:+data FakeWork = Work Time FakeWork+ | Fork FakeWork FakeWork+ | SyncAll FakeWork+ | Nop++-- | Spawn Id FakeWork FakeWork+-- | Seq [FakeWork]+-- | Sync Id FakeWork+ deriving (Eq,Show,Read,Typeable)+-- All constructors take a continuation. ++type Time = Int -- Time in milliseconds+type Id = Int++-- A simple test that ensures a single steal for two workers:+-- t1 = Spawn 11 (Work 101) $ +-- Seq [Work 102, +-- Sync 11]+ +t1 = Fork (Work 101 Nop) $ + Work 102 $ + SyncAll Nop++t2 = switcher 3 3 True++-- This one alternates where the *real* work will be.+--+-- Takes number of switches. Performs a shrinking number of work+-- items per "straightaway":+switcher 1 m _ = Work 100 (SyncAll Nop)+switcher _ _ False = Work 101 (SyncAll Nop)+switcher n m True = Work 102 $ switcher n (m-1) True+switcher n 1 b = Fork (switcher (n-1) n b) + (switcher (n-1) n (not b))++----------------------------------------------------------------------------------------------------++runTest :: FakeWork -> D.Par ()+--runTest fw = theloop fw M.empty+runTest fw = theloop fw []++theloop fw ls =+ case fw of + Nop -> return ()+ Work t cont -> + do liftIO$ threadDelay (t * 1000)+ liftIO$ putStrLn$ "Finished work "++show t+ theloop cont ls+-- Seq ls -> mapM_ theloop ls+-- Spawn id fw cont -> + Fork child cont -> + do + iv <- D.longSpawn$ $(mkClosureRec 'runTest) child+ -- Associate id with ivar+-- theloop cont (M.insert id iv mp)+ theloop cont (iv:ls)+ SyncAll cont -> + do mapM_ D.get ls+ theloop cont []++-- Generate stub code for RPC:+remotable ['runTest]++-- instance Serialize FakeWork where ++instance Binary FakeWork where + put fw = put (show fw)+-- get str = return (read (BS.unpack str))+ get = get >>= return . read+++----------------------------------------------------------------------------------------------------++main = do + [version] <- getArgs+ case version of + "slave" -> D.runParSlaveWithTransport [__remoteCallMetaData] D.TCP+ "master" -> do + D.runParDistWithTransport [__remoteCallMetaData] D.TCP (runTest t1)+ putStrLn $ "Finished with work. Calling SHUTDOWN..."+ D.shutdownDist+ putStrLn $ "... returned from shutdown, apparently successful."++ str -> error$"Unhandled mode: " ++ str
+ tests/Test_ContReaderT.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE CPP, ScopedTypeVariables #-}++-- If we instead commute the monad transformers we can change the+-- reader value observed by a continuation.++import Control.Monad.Cont as C+import qualified Control.Monad.Reader as R+import Data.IORef+import Text.Printf++type M a = C.ContT () (R.ReaderT Int IO) a++test ref = do + x <- R.ask + liftIO$ printf "Observed value %d before callCC\n" x + callCC$ \cont -> do+ liftIO$ writeIORef ref cont+ liftIO$ printf "Write ioref inside callcc...\n" + z <- R.ask + liftIO$ printf "Observed value %d in invoked continuation\n" z+ return ()++main = do ref :: IORef (() -> M ()) <- newIORef (error "should not be used")+ let m0 = test ref+ m1 = C.runContT m0 (\ () -> return ())+ m2 = R.runReaderT m1 (100::Int)+ m2 ++ k <- readIORef ref+ let m3 = do + w <- lift$ R.ask + liftIO$ putStrLn ("In new runReader instance: observed " ++ show w)+ k ()+ liftIO$ putStrLn " !! Should not reach here..."++ R.runReaderT (C.runContT m3 (\ () -> return ())) 200+ putStrLn "Done with main."
+ tests/Test_ReaderContT.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE CPP #-}+++import Control.Monad.Cont as C+import qualified Control.Monad.Reader as R+import Data.IORef+import Text.Printf++type M a = R.ReaderT Int ContIO a+type ContIO = C.ContT () IO++test ref = do + x <- R.ask + liftIO$ printf "Observed value %d before callCC\n" x + callCC$ \cont -> do+ y <- R.ask + liftIO$ writeIORef ref cont+ liftIO$ printf "Observed value %d inside callCC\n" y+ z <- R.ask + liftIO$ printf "Observed value %d in invoked continuation\n" z+ return ()++main = do ref <- newIORef (error "unused")+ let test' = do test ref+ m1 = do R.runReaderT test' (100::Int)++ C.runContT m1 (\ () -> return ())+ k <- readIORef ref+ let m2 = do w <- R.ask + liftIO$ putStrLn (" In new runReader instance: observed " ++ show w)+ k ()+ liftIO$ putStrLn " !! Should not reach here..."++ C.runContT (R.runReaderT m2 200) (\ () -> return ())+ putStrLn "Done with main."
+ tests/hs_cassandra_microbench.hs view
@@ -0,0 +1,88 @@++-- Peculiar:+-- * Requires hscassandra 0.0.8, available on github only++-- Functions to:+-- * Connect to a cassandra nosql server+-- * Put a bytestring+-- * Get a bytestring++-- This file acts as a microbench for insertion or retrieval of keys++import Database.Cassandra+import Database.Cassandra.Types+import qualified Data.ByteString.Lazy.Char8 as BS+import qualified Database.Cassandra.Thrift.Cassandra_Types as CT+import Data.Either.Utils+import qualified Data.List as L+import System.Time+import Data.Time.Clock+import System.Environment+import Control.Monad+import qualified Data.Set as S+++config = CassandraConfig { cassandraKeyspace = "Test2"+ , cassandraConsistencyLevel = ONE+ , cassandraHostname = "127.0.0.1"+ , cassandraPort = 9160+ , cassandraUsername = ""+ , cassandraPassword = ""+ }++pack :: [Char] -> BS.ByteString+pack string = BS.pack string+ +deColumnValue :: Column -> BS.ByteString+deColumnValue (Column _ value _) = value+ +fetchValue string = runCassandraT config $ do+ res <- get "Users" (pack string) AllColumns+ return $ deColumnValue $ head $ res++insertValue string byteString = runCassandraT config $ do+ insert "Users" (pack string) [ (pack "name") =: byteString ]+ +removeValue string = runCassandraT config $ do+ remove "Users" (pack string) (ColNames [ (pack "name") ])++main = do+ + --input <- readFile "/usr/share/dict/words"+ --let words = tail $ lines input+ let words = map (\n -> (show n) ++ "Thequickbrownfoxjumpedoverthelazydog") $ take 5000 [1..]+ + + putStrLn "Benchmarking Cassandra bindings by writing in every dictionary file word as a k,v pair."+ + putStrLn "About to start timing writes..."+ + writeStart <- getCurrentTime+ mapM_ (\w -> insertValue w (pack w)) words+ writeStop <- getCurrentTime+ + let writeTime = diffUTCTime writeStop writeStart+ + putStrLn ("Writes took " ++ (show $ writeTime))+ + putStrLn "Starting reads..."+ + readStart <- getCurrentTime+ mapM_ (\w -> fetchValue w) words+ let pairs = length words+ readStop <- getCurrentTime+ + let readTime = diffUTCTime readStop readStart+ + putStrLn ("Reads took " ++ (show $ readTime))+ + let totalTime = diffUTCTime readStop writeStart+ + putStrLn ("Total time: " ++ (show $ totalTime))+ + putStrLn "Removing keys..."+ + mapM_ (\w -> removeValue w) words+ + +
+ tests/hs_cassandra_microbench2.hs view
@@ -0,0 +1,91 @@++-- Peculiar:+-- * Requires hscassandra 0.0.8, available on github only++-- Functions to:+-- * Connect to a cassandra nosql server+-- * Put a bytestring+-- * Get a bytestring++-- This file acts as a microbench for insertion or retrieval of keys++import Database.Cassandra+import Database.Cassandra.Types+import qualified Data.ByteString.Lazy.Char8 as BS+import qualified Database.Cassandra.Thrift.Cassandra_Types as CT+import Data.Either.Utils+import qualified Data.List as L+import System.Time+import Data.Time.Clock+import System.Environment+import Control.Monad+import qualified Data.Set as S+++config = CassandraConfig { cassandraKeyspace = "Test2"+ , cassandraConsistencyLevel = ONE+ , cassandraHostname = "127.0.0.1"+ , cassandraPort = 9160+ , cassandraUsername = ""+ , cassandraPassword = ""+ }++pack :: [Char] -> BS.ByteString+pack string = BS.pack string+ +deColumnValue :: Column -> BS.ByteString+deColumnValue (Column _ value _) = value+ +fetchValue string = runCassandraT config $ do+ res <- get "Users" (pack string) AllColumns+ return $ deColumnValue $ head $ res++insertValue string byteString = runCassandraT config $ do+ insert "Users" (pack string) [ (pack "name") =: byteString ]+ +removeValue string = runCassandraT config $ do+ remove "Users" (pack string) (ColNames [ (pack "name") ])++main = do+ + let words = map (\n -> (show n) ++ "Thequickbrownfoxjumpedoverthelazydog") $ take 50000 [1..]+ + putStrLn "Benchmarking Cassandra binding."+ + putStrLn "About to start timing writes..."+ + writeStart <- getCurrentTime+ + runCassandraT config $ do+ mapM_ (\w -> insert "Users" (pack w) [(pack "name") =: (pack w) ]) words+ + writeStop <- getCurrentTime+ + let writeTime = diffUTCTime writeStop writeStart+ + putStrLn ("Writes took " ++ (show $ writeTime))+ + putStrLn "Starting reads..."+ + readStart <- getCurrentTime+ + runCassandraT config $ do+ mapM_ (\w -> get "Users" (pack w) AllColumns) words++ readStop <- getCurrentTime+ + let readTime = diffUTCTime readStop readStart+ + putStrLn ("Reads took " ++ (show $ readTime))+ + let totalTime = diffUTCTime readStop writeStart+ + putStrLn ("Total time: " ++ (show $ totalTime))+ + putStrLn "Removing keys..."+ + runCassandraT config $ do+ mapM_ (\w -> remove "Users" (pack w) (ColNames [ (pack "name") ])) words+ + +