From b2f829d94981f23fdd1eedf4a778f61882c69af2 Mon Sep 17 00:00:00 2001 From: Sibi Prabakaran Date: Sun, 14 Jun 2020 14:14:55 +0530 Subject: More efficient formatting --- src/Xmobar/Plugins/Monitors/Common/Output.hs | 1 + src/Xmobar/Plugins/Monitors/Cpu.hs | 154 +++++++++++++++++++++++---- 2 files changed, 132 insertions(+), 23 deletions(-) diff --git a/src/Xmobar/Plugins/Monitors/Common/Output.hs b/src/Xmobar/Plugins/Monitors/Common/Output.hs index 0ac6e95..a1ece89 100644 --- a/src/Xmobar/Plugins/Monitors/Common/Output.hs +++ b/src/Xmobar/Plugins/Monitors/Common/Output.hs @@ -43,6 +43,7 @@ module Xmobar.Plugins.Monitors.Common.Output ( IconPattern , pShowPercentBar , pShowVerticalBar , pShowIconPattern + , pShowPercentWithColors ) where import Data.Char diff --git a/src/Xmobar/Plugins/Monitors/Cpu.hs b/src/Xmobar/Plugins/Monitors/Cpu.hs index 10881b6..6c2494f 100644 --- a/src/Xmobar/Plugins/Monitors/Cpu.hs +++ b/src/Xmobar/Plugins/Monitors/Cpu.hs @@ -27,7 +27,7 @@ module Xmobar.Plugins.Monitors.Cpu ) where import Xmobar.Plugins.Monitors.Common -import qualified Data.ByteString.Char8 as B +import qualified Data.ByteString.Lazy.Char8 as B import Data.IORef (IORef, newIORef, readIORef, writeIORef) import System.Console.GetOpt import Xmobar.App.Timer (doEveryTenthSeconds) @@ -48,13 +48,51 @@ options = o { loadIconPattern = Just $ parseIconPattern x }) "") "" ] +barField :: String +barField = "bar" + +vbarField :: String +vbarField = "vbar" + +ipatField :: String +ipatField = "ipat" + +totalField :: String +totalField = "total" + +userField :: String +userField = "user" + +niceField :: String +niceField = "nice" + +systemField :: String +systemField = "system" + +idleField :: String +idleField = "idle" + +iowaitField :: String +iowaitField = "iowait" + cpuConfig :: IO MConfig -cpuConfig = mkMConfig - "Cpu: %" - ["bar","vbar","ipat","total","user","nice","system","idle","iowait"] +cpuConfig = + mkMConfig + "Cpu: %" + [ barField + , vbarField + , ipatField + , totalField + , userField + , niceField + , systemField + , idleField + , iowaitField + ] type CpuDataRef = IORef [Int] +-- Details about the fields here: https://www.kernel.org/doc/Documentation/filesystems/proc.txt cpuData :: IO [Int] cpuData = cpuParser <$> B.readFile "/proc/stat" @@ -66,25 +104,93 @@ readInt bs = case B.readInt bs of cpuParser :: B.ByteString -> [Int] cpuParser = map readInt . tail . B.words . head . B.lines -parseCpu :: CpuDataRef -> IO [Float] +data CpuData = CpuData { + cpuUser :: !Float, + cpuNice :: !Float, + cpuSystem :: !Float, + cpuIdle :: !Float, + cpuIowait :: !Float, + cpuTotal :: !Float + } + +convertToCpuData :: [Float] -> CpuData +convertToCpuData (u:n:s:id:iw:_) = CpuData { + cpuUser = u, + cpuNice = n, + cpuSystem = s, + cpuIdle = id, + cpuIowait = iw, + cpuTotal = sum [u,n,s] + } +convertToCpuData args = error $ "convertToCpuData: Unexpected list" <> show args + + +parseCpu :: CpuDataRef -> IO CpuData parseCpu cref = do a <- readIORef cref b <- cpuData writeIORef cref b let dif = zipWith (-) b a tot = fromIntegral $ sum dif - percent = map ((/ tot) . fromIntegral) dif - return percent - -formatCpu :: CpuOpts -> [Float] -> PureConfig -> IO [String] -formatCpu _ [] _ = return $ replicate 8 "" -formatCpu opts xs p = do - let t = sum $ take 3 xs - b <- pShowPercentBar p (100 * t) t - v <- pShowVerticalBar p (100 * t) t - d <- pShowIconPattern (loadIconPattern opts) t - ps <- pShowPercentsWithColors p (t:xs) - return $ (b:v:d:ps) + safeDiv n = case tot of + 0 -> 0 + v -> (fromIntegral n) / v + percent = map safeDiv dif + return $ convertToCpuData percent + +conditionalCompute :: [String] -> String -> IO String -> IO String +conditionalCompute allFields field action = if field `elem` allFields + then action + else pure [] + + +data Field = Field { + fieldName :: !String, + fieldCompute :: !ShouldCompute + } deriving (Eq, Ord, Show) + +data ShouldCompute = Compute | Skip deriving (Eq, Ord, Show) + +formatField :: PureConfig -> CpuOpts -> CpuData -> Field -> IO String +formatField cpuParams cpuOpts cpuInfo@CpuData{..} Field{..} + | fieldName == barField = if fieldCompute == Compute + then pShowPercentBar cpuParams (100 * cpuTotal) cpuTotal + else pure [] + | fieldName == vbarField = if fieldCompute == Compute + then pShowVerticalBar cpuParams (100 * cpuTotal) cpuTotal + else pure [] + | fieldName == ipatField = if fieldCompute == Compute + then pShowIconPattern (loadIconPattern cpuOpts) cpuTotal + else pure [] + | otherwise = if fieldCompute == Compute + then pShowPercentWithColors cpuParams (getFieldValue fieldName cpuInfo) + else pure [] + +getFieldValue :: String -> CpuData -> Float +getFieldValue field CpuData{..} + | field == barField = cpuTotal + | field == vbarField = cpuTotal + | field == ipatField = cpuTotal + | field == totalField = cpuTotal + | field == userField = cpuUser + | field == niceField = cpuNice + | field == systemField = cpuSystem + | field == idleField = cpuIdle + | otherwise = cpuIowait + +computeFields :: [String] -> [String] -> [Field] +computeFields [] _ = [] +computeFields (x:xs) inputFields = + if x `elem` inputFields + then (Field {fieldName = x, fieldCompute = Compute}) : + (computeFields xs inputFields) + else (Field {fieldName = x, fieldCompute = Skip}) : (computeFields xs inputFields) + +formatCpu :: CpuArguments -> CpuData -> IO [String] +formatCpu args@CpuArguments{..} cpuData = mapM (formatField cpuParams cpuOpts cpuData) cpuFields + +getInputFields :: CpuArguments -> [String] +getInputFields CpuArguments{..} = map (\(_,f,_) -> f) cpuInputTemplate data CpuArguments = CpuArguments { cpuDataRef :: !CpuDataRef, @@ -92,12 +198,15 @@ data CpuArguments = CpuArguments { cpuArgs :: ![String], cpuOpts :: !CpuOpts, cpuInputTemplate :: ![(String, String, String)], -- [("Cpu: ","total","% "),("","user","%")] - cpuAllTemplate :: ![(String, [(String, String, String)])] -- [("bar",[]),("vbar",[]),("ipat",[]),("total",[]),...] + cpuAllTemplate :: ![(String, [(String, String, String)])], -- [("bar",[]),("vbar",[]),("ipat",[]),("total",[]),...] + cpuFields :: ![Field] } getArguments :: [String] -> IO CpuArguments getArguments cpuArgs = do - cpuDataRef <- newIORef [] + initCpuData <- cpuData + cpuDataRef <- newIORef initCpuData + cpuData <- parseCpu cpuDataRef cpuParams <- computePureConfig cpuArgs cpuConfig cpuInputTemplate <- runTemplateParser cpuParams cpuAllTemplate <- runExportParser (pExport cpuParams) @@ -107,19 +216,18 @@ getArguments cpuArgs = do cpuOpts <- case getOpt Permute options nonOptions of (o, _, []) -> pure $ foldr id defaultOpts o (_,_,errs) -> error $ "getArguments options: " <> show errs + let cpuFields = computeFields (map fst cpuAllTemplate) (map (\(_,f,_) -> f) cpuInputTemplate) pure CpuArguments{..} runCpu :: CpuArguments -> IO String -runCpu CpuArguments{..} = do +runCpu args@CpuArguments{..} = do cpuValue <- parseCpu cpuDataRef - temMonitorValues <- formatCpu cpuOpts cpuValue cpuParams + temMonitorValues <- formatCpu args cpuValue let templateInput = TemplateInput { temInputTemplate = cpuInputTemplate, temAllTemplate = cpuAllTemplate, ..} pureParseTemplate cpuParams templateInput startCpu :: [String] -> Int -> (String -> IO ()) -> IO () startCpu args refreshRate cb = do - cref <- newIORef [] - void $ parseCpu cref cpuArgs <- getArguments args doEveryTenthSeconds refreshRate (runCpu cpuArgs >>= cb) -- cgit v1.2.3