1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
|
module Timing(
timed, timedIO,
startTimings,
printTimings
) where
import qualified Data.HashMap.Strict as Map
import Control.Exception
import Data.IORef.Extra
import Data.Tuple.Extra
import Data.List.Extra
import System.Time.Extra
import System.IO.Unsafe
type Category = String
type Item = String
{-# NOINLINE useTimingsRef #-}
useTimingsRef :: IORef Bool
useTimingsRef = unsafePerformIO $ newIORef False
{-# NOINLINE useTimings #-}
useTimings :: Bool
useTimings = unsafePerformIO $ readIORef useTimingsRef
{-# NOINLINE timings #-}
timings :: IORef (Map.HashMap (Category, Item) Seconds)
timings = unsafePerformIO $ newIORef Map.empty
{-# NOINLINE timed #-}
timed :: Category -> Item -> a -> a
timed c i x = if not useTimings then x else unsafePerformIO $ timedIO c i $ evaluate x
timedIO :: Category -> Item -> IO a -> IO a
timedIO c i x = if not useTimings then x else do
(time, x) <- duration x
atomicModifyIORef' timings $ \mp -> (Map.insertWith (+) (c, i) time mp, ())
return x
startTimings :: IO ()
startTimings = do
writeIORef useTimingsRef True
writeIORef timings Map.empty
printTimings :: IO ()
printTimings = do
mp <- readIORef timings
let items = sortOn (sumSnd . snd) $
groupSort $ map (\((a,b),c) -> (a,(b,c))) $ Map.toList mp
putStrLn $ unlines $ intercalate [""] $ map disp $ items ++ [("TOTAL", map (second sumSnd) items)]
where
sumSnd = sum . map snd
disp (cat,xs) =
("Timing " ++ cat) :
[" " ++ showDuration b ++ " " ++ a | (a,b) <- xs2] ++
[" " ++ showDuration (sumSnd xs2) ++ " TOTAL"]
where
xs2 = f $ splitAt 9 $ sortOn (negate . snd) xs
f (xs,ys)
| length ys <= 1 = xs ++ ys
| otherwise = xs ++ [("Other items (" ++ show (length ys) ++ ")", sumSnd ys)]
|