packages feed

lossy-chan-0.1.0.0: benchmark/Benchmark/Simple.hs

{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}

module Benchmark.Simple (
  SimpleBenchOpts (..),
  runSimpleBench,
) where

import Benchmark.Chan
import Control.Concurrent.Async (async, wait)
import Control.Concurrent.LossyChan (NoInChanError)
import Control.Exception (BlockedIndefinitelyOnSTM, Handler (..), catches)
import Control.Monad (void)
import Data.Foldable (for_)
import Data.Traversable (for)

{- |
Options for a simple benchmark.
-}
data SimpleBenchOpts
  = MkSimpleBenchOpts
  { messages :: !Int
  , senders :: !Int
  , receivers :: !Int
  }

{- |
Run a simple benchmark.
-}
runSimpleBench :: Chan i o -> SimpleBenchOpts -> IO ()
runSimpleBench MkChan{..} =
  \MkSimpleBenchOpts{..} -> do
    (i, o) <- new
    receiverAsyncs <-
      for [1 .. receivers] $ \r -> do
        o' <- if r == receivers then pure o else dup (i, o)
        async $
          handles $
            for_ [1 .. messages] $ \_m -> do
              void (recv o')
    _senderAsync <-
      for [1 .. senders] $ \s -> do
        async $
          for_ [1 .. messages] $ \m -> do
            void (send i (s, m))
    for_ receiverAsyncs wait
{-# INLINE runSimpleBench #-}


handles :: IO () -> IO ()
handles = (`catches` handlers)
 where
  handlers :: [Handler ()]
  handlers =
    [ Handler (\(_e :: BlockedIndefinitelyOnSTM) -> pure ())
    , Handler (\(_e :: NoInChanError) -> pure ())
    ]
{-# INLINE handles #-}