IntersectMBO / IntersectMBO/ouroboros-consensus

[FEAT] - Specialize IOLike to IO

Open
#1,380 1 comment 0 reactions 0 assignees View on GitHub
🏎️ performance
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.