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
|
-----------------------------------------------------------------------------
-- |
-- Module : Plugins.Monitors.Top.Linux
-- Copyright : (c) 2010, 2011, 2012, 2013, 2014, 2018 Jose A Ortega Ruiz
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Jose A Ortega Ruiz <jao@gnu.org>
-- Stability : unstable
-- Portability : unportable
--
-- Process activity and memory consumption monitors
--
-----------------------------------------------------------------------------
{-# LANGUAGE ForeignFunctionInterface #-}
module Xmobar.Plugins.Monitors.Top.Linux (
timeMemEntries
, meminfos
, scale) where
import Xmobar.Plugins.Monitors.Common (parseFloat, parseInt)
import Xmobar.Plugins.Monitors.Top.Common (MemInfo, TimeEntry)
import Control.Exception (SomeException, handle)
import Data.List (foldl')
import System.Directory (getDirectoryContents)
import System.FilePath ((</>))
import System.IO (IOMode(ReadMode), hGetLine, withFile)
import System.Posix.Unistd (SysVar(ClockTick), getSysVar)
import Foreign.C.Types
foreign import ccall "unistd.h getpagesize"
c_getpagesize :: CInt
pageSize :: Float
pageSize = fromIntegral c_getpagesize / 1024
processes :: IO [FilePath]
processes = fmap (filter isPid) (getDirectoryContents "/proc")
where isPid = (`elem` ['0'..'9']) . head
statWords :: [String] -> [String]
statWords line@(x:pn:ppn:xs) =
if last pn == ')' then line else statWords (x:(pn ++ " " ++ ppn):xs)
statWords _ = replicate 52 "0"
getProcessData :: FilePath -> IO [String]
getProcessData pidf =
handle ign $ withFile ("/proc" </> pidf </> "stat") ReadMode readWords
where readWords = fmap (statWords . words) . hGetLine
ign = const (return []) :: SomeException -> IO [String]
memPages :: [String] -> String
memPages fs = fs!!23
ppid :: [String] -> String
ppid fs = fs!!3
skip :: [String] -> Bool
skip fs = length fs < 24 || memPages fs == "0" || ppid fs == "0"
handleProcesses :: ([String] -> a) -> IO [a]
handleProcesses f =
fmap (foldl' (\a p -> if skip p then a else f p : a) [])
(processes >>= mapM getProcessData)
processName :: [String] -> String
processName = drop 1 . init . (!!1)
meminfo :: [String] -> MemInfo
meminfo fs = (processName fs, pageSize * parseFloat (fs!!23))
meminfos :: IO [MemInfo]
meminfos = handleProcesses meminfo
timeMemEntry :: [String] -> (TimeEntry, MemInfo)
timeMemEntry fs = ((p, (n, t)), (n, r))
where p = parseInt (head fs)
n = processName fs
t = parseFloat (fs!!13) + parseFloat (fs!!14)
(_, r) = meminfo fs
timeMemEntries :: IO [(TimeEntry, MemInfo)]
timeMemEntries = handleProcesses timeMemEntry
scale :: IO Float
scale = do
cr <- getSysVar ClockTick
return $ fromIntegral cr / 100
|