From: Simon Marlow Date: Fri, 24 Oct 2008 12:02:36 +0000 (+0000) Subject: Document the new SPARKS statistic, and xref from the parallelism section X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=commitdiff_plain;h=816b587f0057113ce9667f1f643d828d7abe2079 Document the new SPARKS statistic, and xref from the parallelism section --- diff --git a/docs/users_guide/parallel.xml b/docs/users_guide/parallel.xml index 76d38dc..37cafd2 100644 --- a/docs/users_guide/parallel.xml +++ b/docs/users_guide/parallel.xml @@ -114,10 +114,10 @@ All these features are described in the papers mentioned earlier. infixr 0 `par` -infixr 1 `seq` +infixr 1 `pseq` -par :: a -> b -> b -seq :: a -> b -> b +par :: a -> b -> b +pseq :: a -> b -> b The expression (x `par` y) sparks the evaluation of x @@ -136,24 +136,35 @@ import Control.Parallel nfib :: Int -> Int nfib n | n <= 1 = 1 - | otherwise = par n1 (seq n2 (n1 + n2 + 1)) + | otherwise = par n1 (pseq n2 (n1 + n2 + 1)) where n1 = nfib (n-1) n2 = nfib (n-2) For values of n greater than 1, we use par to spark a thread to evaluate nfib (n-1), - and then we use seq to force the + and then we use pseq to force the parent thread to evaluate nfib (n-2) before going on to add together these two subexpressions. In this divide-and-conquer approach, we only spark a new thread for one branch of the computation (leaving the parent to evaluate the other branch). Also, we must use - seq to ensure that the parent will evaluate + pseq to ensure that the parent will evaluate n2 before n1 in the expression (n1 + n2 + 1). It is not sufficient to reorder the expression as (n2 + n1 + 1), because the compiler may not generate code to evaluate the addends from left to right. + + Note that we use pseq rather + than seq. The two are almost equivalent, but + differ in their runtime behaviour in a subtle + way: seq can evaluate its arguments in either + order, but pseq is required to evaluate its + first argument before its second, which makes it more suitable + for controlling the evaluation order in conjunction + with par. + + When using par, the general rule of thumb is that the sparked computation should be required at a later time, but not too soon. Also, the sparked computation should not be too small, otherwise @@ -161,6 +172,10 @@ nfib n | n <= 1 = 1 amount of parallelism gained. Getting these factors right is tricky in practice. + It is possible to glean a little information about how + well par is working from the runtime + statistics; see . + More sophisticated combinators for expressing parallelism are available from the Control.Parallel.Strategies module. diff --git a/docs/users_guide/runtime_control.xml b/docs/users_guide/runtime_control.xml index 8a7bafd..5039526 100644 --- a/docs/users_guide/runtime_control.xml +++ b/docs/users_guide/runtime_control.xml @@ -531,6 +531,8 @@ Generation 0: 67 collections, 0 parallel, 0.04s, 0.03s elapsed Generation 1: 2 collections, 0 parallel, 0.03s, 0.04s elapsed + SPARKS: 359207 (557 converted, 149591 pruned) + INIT time 0.00s ( 0.00s elapsed) MUT time 0.01s ( 0.02s elapsed) GC time 0.07s ( 0.07s elapsed) @@ -589,6 +591,17 @@ + The SPARKS statistic refers to the + use of Control.Parallel.par and related + functionality in the program. Each spark represents a call + to par; a spark is "converted" when it is + executed in parallel; and a spark is "pruned" when it is + found to be already evaluated and is discarded from the pool + by the garbage collector. Any remaining sparks are + discarded at the end of execution, so "converted" plus + "pruned" does not necessarily add up to the total. + + Next there is the CPU time and wall clock time elapsedm broken down by what the runtiem system was doing at the time.