IntersectMBO / IntersectMBO/ouroboros-consensus
[FEAT] - Specialize IOLike to IO
- Dominant language
- Haskell
- Stars
- 67
- Forks
- 43
- Avg merge
- 5d 13h
- Merged PRs (30d)
- 43
Description
The code emitted by using the `io-classes` abstractions does not take advantage of the fact that the node will end up running in IO. This imposes a performance penalty that could be avoided by specializing the whole of the Consensus codebase to IO.
For example this code:
```haskell
import Control.Monad.Class.MonadEventlog
import Control.Monad.Class.MonadSTM
import Control.Concurrent.Class.MonadSTM
data CounterState n = CounterOpen !(Container n) | CounterClosed
data Counter m n = Counter {
incrementBy :: n -> m ()
, readCounter :: m n
, decrementBy :: n -> m ()
, close :: m ()
}
guardClosed (CounterOpen (Container n)) f = f n
guardClosed CounterClosed _ = error "Closed"
data Container n = Container !n
{-# SPECIALIZE newCounter :: (Num n, Show n, Enum n) => Container n -> IO (Counter IO n) #-}
newCounter ::
(Num n, Show n, Enum n, MonadSTM m, MonadEventlog m) =>
Container n -> m (Counter m n)
newCounter n = do
!tv <- newTVarIO (CounterOpen n)
pure Counter {
incrementBy = \n' -> do
n0 <- readTVarIO tv
guardClosed n0 $ \nn -> do
traceEventIO $ "increment " ++ show nn
atomically $ writeTVar tv (CounterOpen $ Container $ foldl (+) nn [0..n'])
, decrementBy = \n' -> do
n0 <- readTVarIO tv
guardClosed n0 $ \nn -> do
traceEventIO $ "decrement " ++ show nn
atomically $ writeTVar tv (CounterOpen $ Container $ foldl (-) nn [0..n'])
, readCounter = do
n0 <- readTVarIO tv
guardClosed n0 $ \nn -> do
traceEventIO $ "Read " ++ show nn
pure nn
, close = atomically $ writeTVar tv CounterClosed
}
```
Results in the following STG definitions:
```haskell
let { lvl24_s3bD = \u [] readTVarIO $dMonadSTM_s3bl tv1_s3bC;
} in
...
let {
sat_s3cm =
\u []
let {
sat_s3cl = \u [] writeTVar $dMonadSTM_s3bl tv1_s3bC CounterClosed;
} in atomically $dMonadSTM_s3bl $dIP11_r35X sat_s3cl; } in
```
where we have updatable thunks depending on the monad. With specialization these are resolved to IO and then there are no thunks around
```haskell
let {
sat_s3bb =
\r [n'_s3aJ void_XF]
case readTVarIO# [ipv1_s3a2 void#] of ds1_s3aL {
(# #) ipv3_s3aN ->
case ipv3_s3aN of wild_s3aO
...
```
Contributor guide
Assessment
This issue has not been assessed yet.