{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE StrictData #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
module Main (main) where
import qualified CommandBenchmark
import Control.Monad (replicateM, unless)
import Criterion.Main (defaultMain)
import Criterion.Types
( bench,
bgroup,
nfAppIO,
)
import Data.Semigroup (Semigroup (stimes))
import UnliftIO.MessageBox.CatchAll
( CatchAllArg (..),
)
import UnliftIO.MessageBox.Class
( IsInput (..),
IsMessageBox (..),
IsMessageBoxArg (..),
deliver,
newInput,
receive,
)
import qualified UnliftIO.MessageBox.Limited as L
import qualified UnliftIO.MessageBox.Unlimited as U
import UnliftIO (MonadUnliftIO, conc, runConc)
main =
defaultMain
[ CommandBenchmark.benchmark,
bgroup
"Messaging"
[ bench
( mboxImplTitle <> " "
<> show noMessages
<> " "
<> show senderNo
<> " : "
<> show receiverNo
)
( nfAppIO
impl
(senderNo, noMessages, receiverNo)
)
| noMessages <- [100_000],
(isNonBlocking, mboxImplTitle, impl) <-
[ let x = U.BlockingUnlimited
in (False, "Unlimited", unidirectionalMessagePassing mkTestMessage x),
let x = CatchAllArg U.BlockingUnlimited
in (False, "CatchUnlimited", unidirectionalMessagePassing mkTestMessage x),
-- let x = L.BlockingBoxLimit L.MessageLimit_1
-- in (False, show x, unidirectionalMessagePassing mkTestMessage x),
-- let x = L.BlockingBoxLimit L.MessageLimit_16
-- in (False, show x, unidirectionalMessagePassing mkTestMessage x),
-- let x = L.BlockingBoxLimit L.MessageLimit_32
-- in (False, show x, unidirectionalMessagePassing mkTestMessage x),
-- let x = L.BlockingBoxLimit L.MessageLimit_64
-- in (False, show x, unidirectionalMessagePassing mkTestMessage x),
-- let x = L.BlockingBoxLimit L.MessageLimit_128
-- in (False, show x, unidirectionalMessagePassing mkTestMessage x),
let x = L.BlockingBoxLimit L.MessageLimit_256
in (False, "Blocking256", unidirectionalMessagePassing mkTestMessage x),
-- ,
-- let x = L.BlockingBoxLimit L.MessageLimit_512
-- in (False, show x, unidirectionalMessagePassing mkTestMessage x),
-- let x = L.BlockingBoxLimit L.MessageLimit_4096
-- in (False, show x, unidirectionalMessagePassing mkTestMessage x),
let x = L.NonBlockingBoxLimit L.MessageLimit_128
in (True, show x, unidirectionalMessagePassing mkTestMessage x),
-- let x = L.WaitingBoxLimit Nothing 5_000_000 L.MessageLimit_128
-- in (False, show x, unidirectionalMessagePassing mkTestMessage x),
let x = L.WaitingBoxLimit (Just 60_000_000) 5_000_000 L.MessageLimit_256
in (True, "Waiting256", unidirectionalMessagePassing mkTestMessage x)
-- let x = CatchAllArg (L.BlockingBoxLimit L.MessageLimit_128)
-- in (False, show x, unidirectionalMessagePassing mkTestMessage x)
],
(senderNo, receiverNo) <-
[ -- (1, 1000),
(10, 100),
(1, 1),
(1000, 1)
],
not isNonBlocking || senderNo == 1 && receiverNo > 1
]
]
mkTestMessage :: Int -> TestMessage
mkTestMessage !i =
MkTestMessage
( "The not so very very very very very very very very very very very very very very very very very very very very very very very very " ++ show i,
"large",
"meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeessssssssssssssssssssssssssssssssss" ++ show i,
( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"ggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
even i,
123423421111111111111111111123234 * toInteger i
)
)
newtype TestMessage = MkTestMessage (String, String, String, (String, String, Bool, Integer))
deriving newtype (Show)
unidirectionalMessagePassing ::
(MonadUnliftIO m, IsMessageBoxArg cfg) =>
(Int -> TestMessage) ->
cfg ->
(Int, Int, Int) ->
m ()
unidirectionalMessagePassing !msgGen !impl (!nP, !nM, !nC) = do
(ccs, cs) <- consumers
let ps = producers cs
runConc (ps <> ccs)
where
producers !cs = stimes nP (conc producer)
where
producer =
mapM_
( \(!msg, !cons) -> do
!ok <- deliver cons msg
unless ok (error ("producer failed to deliver: " <> show msg))
)
((,) <$> (msgGen <$> [0 .. (nM `div` (nC * nP)) - 1]) <*> cs)
consumers = do
cis <- replicateM nC (newMessageBox impl)
let ccs = foldMap (conc . consume (nM `div` nC)) cis
cs <- traverse newInput cis
return (ccs, cs)
where
consume 0 _inBox = return ()
consume workLeft inBox = do
receive inBox
>>= maybe
(error "consumer failed to receive")
(const (consume (workLeft - 1) inBox))