{-# Language OverloadedStrings #-}

{-|
Module      : RtsStats
Description : Human readable interface to GHC RTS statistics
Copyright   : (c) Eric Mertens, 2017
License     : ISC
Maintainer  : emertens@gmail.com

-}

module RtsStats
  ( Stats
  , getStats
  , statsToEntries
  ) where

import           Data.Int        (Int64)
import           Data.List       (intercalate)
import           Data.List.Split (chunksOf)
import           Data.Text       (Text)
import qualified Data.Text as Text
import           Data.Word       (Word32, Word64)
import           GHC.Stats

class    Render a      where render :: a -> Text
instance Render Word32 where render :: Word32 -> Text
render = Word32 -> Text
forall a. (Show a, Num a, Ord a) => a -> Text
prettyNum
instance Render Word64 where render :: Word64 -> Text
render = Word64 -> Text
forall a. (Show a, Num a, Ord a) => a -> Text
prettyNum
instance Render Int64  where render :: Int64 -> Text
render = Int64 -> Text
forall a. (Show a, Num a, Ord a) => a -> Text
prettyNum
instance Render Double where render :: Double -> Text
render = String -> Text
Text.pack (String -> Text) -> (Double -> String) -> Double -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> String
forall a. Show a => a -> String
show

prettyNum :: Show a => Num a => Ord a => a -> Text
prettyNum :: a -> Text
prettyNum a
n = String -> Text
Text.pack (String -> String
addSign (String -> String
addCommas (a -> String
forall a. Show a => a -> String
show (a -> a
forall a. Num a => a -> a
abs a
n))))
  where
    addSign :: String -> String
addSign = if a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0 then (:) Char
'-' else String -> String
forall a. a -> a
id

addCommas :: String -> String
addCommas :: String -> String
addCommas = String -> String
forall a. [a] -> [a]
reverse (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"," ([String] -> String) -> (String -> [String]) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String -> [String]
forall e. Int -> [e] -> [[e]]
chunksOf Int
3 (String -> [String]) -> (String -> String) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
forall a. [a] -> [a]
reverse

newtype Stats = Stats RTSStats

getStats :: IO (Maybe Stats)
getStats :: IO (Maybe Stats)
getStats =
  do Bool
enabled <- IO Bool
getRTSStatsEnabled
     if Bool
enabled then Stats -> Maybe Stats
forall a. a -> Maybe a
Just (Stats -> Maybe Stats)
-> (RTSStats -> Stats) -> RTSStats -> Maybe Stats
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RTSStats -> Stats
Stats (RTSStats -> Maybe Stats) -> IO RTSStats -> IO (Maybe Stats)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO RTSStats
getRTSStats
                else Maybe Stats -> IO (Maybe Stats)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe Stats
forall a. Maybe a
Nothing

statsToEntries :: Stats -> [(Text, Text)]
statsToEntries :: Stats -> [(Text, Text)]
statsToEntries (Stats RTSStats
rts) =
  let rgc :: GCDetails
rgc = RTSStats -> GCDetails
gc RTSStats
rts in GCDetails -> [(Text, Text)] -> [(Text, Text)]
seq GCDetails
rgc
  [ (Text
"GCs"                                 , Word32 -> Text
forall a. Render a => a -> Text
render (Word32 -> Text) -> Word32 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Word32
gcs                             RTSStats
rts)
  , (Text
"Major GCs"                           , Word32 -> Text
forall a. Render a => a -> Text
render (Word32 -> Text) -> Word32 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Word32
major_gcs                       RTSStats
rts)
  , (Text
"Allocated bytes"                     , Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Word64
allocated_bytes                 RTSStats
rts)
  , (Text
"Max live bytes"                      , Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Word64
max_live_bytes                  RTSStats
rts)
  , (Text
"Max large objects bytes"             , Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Word64
max_large_objects_bytes         RTSStats
rts)
  , (Text
"Max compact bytes"                   , Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Word64
max_compact_bytes               RTSStats
rts)
  , (Text
"Max slop bytes"                      , Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Word64
max_slop_bytes                  RTSStats
rts)
  , (Text
"Max memory in use bytes"             , Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Word64
max_mem_in_use_bytes            RTSStats
rts)
  , (Text
"Cumulative live bytes"               , Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Word64
cumulative_live_bytes           RTSStats
rts)
  , (Text
"Copied bytes"                        , Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Word64
copied_bytes                    RTSStats
rts)
  , (Text
"Parallel copied bytes"               , Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Word64
par_copied_bytes                RTSStats
rts)
  , (Text
"Cumulative parallel max copied bytes", Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Word64
cumulative_par_max_copied_bytes RTSStats
rts)
  , (Text
"Mutator CPU ns"                      , Int64 -> Text
forall a. Render a => a -> Text
render (Int64 -> Text) -> Int64 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Int64
mutator_cpu_ns                  RTSStats
rts)
  , (Text
"Mutator elapsed ns"                  , Int64 -> Text
forall a. Render a => a -> Text
render (Int64 -> Text) -> Int64 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Int64
mutator_elapsed_ns              RTSStats
rts)
  , (Text
"GC CPU ns"                           , Int64 -> Text
forall a. Render a => a -> Text
render (Int64 -> Text) -> Int64 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Int64
gc_cpu_ns                       RTSStats
rts)
  , (Text
"GC elapsed ns"                       , Int64 -> Text
forall a. Render a => a -> Text
render (Int64 -> Text) -> Int64 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Int64
gc_elapsed_ns                   RTSStats
rts)
  , (Text
"CPU ns"                              , Int64 -> Text
forall a. Render a => a -> Text
render (Int64 -> Text) -> Int64 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Int64
cpu_ns                          RTSStats
rts)
  , (Text
"Elapsed ns"                          , Int64 -> Text
forall a. Render a => a -> Text
render (Int64 -> Text) -> Int64 -> Text
forall a b. (a -> b) -> a -> b
$ RTSStats -> Int64
elapsed_ns                      RTSStats
rts)
  , (Text
"==[Totals]=="                        , Text
""                                          )
  , (Text
""                                    , Text
""                                          )
  , (Text
"Generation"                          , Word32 -> Text
forall a. Render a => a -> Text
render (Word32 -> Text) -> Word32 -> Text
forall a b. (a -> b) -> a -> b
$ GCDetails -> Word32
gcdetails_gen                   GCDetails
rgc)
  , (Text
"Threads"                             , Word32 -> Text
forall a. Render a => a -> Text
render (Word32 -> Text) -> Word32 -> Text
forall a b. (a -> b) -> a -> b
$ GCDetails -> Word32
gcdetails_threads               GCDetails
rgc)
  , (Text
"Allocated bytes"                     , Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ GCDetails -> Word64
gcdetails_allocated_bytes       GCDetails
rgc)
  , (Text
"Live bytes"                          , Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ GCDetails -> Word64
gcdetails_live_bytes            GCDetails
rgc)
  , (Text
"Large objects bytes"                 , Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ GCDetails -> Word64
gcdetails_large_objects_bytes   GCDetails
rgc)
  , (Text
"Compact bytes"                       , Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ GCDetails -> Word64
gcdetails_compact_bytes         GCDetails
rgc)
  , (Text
"Slop bytes"                          , Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ GCDetails -> Word64
gcdetails_slop_bytes            GCDetails
rgc)
  , (Text
"Memory in use bytes"                 , Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ GCDetails -> Word64
gcdetails_mem_in_use_bytes      GCDetails
rgc)
  , (Text
"Copied bytes"                        , Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ GCDetails -> Word64
gcdetails_copied_bytes          GCDetails
rgc)
  , (Text
"Parallel max copied bytes"           , Word64 -> Text
forall a. Render a => a -> Text
render (Word64 -> Text) -> Word64 -> Text
forall a b. (a -> b) -> a -> b
$ GCDetails -> Word64
gcdetails_par_max_copied_bytes  GCDetails
rgc)
  , (Text
"Sync elapsed ns"                     , Int64 -> Text
forall a. Render a => a -> Text
render (Int64 -> Text) -> Int64 -> Text
forall a b. (a -> b) -> a -> b
$ GCDetails -> Int64
gcdetails_sync_elapsed_ns       GCDetails
rgc)
  , (Text
"CPU ns"                              , Int64 -> Text
forall a. Render a => a -> Text
render (Int64 -> Text) -> Int64 -> Text
forall a b. (a -> b) -> a -> b
$ GCDetails -> Int64
gcdetails_cpu_ns                GCDetails
rgc)
  , (Text
"Elapsed ns"                          , Int64 -> Text
forall a. Render a => a -> Text
render (Int64 -> Text) -> Int64 -> Text
forall a b. (a -> b) -> a -> b
$ GCDetails -> Int64
gcdetails_elapsed_ns            GCDetails
rgc)
  , (Text
"==[Last GC]=="                       , Text
""                                          )
  ]