Difference between revisions of "GHC/Data Parallel Haskell"

From HaskellWiki
< GHC
Jump to navigation Jump to search
Line 30: Line 30:
 
You can use this module in an interactive GHCi session as follows:
 
You can use this module in an interactive GHCi session as follows:
   
  +
<blockquote><pre>
<haskell>
 
> :set -fparr -fglasgow-exts
+
Prelude> :set -fparr -fglasgow-exts
> :load DotP
+
Prelude> :load DotP
 
[1 of 1] Compiling DotP ( code/haskell/DotP.hs, interpreted )
 
[1 of 1] Compiling DotP ( code/haskell/DotP.hs, interpreted )
 
Ok, modules loaded: DotP.
 
Ok, modules loaded: DotP.
Line 38: Line 38:
 
32
 
32
 
*DotP>
 
*DotP>
  +
</pre></blockquote>
</haskell>
 
 
(NB: The <tt>:set</tt> is needed despite the <tt>OPTIONS</tt> pragma in <tt>DotP.hs</tt>, so that you can use array syntax on the interactive command line of GHCi.)
 
(NB: The <tt>:set</tt> is needed despite the <tt>OPTIONS</tt> pragma in <tt>DotP.hs</tt>, so that you can use array syntax on the interactive command line of GHCi.)
   
