{-# LANGUAGE CPP #-}
{-# LANGUAGE RecordWildCards #-}
module Hermod.Tracing.Resources.Linux
(
readResourceStatsInternal
) where
import Hermod.Tracing.Resources.Types
import Data.Maybe (fromMaybe)
import qualified Data.Text as T
import qualified Data.Text.IO as T (readFile)
import qualified Data.Text.Read as T (decimal)
import Data.Word
import qualified GHC.Stats as GhcStats
import System.Posix.Files (fileMode, getFileStatus, intersectFileModes, ownerReadMode)
readProcBlockInOut :: IO (Word64, Word64)
readProcBlockInOut :: IO (Word64, Word64)
readProcBlockInOut = do
[Integer]
fields <- FilePath -> IO [Integer]
readProcList FilePath
"/proc/self/io"
case
(Integer -> Word64) -> [Integer] -> [Word64]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Integer -> Word64
forall a. Num a => Integer -> a
fromInteger ([Integer] -> [Word64])
-> ([Integer] -> [Integer]) -> [Integer] -> [Word64]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [Integer] -> [Integer]
forall a. Int -> [a] -> [a]
take Int
3 ([Integer] -> [Integer])
-> ([Integer] -> [Integer]) -> [Integer] -> [Integer]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [Integer] -> [Integer]
forall a. Int -> [a] -> [a]
drop Int
9 ([Integer] -> [Word64]) -> [Integer] -> [Word64]
forall a b. (a -> b) -> a -> b
$ [Integer]
fields of
[Word64
fsRd, Word64
_, Word64
fsWr] -> (Word64, Word64) -> IO (Word64, Word64)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Word64
fsRd, Word64
fsWr)
[Word64]
_ -> (Word64, Word64) -> IO (Word64, Word64)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Word64
0, Word64
0)
readProcNetInOut :: IO (Word64, Word64)
#ifdef WITH_NETSTAT
readProcNetInOut = do
fields <- T.words . fourthLine . T.lines <$> T.readFile "/proc/self/net/netstat"
case
fmap readMaybeText . take 2 . drop 7 $ fields of
[Just netIn, Just netOut] -> pure (netIn, netOut)
_ -> pure (0, 0)
where
fourthLine ls = case drop 3 ls of
l:_ -> l
_ -> T.empty
#else
readProcNetInOut :: IO (Word64, Word64)
readProcNetInOut = (Word64, Word64) -> IO (Word64, Word64)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Word64
0, Word64
0)
#endif
readResourceStatsInternal :: IO (Maybe ResourceStats)
readResourceStatsInternal :: IO (Maybe ResourceStats)
readResourceStatsInternal = do
RTSStats
rts <- IO RTSStats
GhcStats.getRTSStats
(Word64, Word64)
net <- IO (Word64, Word64)
readProcNetInOut
(Word64, Word64)
fs <- IO (Word64, Word64)
readProcBlockInOut
RTSStats
-> (Word64, Word64)
-> (Word64, Word64)
-> [Word64]
-> Maybe ResourceStats
mkProcStats RTSStats
rts (Word64, Word64)
net (Word64, Word64)
fs ([Word64] -> Maybe ResourceStats)
-> ([Integer] -> [Word64]) -> [Integer] -> Maybe ResourceStats
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Integer -> Word64) -> [Integer] -> [Word64]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Integer -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([Integer] -> Maybe ResourceStats)
-> IO [Integer] -> IO (Maybe ResourceStats)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> IO [Integer]
readProcList FilePath
"/proc/self/stat"
where
mkProcStats :: GhcStats.RTSStats -> (Word64, Word64) -> (Word64, Word64) -> [Word64] -> Maybe ResourceStats
mkProcStats :: RTSStats
-> (Word64, Word64)
-> (Word64, Word64)
-> [Word64]
-> Maybe ResourceStats
mkProcStats RTSStats
rts
(Word64
rNetRd, Word64
rNetWr)
(Word64
rFsRd, Word64
rFsWr)
(Word64
_:Word64
_:Word64
_:Word64
_:Word64
_:Word64
_:Word64
_:Word64
_:Word64
_:Word64
_
:Word64
_:Word64
_:Word64
_:Word64
user:Word64
sys:Word64
_:Word64
_:Word64
_:Word64
_:Word64
rThreads
:Word64
_:Word64
_:Word64
_:Word64
rss:Word64
_:Word64
_:Word64
_:Word64
_:Word64
_:Word64
_
:Word64
_:Word64
_:Word64
_:Word64
_:Word64
_:Word64
_:Word64
_:Word64
_:Word64
_:Word64
_
:Word64
_:Word64
rCentiBlkIO:[Word64]
_rest) =
ResourceStats -> Maybe ResourceStats
forall a. a -> Maybe a
Just (ResourceStats -> Maybe ResourceStats)
-> ResourceStats -> Maybe ResourceStats
forall a b. (a -> b) -> a -> b
$ Resources
{ rCentiCpu :: Word64
rCentiCpu = Word64
user Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
sys
, rCentiGC :: Word64
rCentiGC = RtsTime -> Word64
nsToCenti (RtsTime -> Word64) -> RtsTime -> Word64
forall a b. (a -> b) -> a -> b
$ RTSStats -> RtsTime
GhcStats.gc_cpu_ns RTSStats
rts
, rCentiMut :: Word64
rCentiMut = RtsTime -> Word64
nsToCenti (RtsTime -> Word64) -> RtsTime -> Word64
forall a b. (a -> b) -> a -> b
$ RTSStats -> RtsTime
GhcStats.mutator_cpu_ns RTSStats
rts
, rGcsMajor :: Word64
rGcsMajor = Word32 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Word64) -> Word32 -> Word64
forall a b. (a -> b) -> a -> b
$ RTSStats -> Word32
GhcStats.major_gcs RTSStats
rts
, rGcsMinor :: Word64
rGcsMinor = Word32 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Word64) -> Word32 -> Word64
forall a b. (a -> b) -> a -> b
$ RTSStats -> Word32
GhcStats.gcs RTSStats
rts Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
- RTSStats -> Word32
GhcStats.major_gcs RTSStats
rts
, rAlloc :: Word64
rAlloc = RTSStats -> Word64
GhcStats.allocated_bytes RTSStats
rts
, rLive :: Word64
rLive = GCDetails -> Word64
GhcStats.gcdetails_live_bytes (GCDetails -> Word64) -> GCDetails -> Word64
forall a b. (a -> b) -> a -> b
$ RTSStats -> GCDetails
GhcStats.gc RTSStats
rts
, rHeap :: Word64
rHeap = GCDetails -> Word64
GhcStats.gcdetails_mem_in_use_bytes (GCDetails -> Word64) -> GCDetails -> Word64
forall a b. (a -> b) -> a -> b
$ RTSStats -> GCDetails
GhcStats.gc RTSStats
rts
, rRSS :: Word64
rRSS = Word64
rss Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
4096
, Word64
rNetRd :: Word64
rNetWr :: Word64
rFsRd :: Word64
rFsWr :: Word64
rThreads :: Word64
rCentiBlkIO :: Word64
rCentiBlkIO :: Word64
rNetRd :: Word64
rNetWr :: Word64
rFsRd :: Word64
rFsWr :: Word64
rThreads :: Word64
..
}
mkProcStats RTSStats
_ (Word64, Word64)
_ (Word64, Word64)
_ [Word64]
_ = Maybe ResourceStats
forall a. Maybe a
Nothing
nsToCenti :: GhcStats.RtsTime -> Word64
nsToCenti :: RtsTime -> Word64
nsToCenti = Double -> Word64
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor (Double -> Word64) -> (RtsTime -> Double) -> RtsTime -> Word64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ (Double
10000000 :: Double)) (Double -> Double) -> (RtsTime -> Double) -> RtsTime -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RtsTime -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral
readProcList :: FilePath -> IO [Integer]
readProcList :: FilePath -> IO [Integer]
readProcList FilePath
fp = do
FileStatus
fs <- FilePath -> IO FileStatus
getFileStatus FilePath
fp
if FileStatus -> Bool
readable FileStatus
fs
then do
Text
cs <- FilePath -> IO Text
T.readFile FilePath
fp
[Integer] -> IO [Integer]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([Integer] -> IO [Integer]) -> [Integer] -> IO [Integer]
forall a b. (a -> b) -> a -> b
$ (Text -> Integer) -> [Text] -> [Integer]
forall a b. (a -> b) -> [a] -> [b]
map (Integer -> Maybe Integer -> Integer
forall a. a -> Maybe a -> a
fromMaybe Integer
0 (Maybe Integer -> Integer)
-> (Text -> Maybe Integer) -> Text -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Maybe Integer
forall a. Integral a => Text -> Maybe a
readMaybeText) (Text -> [Text]
T.words Text
cs)
else
[Integer] -> IO [Integer]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return []
where
readable :: FileStatus -> Bool
readable FileStatus
fs = FileMode -> FileMode -> FileMode
intersectFileModes (FileStatus -> FileMode
fileMode FileStatus
fs) FileMode
ownerReadMode FileMode -> FileMode -> Bool
forall a. Eq a => a -> a -> Bool
== FileMode
ownerReadMode
readMaybeText :: Integral a => T.Text -> Maybe a
readMaybeText :: forall a. Integral a => Text -> Maybe a
readMaybeText Text
t =
case Reader a
forall a. Integral a => Reader a
T.decimal Text
t of
Right (a
v, Text
_) -> a -> Maybe a
forall a. a -> Maybe a
Just a
v
Either FilePath (a, Text)
_ -> Maybe a
forall a. Maybe a
Nothing