Commit 816b587f authored by Simon Marlow's avatar Simon Marlow
Browse files

Document the new SPARKS statistic, and xref from the parallelism section

parent b7ea7671
......@@ -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 -&#62; b -&#62; b
seq :: a -&#62; b -&#62; b</programlisting>
par :: a -&#62; b -&#62; b
pseq :: a -&#62; b -&#62; b</programlisting>
<para>The expression <literal>(x `par` y)</literal>
<emphasis>sparks</emphasis> the evaluation of <literal>x</literal>
......@@ -136,24 +136,35 @@ import Control.Parallel
nfib :: Int -&#62; Int
nfib n | n &#60;= 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)</programlisting>
<para>For values of <varname>n</varname> greater than 1, we use
<function>par</function> to spark a thread to evaluate <literal>nfib (n-1)</literal>,
and then we use <function>seq</function> to force the
and then we use <function>pseq</function> to force the
parent thread to evaluate <literal>nfib (n-2)</literal> 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
<function>seq</function> to ensure that the parent will evaluate
<function>pseq</function> to ensure that the parent will evaluate
<varname>n2</varname> <emphasis>before</emphasis> <varname>n1</varname>
in the expression <literal>(n1 + n2 + 1)</literal>. It is not sufficient
to reorder the expression as <literal>(n2 + n1 + 1)</literal>, because
the compiler may not generate code to evaluate the addends from left to
Note that we use <literal>pseq</literal> rather
than <literal>seq</literal>. The two are almost equivalent, but
differ in their runtime behaviour in a subtle
way: <literal>seq</literal> can evaluate its arguments in either
order, but <literal>pseq</literal> is required to evaluate its
first argument before its second, which makes it more suitable
for controlling the evaluation order in conjunction
with <literal>par</literal>.
<para>When using <literal>par</literal>, 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 &#60;= 1 = 1
amount of parallelism gained. Getting these factors right is tricky in
<para>It is possible to glean a little information about how
well <literal>par</literal> is working from the runtime
statistics; see <xref linkend="rts-options-gc" />.</para>
<para>More sophisticated combinators for expressing parallelism are
available from the <ulink
url="../libraries/parallel/Control-Parallel-Strategies.html"><literal>Control.Parallel.Strategies</literal></ulink> module.
......@@ -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)
......@@ -588,6 +590,17 @@
that generation.
<para>The <literal>SPARKS</literal> statistic refers to the
use of <literal>Control.Parallel.par</literal> and related
functionality in the program. Each spark represents a call
to <literal>par</literal>; 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.</para>
Next there is the CPU time and wall clock time elapsedm broken
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment