packages feed

timestats 0.1.1 → 0.1.2

raw patch · 4 files changed

+44/−19 lines, 4 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Debug.TimeStats: collect :: MonadIO m => m [(String, TimeStats)]
+ Debug.TimeStats: collect :: Monad m => m [(String, TimeStats)]
- Debug.TimeStats: hPrintTimeStats :: MonadIO m => Handle -> m ()
+ Debug.TimeStats: hPrintTimeStats :: Monad m => Handle -> m ()
- Debug.TimeStats: measureM :: MonadIO m => String -> m a -> m a
+ Debug.TimeStats: measureM :: Monad m => String -> m a -> m a
- Debug.TimeStats: printTimeStats :: MonadIO m => m ()
+ Debug.TimeStats: printTimeStats :: Monad m => m ()
- Debug.TimeStats: reset :: MonadIO m => m ()
+ Debug.TimeStats: reset :: Monad m => m ()
- Debug.TimeStats: scope :: MonadIO m => m a -> m a
+ Debug.TimeStats: scope :: Monad m => m a -> m a

Files

CHANGELOG.md view
@@ -1,5 +1,9 @@ # Revision history for timestats +## 0.1.2 -- 2024-05-17++* Change the type of `measureM` to work in any monad (not only MonadIO instances).+ ## 0.1.1 -- 2023-11-05  * Format counts with a thousand separator
src/Debug/TimeStats.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE ScopedTypeVariables #-}+ -- | A module to collect aggregates on how much time is spent in a computation -- -- Aggregates can be identified with a label that determines where the time of@@ -31,7 +33,6 @@  import Control.Exception (evaluate) import Control.Monad (forM, forM_, unless)-import Control.Monad.IO.Class (MonadIO(liftIO)) import Data.IORef import Data.Map (Map) import Data.Maybe (isJust)@@ -66,7 +67,7 @@ -- evaluated. -- {-# INLINE measureM #-}-measureM :: MonadIO m => String -> m a -> m a+measureM :: Monad m => String -> m a -> m a measureM label =     -- See the documentation of 'enabled'     if enabled then do@@ -125,8 +126,8 @@ labelStatsMapRef = unsafePerformIO $ newIORef Map.empty  -- | Set all statistics to initial values.-reset :: MonadIO m => m ()-reset = liftIO $+reset :: Monad m => m ()+reset = intersperseIOinM $     if enabled then do       m <- readIORef labelStatsMapRef       forM_ (Map.elems m) $ \(TimeStatsRef ref) ->@@ -136,7 +137,7 @@  -- | Run an action by previously reseting all stats to initial values -- and printing them afterwards.-scope :: MonadIO m => m a -> m a+scope :: Monad m => m a -> m a scope =     if enabled then       \m -> do@@ -159,21 +160,21 @@         Just r -> (m, r)  -- | Yields the labels and the stats collected thus far.-collect :: MonadIO m => m [(String, TimeStats)]-collect = liftIO $ do+collect :: Monad m => m [(String, TimeStats)]+collect = intersperseIOinM $ do     m <- readIORef labelStatsMapRef     forM (Map.toList m) $ \(label, TimeStatsRef ref) ->       (,) label <$> readIORef ref  -- | Prints the time stats to the given handle.-hPrintTimeStats :: MonadIO m => Handle -> m ()-hPrintTimeStats h = liftIO $ do+hPrintTimeStats :: Monad m => Handle -> m ()+hPrintTimeStats h = intersperseIOinM $ do     xs <- collect     unless (null xs) $       Text.hPutStrLn h (asText xs)  -- | Prints the time stats to stderr.-printTimeStats :: MonadIO m => m ()+printTimeStats :: Monad m => m () printTimeStats = hPrintTimeStats stderr  -- | Renders the given time stats in a tabular format@@ -224,16 +225,16 @@ initialTimeStats = TimeStats 0 0  -- | Creates a reference to time stats with intial values-newTimeStatsRef :: MonadIO m => m TimeStatsRef-newTimeStatsRef = liftIO $ TimeStatsRef <$> newIORef initialTimeStats+newTimeStatsRef :: Monad m => m TimeStatsRef+newTimeStatsRef = intersperseIOinM $ TimeStatsRef <$> newIORef initialTimeStats  -- | Measure the time it takes to run the given action and update with it -- the given reference to time stats.-measureMWith :: MonadIO m => TimeStatsRef -> m a -> m a+measureMWith :: Monad m => TimeStatsRef -> m a -> m a measureMWith tref m = do-    t0 <- liftIO getMonotonicTimeNSec+    t0 <- intersperseIOinM getMonotonicTimeNSec     a <- m-    liftIO $ do+    intersperseIOinM $ do       tf <- getMonotonicTimeNSec       updateTimeStatsRef tref $ \st ->         st@@ -246,3 +247,23 @@ updateTimeStatsRef :: TimeStatsRef -> (TimeStats -> TimeStats) -> IO () updateTimeStatsRef (TimeStatsRef ref) f =     atomicModifyIORef' ref $ \st -> (f st, ())++---------------------+-- intersperseIOinM+---------------------++-- | Hack to intersperse IO actions into any monad+intersperseIOinM :: forall a m. Monad m => IO a -> m a+intersperseIOinM m = do+    -- The ficticious state is only used to force unsafePerformIO to run @m@+    -- every time @intersperseIOinM m@ is evaluated.+    s <- getStateM+    pure $! snd $ unsafePerformIO $ do+      r <- m+      pure (s, r)+  where+    -- We mark this function as NOINLINE to ensure the compiler cannot reason+    -- that two calls of @getStateM@ might yield the same value.+    {-# NOINLINE getStateM #-}+    getStateM :: m Int+    getStateM = pure 0
tests/Main.hs view
@@ -14,7 +14,7 @@ main :: IO () main = do     testMeasureM-    testFormatNatWithSeparator+    testFormatIntWithSeparator  testMeasureM :: IO () testMeasureM = do@@ -36,8 +36,8 @@     eqStat (lbl0, ts0) (lbl1, ts1) =       lbl0 == lbl1 && TimeStats.countStat ts0 == TimeStats.countStat ts1 -testFormatNatWithSeparator :: IO ()-testFormatNatWithSeparator = do+testFormatIntWithSeparator :: IO ()+testFormatIntWithSeparator = do     testCase   123456789   "123_456_789"     testCase    23456789    "23_456_789"     testCase     3456789     "3_456_789"
timestats.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.4 name:               timestats-version:            0.1.1+version:            0.1.2  synopsis: A library for profiling time in Haskell applications