packages feed

accelerate-llvm-1.3.0.0: src/Data/Array/Accelerate/LLVM/Execute/Async.hs

{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE GADTs                      #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables        #-}
{-# LANGUAGE TypeApplications           #-}
{-# LANGUAGE TypeFamilies               #-}
{-# OPTIONS_HADDOCK hide #-}
-- |
-- Module      : Data.Array.Accelerate.LLVM.Execute.Async
-- Copyright   : [2014..2020] The Accelerate Team
-- License     : BSD3
--
-- Maintainer  : Trevor L. McDonell <trevor.mcdonell@gmail.com>
-- Stability   : experimental
-- Portability : non-portable (GHC extensions)
--

module Data.Array.Accelerate.LLVM.Execute.Async
  where

import Data.Array.Accelerate.LLVM.State                             ( LLVM )
import Data.Array.Accelerate.Representation.Array
import Data.Array.Accelerate.Representation.Type

import GHC.Stack


class Monad (Par arch) => Async arch where

  -- | The monad parallel computations will be executed in. Presumably a stack
  -- with the LLVM monad at the base.
  --
  data Par arch :: * -> *

  -- | Parallel computations can communicate via futures.
  --
  type FutureR arch :: * -> *

  -- | Create a new (empty) promise, to be fulfilled at some future point.
  --
  new :: HasCallStack => Par arch (FutureR arch a)

  -- | The future is here. Multiple 'put's to the same future are not allowed
  -- and (presumably) result in a runtime error.
  --
  put :: HasCallStack => FutureR arch a -> a -> Par arch ()

  -- | Read the value stored in a future, once it is available. It is _not_
  -- required that this is a blocking operation on the host, only that it is
  -- blocking with respect to computations on the remote device.
  --
  get :: HasCallStack => FutureR arch a -> Par arch a

  -- | Fork a computation to happen in parallel. The forked computation may
  -- exchange values with other computations using Futures.
  --
  fork :: HasCallStack => Par arch () -> Par arch ()

  -- | Lift an operation from the base LLVM monad into the Par monad
  --
  liftPar :: HasCallStack => LLVM arch a -> Par arch a

  -- | Read a value stored in a future, once it is available. This is blocking
  -- with respect to both the host and remote device.
  --
  {-# INLINEABLE block #-}
  block :: HasCallStack => FutureR arch a -> Par arch a
  block = get

  -- | Evaluate a computation in a new thread/context. This might be implemented
  -- more efficiently than the default implementation.
  --
  {-# INLINEABLE spawn #-}
  spawn :: HasCallStack => Par arch a -> Par arch a
  spawn m = do
    r <- new
    fork $ put r =<< m
    get r

  -- | Create a new "future" where the value is available immediately. This
  -- might be implemented more efficiently than the default implementation.
  --
  {-# INLINEABLE newFull #-}
  newFull :: HasCallStack => a -> Par arch (FutureR arch a)
  newFull a = do
    r <- new
    put r a
    return r

type family FutureArraysR arch arrs where
  FutureArraysR arch ()           = ()
  FutureArraysR arch (a, b)       = (FutureArraysR arch a, FutureArraysR arch b)
  FutureArraysR arch (Array sh e) = FutureR arch (Array sh e)

getArrays :: Async arch => ArraysR a -> FutureArraysR arch a -> Par arch a
getArrays (TupRsingle ArrayR{}) a        = get a
getArrays TupRunit              _        = return ()
getArrays (TupRpair r1 r2)      (a1, a2) = (,) <$> getArrays r1 a1 <*> getArrays r2 a2

blockArrays :: Async arch => ArraysR a -> FutureArraysR arch a -> Par arch a
blockArrays (TupRsingle ArrayR{}) a        = block a
blockArrays TupRunit              _        = return ()
blockArrays (TupRpair r1 r2)      (a1, a2) = (,) <$> blockArrays r1 a1 <*> blockArrays r2 a2

-- | Create new (empty) promises for a structure of arrays, to be fulfilled
-- at some future point. Note that the promises in the structure may all be
-- fullfilled at different moments.
--
newArrays :: Async arch => ArraysR a -> Par arch (FutureArraysR arch a)
newArrays TupRunit               = return ()
newArrays (TupRsingle ArrayR{})  = new
newArrays (TupRpair repr1 repr2) = (,) <$> newArrays repr1 <*> newArrays repr2