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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
-----------------------------------------------------------------------------
-- |
-- Module : Plugins.Monitors.MultiCpu
-- Copyright : (c) Jose A Ortega Ruiz
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Jose A Ortega <jao@gnu.org>
-- Stability : unstable
-- Portability : unportable
--
-- A multi-cpu monitor for Xmobar
--
-----------------------------------------------------------------------------
module Xmobar.Plugins.Monitors.MultiCpu (startMultiCpu) where
import Xmobar.Plugins.Monitors.Common
import qualified Data.ByteString.Lazy.Char8 as B
import Data.List (isPrefixOf, transpose, unfoldr)
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import System.Console.GetOpt
data MultiCpuOpts = MultiCpuOpts
{ loadIconPatterns :: [IconPattern]
, loadIconPattern :: Maybe IconPattern
, fallbackIconPattern :: Maybe IconPattern
, contiguous :: Bool
}
defaultOpts :: MultiCpuOpts
defaultOpts = MultiCpuOpts
{ loadIconPatterns = []
, loadIconPattern = Nothing
, fallbackIconPattern = Nothing
, contiguous = False
}
options :: [OptDescr (MultiCpuOpts -> MultiCpuOpts)]
options =
[ Option "" ["load-icon-pattern"] (ReqArg (\x o ->
o { loadIconPattern = Just $ parseIconPattern x }) "") ""
, Option "" ["load-icon-patterns"] (ReqArg (\x o ->
o { loadIconPatterns = parseIconPattern x : loadIconPatterns o }) "") ""
, Option "" ["fallback-icon-pattern"] (ReqArg (\x o ->
o { fallbackIconPattern = Just $ parseIconPattern x }) "") ""
, Option "" ["contiguous-icons"] (NoArg (\o -> o {contiguous = True})) ""
]
variables :: [String]
variables = ["bar", "vbar","ipat","total","user","nice","system","idle"]
vNum :: Int
vNum = length variables
multiCpuConfig :: IO MConfig
multiCpuConfig =
mkMConfig "Cpu: <total>%" $
["auto" ++ k | k <- variables] ++
[ k ++ n | n <- "" : map show [0 :: Int ..]
, k <- variables]
type CpuDataRef = IORef [[Int]]
cpuData :: IO [[Int]]
cpuData = parse `fmap` B.readFile "/proc/stat"
where parse = map parseList . cpuLists
cpuLists = takeWhile isCpu . map B.words . B.lines
isCpu (w:_) = "cpu" `isPrefixOf` B.unpack w
isCpu _ = False
parseList = map (parseInt . B.unpack) . tail
parseCpuData :: CpuDataRef -> IO [[Float]]
parseCpuData cref =
do as <- readIORef cref
bs <- cpuData
writeIORef cref bs
let p0 = zipWith percent bs as
return p0
percent :: [Int] -> [Int] -> [Float]
percent b a = if tot > 0 then map (/ tot) $ take 4 dif else [0, 0, 0, 0]
where dif = map fromIntegral $ zipWith (-) b a
tot = sum dif
formatMultiCpus :: MultiCpuOpts -> [[Float]] -> Monitor [String]
formatMultiCpus _ [] = return []
formatMultiCpus opts xs =
concat <$> mapM (\(i, x) -> formatCpu opts i x) (zip [0..] xs)
formatCpu :: MultiCpuOpts -> Int -> [Float] -> Monitor [String]
formatCpu opts i xs
| length xs < 4 = showPercentsWithColors $ replicate vNum 0.0
| otherwise = let t = sum $ take 3 xs
in do b <- showPercentBar (100 * t) t
h <- showVerticalBar (100 * t) t
d <- showIconPattern tryString t
ps <- showPercentsWithColors (t:xs)
return (b:h:d:ps)
where tryString
| i == 0 = loadIconPattern opts
| i <= length (loadIconPatterns opts) =
Just $ loadIconPatterns opts !! (i - 1)
| otherwise = fallbackIconPattern opts
splitEvery :: Int -> [a] -> [[a]]
splitEvery n = unfoldr (\x -> if null x then Nothing else Just $ splitAt n x)
groupData :: [String] -> [[String]]
groupData = transpose . tail . splitEvery vNum
formatAutoCpus :: MultiCpuOpts -> [String] -> Monitor [String]
formatAutoCpus _ [] = return $ replicate vNum ""
formatAutoCpus opts xs =
return $ map (if contiguous opts then concat else unwords) (groupData xs)
runMultiCpu :: CpuDataRef -> [String] -> Monitor String
runMultiCpu cref argv =
do c <- io $ parseCpuData cref
opts <- io $ parseOptsWith options defaultOpts argv
l <- formatMultiCpus opts c
a <- formatAutoCpus opts l
parseTemplate $ a ++ l
startMultiCpu :: [String] -> Int -> (String -> IO ()) -> IO ()
startMultiCpu a r cb = do
cref <- newIORef [[]]
_ <- parseCpuData cref
runM a multiCpuConfig (runMultiCpu cref) r cb
|