-- GENERATED by C->Haskell Compiler, version 0.28.6 Switcheroo, 25 November 2017 (Haskell)
-- Edit the ORIGNAL .chs file instead!


{-# LINE 1 "src/Foreign/CUDA/Driver/Event.chs" #-}
{-# LANGUAGE BangPatterns             #-}
{-# LANGUAGE CPP                      #-}
{-# LANGUAGE EmptyDataDecls           #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE TemplateHaskell          #-}
{-# LANGUAGE EmptyCase                #-}
--------------------------------------------------------------------------------
-- |
-- Module    : Foreign.CUDA.Driver.Event
-- Copyright : [2009..2018] Trevor L. McDonell
-- License   : BSD
--
-- Event management for low-level driver interface
--
--------------------------------------------------------------------------------

module Foreign.CUDA.Driver.Event (

  -- * Event Management
  Event(..), EventFlag(..), WaitFlag,
  create, destroy, elapsedTime, query, record, wait, block

) where
import qualified Foreign.C.Types as C2HSImp
import qualified Foreign.Ptr as C2HSImp





{-# LINE 28 "src/Foreign/CUDA/Driver/Event.chs" #-}


-- Friends
import Foreign.CUDA.Internal.C2HS
import Foreign.CUDA.Driver.Error
import Foreign.CUDA.Driver.Stream                         ( Stream(..), defaultStream )

-- System
import Foreign
import Foreign.C
import Data.Maybe
import Control.Monad                                      ( liftM )
import Control.Exception                                  ( throwIO )


--------------------------------------------------------------------------------
-- Data Types
--------------------------------------------------------------------------------

-- |
-- Events are markers that can be inserted into the CUDA execution stream and
-- later queried.
--
newtype Event = Event { useEvent :: ((C2HSImp.Ptr ()))}
  deriving (Eq, Show)

-- |
-- Event creation flags
--
data EventFlag = Default
               | BlockingSync
               | DisableTiming
               | Interprocess
  deriving (Eq,Show,Bounded)
instance Enum EventFlag where
  succ Default = BlockingSync
  succ BlockingSync = DisableTiming
  succ DisableTiming = Interprocess
  succ Interprocess = error "EventFlag.succ: Interprocess has no successor"

  pred BlockingSync = Default
  pred DisableTiming = BlockingSync
  pred Interprocess = DisableTiming
  pred Default = error "EventFlag.pred: Default has no predecessor"

  enumFromTo from to = go from
    where
      end = fromEnum to
      go v = case compare (fromEnum v) end of
                 LT -> v : go (succ v)
                 EQ -> [v]
                 GT -> []

  enumFrom from = enumFromTo from Interprocess

  fromEnum Default = 0
  fromEnum BlockingSync = 1
  fromEnum DisableTiming = 2
  fromEnum Interprocess = 4

  toEnum 0 = Default
  toEnum 1 = BlockingSync
  toEnum 2 = DisableTiming
  toEnum 4 = Interprocess
  toEnum unmatched = error ("EventFlag.toEnum: Cannot match " ++ show unmatched)

{-# LINE 60 "src/Foreign/CUDA/Driver/Event.chs" #-}


-- |
-- Possible option flags for waiting for events
--
data WaitFlag
instance Enum WaitFlag where
  toEnum   x = error ("WaitFlag.toEnum: Cannot match " ++ show x)
  fromEnum x = case x of {}


--------------------------------------------------------------------------------
-- Event management
--------------------------------------------------------------------------------

-- |
-- Create a new event
--
-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1g450687e75f3ff992fe01662a43d9d3db>
--
{-# INLINEABLE create #-}
create :: [EventFlag] -> IO Event
create !flags = resultIfOk =<< cuEventCreate flags

{-# INLINE cuEventCreate #-}
cuEventCreate :: ([EventFlag]) -> IO ((Status), (Event))
cuEventCreate a2 =
  alloca $ \a1' ->
  let {a2' = combineBitMasks a2} in
  cuEventCreate'_ a1' a2' >>= \res ->
  let {res' = cToEnum res} in
  peekEvt  a1'>>= \a1'' ->
  return (res', a1'')

{-# LINE 89 "src/Foreign/CUDA/Driver/Event.chs" #-}

  where peekEvt = liftM Event . peek


-- |
-- Destroy an event
--
-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1g593ec73a8ec5a5fc031311d3e4dca1ef>
--
{-# INLINEABLE destroy #-}
destroy :: Event -> IO ()
destroy !ev = nothingIfOk =<< cuEventDestroy ev

{-# INLINE cuEventDestroy #-}
cuEventDestroy :: (Event) -> IO ((Status))
cuEventDestroy a1 =
  let {a1' = useEvent a1} in
  cuEventDestroy'_ a1' >>= \res ->
  let {res' = cToEnum res} in
  return (res')

{-# LINE 104 "src/Foreign/CUDA/Driver/Event.chs" #-}



-- |
-- Determine the elapsed time (in milliseconds) between two events
--
-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1gdfb1178807353bbcaa9e245da497cf97>
--
{-# INLINEABLE elapsedTime #-}
elapsedTime :: Event -> Event -> IO Float
elapsedTime !ev1 !ev2 = resultIfOk =<< cuEventElapsedTime ev1 ev2

{-# INLINE cuEventElapsedTime #-}
cuEventElapsedTime :: (Event) -> (Event) -> IO ((Status), (Float))
cuEventElapsedTime a2 a3 =
  alloca $ \a1' ->
  let {a2' = useEvent a2} in
  let {a3' = useEvent a3} in
  cuEventElapsedTime'_ a1' a2' a3' >>= \res ->
  let {res' = cToEnum res} in
  peekFloatConv  a1'>>= \a1'' ->
  return (res', a1'')

{-# LINE 120 "src/Foreign/CUDA/Driver/Event.chs" #-}



-- |
-- Determines if a event has actually been recorded
--
-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1g6f0704d755066b0ee705749ae911deef>
--
{-# INLINEABLE query #-}
query :: Event -> IO Bool
query !ev =
  cuEventQuery ev >>= \rv ->
  case rv of
    Success  -> return True
    NotReady -> return False
    _        -> throwIO (ExitCode rv)

{-# INLINE cuEventQuery #-}
cuEventQuery :: (Event) -> IO ((Status))
cuEventQuery a1 =
  let {a1' = useEvent a1} in
  cuEventQuery'_ a1' >>= \res ->
  let {res' = cToEnum res} in
  return (res')

{-# LINE 139 "src/Foreign/CUDA/Driver/Event.chs" #-}



-- |
-- Record an event once all operations in the current context (or optionally
-- specified stream) have completed. This operation is asynchronous.
--
-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1g95424d3be52c4eb95d83861b70fb89d1>
--
{-# INLINEABLE record #-}
record :: Event -> Maybe Stream -> IO ()
record !ev !mst =
  nothingIfOk =<< cuEventRecord ev (fromMaybe defaultStream mst)

{-# INLINE cuEventRecord #-}
cuEventRecord :: (Event) -> (Stream) -> IO ((Status))
cuEventRecord a1 a2 =
  let {a1' = useEvent a1} in
  let {a2' = useStream a2} in
  cuEventRecord'_ a1' a2' >>= \res ->
  let {res' = cToEnum res} in
  return (res')

{-# LINE 156 "src/Foreign/CUDA/Driver/Event.chs" #-}



-- |
-- Makes all future work submitted to the (optional) stream wait until the given
-- event reports completion before beginning execution. Synchronisation is
-- performed on the device, including when the event and stream are from
-- different device contexts.
--
-- Requires CUDA-3.2.
--
-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__STREAM.html#group__CUDA__STREAM_1g6a898b652dfc6aa1d5c8d97062618b2f>
--
{-# INLINEABLE wait #-}
wait :: Event -> Maybe Stream -> [WaitFlag] -> IO ()
wait !ev !mst !flags =
  nothingIfOk =<< cuStreamWaitEvent (fromMaybe defaultStream mst) ev flags

{-# INLINE cuStreamWaitEvent #-}
cuStreamWaitEvent :: (Stream) -> (Event) -> ([WaitFlag]) -> IO ((Status))
cuStreamWaitEvent a1 a2 a3 =
  let {a1' = useStream a1} in
  let {a2' = useEvent a2} in
  let {a3' = combineBitMasks a3} in
  cuStreamWaitEvent'_ a1' a2' a3' >>= \res ->
  let {res' = cToEnum res} in
  return (res')

{-# LINE 182 "src/Foreign/CUDA/Driver/Event.chs" #-}


-- |
-- Wait until the event has been recorded
--
-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1g9e520d34e51af7f5375610bca4add99c>
--
{-# INLINEABLE block #-}
block :: Event -> IO ()
block !ev = nothingIfOk =<< cuEventSynchronize ev

{-# INLINE cuEventSynchronize #-}
cuEventSynchronize :: (Event) -> IO ((Status))
cuEventSynchronize a1 =
  let {a1' = useEvent a1} in
  cuEventSynchronize'_ a1' >>= \res ->
  let {res' = cToEnum res} in
  return (res')

{-# LINE 195 "src/Foreign/CUDA/Driver/Event.chs" #-}



foreign import ccall unsafe "Foreign/CUDA/Driver/Event.chs.h cuEventCreate"
  cuEventCreate'_ :: ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (C2HSImp.CUInt -> (IO C2HSImp.CInt)))

foreign import ccall unsafe "Foreign/CUDA/Driver/Event.chs.h cuEventDestroy"
  cuEventDestroy'_ :: ((C2HSImp.Ptr ()) -> (IO C2HSImp.CInt))

foreign import ccall unsafe "Foreign/CUDA/Driver/Event.chs.h cuEventElapsedTime"
  cuEventElapsedTime'_ :: ((C2HSImp.Ptr C2HSImp.CFloat) -> ((C2HSImp.Ptr ()) -> ((C2HSImp.Ptr ()) -> (IO C2HSImp.CInt))))

foreign import ccall unsafe "Foreign/CUDA/Driver/Event.chs.h cuEventQuery"
  cuEventQuery'_ :: ((C2HSImp.Ptr ()) -> (IO C2HSImp.CInt))

foreign import ccall unsafe "Foreign/CUDA/Driver/Event.chs.h cuEventRecord"
  cuEventRecord'_ :: ((C2HSImp.Ptr ()) -> ((C2HSImp.Ptr ()) -> (IO C2HSImp.CInt)))

foreign import ccall unsafe "Foreign/CUDA/Driver/Event.chs.h cuStreamWaitEvent"
  cuStreamWaitEvent'_ :: ((C2HSImp.Ptr ()) -> ((C2HSImp.Ptr ()) -> (C2HSImp.CUInt -> (IO C2HSImp.CInt))))

foreign import ccall safe "Foreign/CUDA/Driver/Event.chs.h cuEventSynchronize"
  cuEventSynchronize'_ :: ((C2HSImp.Ptr ()) -> (IO C2HSImp.CInt))