summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorTomas Janousek <tomi@nomi.cz>2017-01-23 14:40:20 +0100
committerTomas Janousek <tomi@nomi.cz>2017-01-23 14:53:43 +0100
commit94b74da9de8d79d74769c7937ef9c969d89ba42f (patch)
treec9b35cc193ed2fa8c81dd03fb1bfb8a0a9b22624
parent9caa2668a0f32af600f0d5183058477b00ff977f (diff)
downloadxmobar-94b74da9de8d79d74769c7937ef9c969d89ba42f.tar.gz
xmobar-94b74da9de8d79d74769c7937ef9c969d89ba42f.tar.bz2
Fix Net monitor for large uptimes/bytecounts
My laptop currently has rx/tx bytes in 10s of gigabytes and it's only been up for 20 days. Normally it's several times more. At this point, Float can only tell the difference of 4KB and up: Prelude> let x = (50 * 2^30 :: Float) in (x + 2000) - x 0.0 Prelude> let x = (50 * 2^30 :: Float) in (x + 3000) - x 4096.0 This commit makes the Net monitor read Word64 which is exactly what the kernel prints into /proc/net/dev [1] and converts to Float only after subtracting the two numbers. [1] https://github.com/torvalds/linux/blob/7a308bb3016f57e5be11a677d15b821536419d36/net/core/net-procfs.c#L82 Still, I think it's time to switch from Float to Double. At half-gigabit speeds (easily attainable at home while rsyncing over a direct UTP cable between two post-2010 laptops), Float can only tell the difference of 8 bytes and up (and I'm not even considering takeDigits!). That's probably okay for a Net monitor in xmobar, but we're so close to the limit it makes sense to move to Double just in case.
-rw-r--r--src/Plugins/Monitors/Net.hs29
1 files changed, 17 insertions, 12 deletions
diff --git a/src/Plugins/Monitors/Net.hs b/src/Plugins/Monitors/Net.hs
index 5954a77..7df8889 100644
--- a/src/Plugins/Monitors/Net.hs
+++ b/src/Plugins/Monitors/Net.hs
@@ -20,6 +20,7 @@ module Plugins.Monitors.Net (
import Plugins.Monitors.Common
+import Data.Word (Word64)
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import Data.Time.Clock (UTCTime, getCurrentTime, diffUTCTime)
import Control.Monad (forM, filterM, liftM)
@@ -63,16 +64,20 @@ instance Show UnitPerSec where
show MBs = "MB/s"
show GBs = "GB/s"
-data NetDev = NA
- | NI String
- | ND String Float Float deriving (Eq,Show,Read)
+data NetDev num
+ = NA
+ | NI String
+ | ND String num num deriving (Eq,Show,Read)
-type NetDevRef = IORef (NetDev, UTCTime)
+type NetDevRawTotal = NetDev Word64
+type NetDevRate = NetDev Float
+
+type NetDevRef = IORef (NetDevRawTotal, UTCTime)
-- The more information available, the better.
-- Note that names don't matter. Therefore, if only the names differ,
-- a compare evaluates to EQ while (==) evaluates to False.
-instance Ord NetDev where
+instance Ord num => Ord (NetDev num) where
compare NA NA = EQ
compare NA _ = LT
compare _ NA = GT
@@ -104,7 +109,7 @@ isUp d = do
operstate <- B.readFile (operstateDir d)
return $ (B.unpack . head . B.lines) operstate `elem` ["up", "unknown"]
-readNetDev :: [String] -> IO NetDev
+readNetDev :: [String] -> IO NetDevRawTotal
readNetDev (d:x:y:_) = do
up <- isUp d
return (if up then ND d (r x) (r y) else NI d)
@@ -113,7 +118,7 @@ readNetDev (d:x:y:_) = do
readNetDev _ = return NA
-netParser :: B.ByteString -> IO [NetDev]
+netParser :: B.ByteString -> IO [NetDevRawTotal]
netParser = mapM (readNetDev . splitDevLine) . readDevLines
where readDevLines = drop 2 . B.lines
splitDevLine = selectCols . wordsBy (`elem` " :") . B.unpack
@@ -122,7 +127,7 @@ netParser = mapM (readNetDev . splitDevLine) . readDevLines
[] -> []
s' -> w : wordsBy f s'' where (w, s'') = break f s'
-findNetDev :: String -> IO NetDev
+findNetDev :: String -> IO NetDevRawTotal
findNetDev dev = do
nds <- B.readFile "/proc/net/dev" >>= netParser
case filter isDev nds of
@@ -145,7 +150,7 @@ formatNet mipat d = do
x <- showWithColors (str s) d
return (x, b, vb, ipat)
-printNet :: NetOpts -> NetDev -> Monitor String
+printNet :: NetOpts -> NetDevRate -> Monitor String
printNet opts nd =
case nd of
ND d r t -> do
@@ -155,7 +160,7 @@ printNet opts nd =
NI _ -> return ""
NA -> getConfigValue naString
-parseNet :: NetDevRef -> String -> IO NetDev
+parseNet :: NetDevRef -> String -> IO NetDevRate
parseNet nref nd = do
(n0, t0) <- readIORef nref
n1 <- findNetDev nd
@@ -163,7 +168,7 @@ parseNet nref nd = do
writeIORef nref (n1, t1)
let scx = realToFrac (diffUTCTime t1 t0)
scx' = if scx > 0 then scx else 1
- rate da db = takeDigits 2 $ (db - da) / scx'
+ rate da db = takeDigits 2 $ fromIntegral (db - da) / scx'
diffRate (ND d ra ta) (ND _ rb tb) = ND d (rate ra rb) (rate ta tb)
diffRate (NI d) _ = NI d
diffRate _ (NI d) = NI d
@@ -176,7 +181,7 @@ runNet nref i argv = do
opts <- io $ parseOpts argv
printNet opts dev
-parseNets :: [(NetDevRef, String)] -> IO [NetDev]
+parseNets :: [(NetDevRef, String)] -> IO [NetDevRate]
parseNets = mapM $ uncurry parseNet
runNets :: [(NetDevRef, String)] -> [String] -> Monitor String