Line 46: Line 46:
   
 
The concurrent, high-performance library of strict, segmented arrays mentioned above takes the form of a GHC package called [http://darcs.haskell.org/packages/ndp/ ''ndp'']. This package is under development and only available in source form. The simplest way to build it is to first '''get''' and '''build''' a source distribution of GHC (preferably the [http://darcs.haskell.org/ghc/ current development version]) - see the docu on [http://hackage.haskell.org/trac/ghc/wiki/Building/GettingTheSources how to get the sources] and [http://hackage.haskell.org/trac/ghc/wiki/Building/Hacking how to build them]. Then, in the source tree, do the following
 
The concurrent, high-performance library of strict, segmented arrays mentioned above takes the form of a GHC package called [http://darcs.haskell.org/packages/ndp/ ''ndp'']. This package is under development and only available in source form. The simplest way to build it is to first '''get''' and '''build''' a source distribution of GHC (preferably the [http://darcs.haskell.org/ghc/ current development version]) - see the docu on [http://hackage.haskell.org/trac/ghc/wiki/Building/GettingTheSources how to get the sources] and [http://hackage.haskell.org/trac/ghc/wiki/Building/Hacking how to build them]. Then, in the source tree, do the following
<pre>
+
<blockquote><pre>
% cd libraries
+
% cd libraries
% darcs get http://darcs.haskell.org/packages/ndp/
+
% darcs get http://darcs.haskell.org/packages/ndp/
% cd ndp
+
% cd ndp
% make boot
+
% make boot
% make
+
% make
</pre>
+
</pre></blockquote>
 
Now, the option <tt>-package ndp</tt> is available for use with the inplace compiler (i.e., <tt>compiler/ghc-inplace</tt>). Alternatively, you can install it by invoking <tt>make install</tt> on the GHC source root '''and''' within <tt>libraries/ndp/</tt>. Then, the option <tt>-package ndp</tt> can be used in the installed compiler.
 
Now, the option <tt>-package ndp</tt> is available for use with the inplace compiler (i.e., <tt>compiler/ghc-inplace</tt>). Alternatively, you can install it by invoking <tt>make install</tt> on the GHC source root '''and''' within <tt>libraries/ndp/</tt>. Then, the option <tt>-package ndp</tt> can be used in the installed compiler.
  +
  +
For example, the following module implements the dot product with package ndp:
  +
 
<haskell>
  +
module DotP_ndp (dotp)
  +
where
  +
  +
import Data.Array.Parallel.Unlifted
  +
  +
dotp :: (Num a, UA a) => UArr a -> UArr a -> a
  +
dotp xs ys = sumU (zipWithU (*) xs ys)
 
</haskell>
  +
  +
We can also use that in an interactive GHCi session:
  +
  +
<blockquote><pre>
  +
Prelude> :set -package ndp
  +
package flags have changed, ressetting and loading new packages...
  +
Loading package ndp-1.0 ... linking ... done.
  +
Prelude> :l /home/chak/code/haskell/DotP_ndp
  +
[1 of 1] Compiling DotP_ndp ( /home/chak/code/haskell/DotP_ndp.hs, interpreted )
  +
Ok, modules loaded: DotP_ndp.
  +
*DotP_ndp> dotp (toU [1..3]) (toU [4..6])
  +
Loading package haskell98 ... linking ... done.
  +
32.0
  +
*DotP_ndp>
  +
</pre></blockquote>
  +
  +
The difference between the package ndp and the <tt>-fparr</tt> version of the dot product is just a fairly small amount of sugar. However, for programs using arrays of more complex (including nested arrays), the difference is much bigger. Nevertheless, many programs can be implemented quite easily with just package ndp. The speed difference between the two options is dramatic.

Revision as of 23:44, 16 October 2006

Data Parallel Haskell

Data Parallel Haskell is the codename for an extension to the Glasgow Haskell Compiler and its libraries to support nested data parallelism with a focus to utilise multi-core CPUs. Nested data parallelism extends the programming model of flat data parallelism, as known from parallel Fortran dialects, to irregular parallel computations (such as divide-and-conquer algorithms) and irregular data structures (such as sparse matrices and tree structures). An introduction to nested data parallelism in Haskell, including some examples, can be found in the paper Nepal -- Nested Data-Parallelism in Haskell.

Data Parallel Haskell is very much work in progress. Some components are already usable, and the rest of this page describes how to use them. However, please be aware that APIs are still in flux and some functionality may be broken at times during development.

Implementation of nested data parallelism in two stages

As Data Parallel Haskell is not fully implemented at this stage, use of the existing components requires some knowledge of the structure of the implementation, which essentially consists of two parts:

  1. A concurrent, high-performance library of strict, segmented arrays. In contrast to Haskell 98 arrays, these arrays are strict in that when one element of an array is evaluated, all of them are - we also call this a parallel evaluation semantics. Moreover, all operations come in two flavours: one for plain, flat arrays and one for segmented arrays, which are a particular representation of arrays with one level of nesting. For example, a sum of a segmented array of numbers computes one sum for each segment. The library has a purely functional interface, but internally uses monadic low-level array operations, array fusion, and a many standard GHC optimisations to produce highly optimised code. Finally, the library uses GHC's SMP concurrency to parallelise array processing on hardware with multiple processing elements.
  2. A vectorising program transformation (in the compiler) that maps nested array code (of arbitrary nesting depth) to code using segmented arrays. Nested parallel arrays are as convenient to use as finite, eagerly evaluated nested lists. Code vectorisation transforms a nested parallel array program such that it operates on the segmented arrays described before. The resulting code would be tedious to write manually, but is much more efficient than a direct implementation of nested arrays. (As segmented arrays correspond to arrays with one level of nesting, vectorisation collapses arbitrary nesting to one level of nesting.)

So far, we have implemented large parts of the concurrent array library (Part 1), but not the vectorisation transformation (Part 2). Hence, users must choose between the following two options: (1) The convenient programming model of arbitrarily nested, irregular array computations with a reasonably efficient, but not highly optimised and only purely sequential implementation. (2) An aggresively optimising, concurrent array library with a less expressive API of segmented (instead of nested) arrays, but which is still purely functional.

Convenience without the speed: nested arrays in Haskell

Any recent stable version of GHC (e.g., version 6.6) includes syntactic support for array comprehensions and a library of frequently used array operations. To use these, you need to pass GHC the command line option -fparr (to enable the extra syntax) and import the module GHC.PArr (a Prelude extension for arrays). (If you like to use parallel array comprehensions, you also need -fglasgow-exts.) For example, the following module implements a dot product using arrays:

{-# OPTIONS -fparr -fglasgow-exts #-}
module DotP (dotp)
where
import GHC.PArr

dotp :: Num a => [:a:] -> [:a:] -> a
dotp xs ys = sumP [:x * y | x <- xs | y <- ys:]

You can use this module in an interactive GHCi session as follows:

Prelude> :set -fparr -fglasgow-exts
Prelude> :load DotP
[1 of 1] Compiling DotP             ( code/haskell/DotP.hs, interpreted )
Ok, modules loaded: DotP.
*DotP> dotp [:1..3:] [:4..6:]
32
*DotP>

(NB: The :set is needed despite the OPTIONS pragma in DotP.hs, so that you can use array syntax on the interactive command line of GHCi.)

Unfortunately, the current version of Haddock does not grok the special array syntax, so there is no nice HTML version of the interface for GHC.PArr. Instead, please consult the source code of GHC.PArr.

Speed with less convenience: package ndp

The concurrent, high-performance library of strict, segmented arrays mentioned above takes the form of a GHC package called ndp. This package is under development and only available in source form. The simplest way to build it is to first get and build a source distribution of GHC (preferably the current development version) - see the docu on how to get the sources and how to build them. Then, in the source tree, do the following

% cd libraries
% darcs get http://darcs.haskell.org/packages/ndp/
% cd ndp
% make boot
% make

Now, the option -package ndp is available for use with the inplace compiler (i.e., compiler/ghc-inplace). Alternatively, you can install it by invoking make install on the GHC source root and within libraries/ndp/. Then, the option -package ndp can be used in the installed compiler.

For example, the following module implements the dot product with package ndp:

module DotP_ndp (dotp)
where

import Data.Array.Parallel.Unlifted

dotp :: (Num a, UA a) => UArr a -> UArr a -> a
dotp xs ys = sumU (zipWithU (*) xs ys)

We can also use that in an interactive GHCi session:

Prelude> :set -package ndp
package flags have changed, ressetting and loading new packages...
Loading package ndp-1.0 ... linking ... done.
Prelude> :l /home/chak/code/haskell/DotP_ndp
[1 of 1] Compiling DotP_ndp         ( /home/chak/code/haskell/DotP_ndp.hs, interpreted )
Ok, modules loaded: DotP_ndp.
*DotP_ndp> dotp (toU [1..3]) (toU [4..6])
Loading package haskell98 ... linking ... done.
32.0
*DotP_ndp>

The difference between the package ndp and the -fparr version of the dot product is just a fairly small amount of sugar. However, for programs using arrays of more complex (including nested arrays), the difference is much bigger. Nevertheless, many programs can be implemented quite easily with just package ndp. The speed difference between the two options is dramatic.