Parse /proc/stat data as Integer
authorKlaus Aehlig <aehlig@google.com>
Tue, 26 Jan 2016 13:17:59 +0000 (14:17 +0100)
committerKlaus Aehlig <aehlig@google.com>
Wed, 27 Jan 2016 18:37:18 +0000 (19:37 +0100)
Values output by /proc/stat are total values of time since the last reboot,
in ticks that usually are 0.01s; so after roughly 250 CPU-days, the total
time can no longer be represented as a 32-bit signed integer. Note that this
can actually happen on a node with a high enough number of CPUs or long enough
uptime. Therefore, take Integer as data type, to avoid being hit by overflows.

Signed-off-by: Klaus Aehlig <aehlig@google.com>
Reviewed-by: Lisa Velden <velden@google.com>

src/Ganeti/Cpu/LoadParser.hs
src/Ganeti/Cpu/Types.hs
src/Ganeti/DataCollectors/CPUload.hs
src/Ganeti/DataCollectors/Types.hs

index c321101..e2ffa01 100644 (file)
@@ -53,16 +53,16 @@ import Ganeti.Cpu.Types
 oneCPUstatParser :: Parser CPUstat
 oneCPUstatParser =
   let nameP = stringP
-      userP = numberP
-      niceP = numberP
-      systemP = numberP
-      idleP = numberP
-      iowaitP = numberP
-      irqP = numberP
-      softirqP = numberP
-      stealP = numberP
-      guestP = numberP
-      guest_niceP = numberP
+      userP = integerP
+      niceP = integerP
+      systemP = integerP
+      idleP = integerP
+      iowaitP = integerP
+      irqP = integerP
+      softirqP = integerP
+      stealP = integerP
+      guestP = integerP
+      guest_niceP = integerP
   in
     CPUstat <$> nameP <*> userP <*> niceP <*> systemP <*> idleP <*> iowaitP
             <*> irqP <*> softirqP <*> stealP <*> guestP <*> guest_niceP
index 9fc31ef..5786435 100644 (file)
@@ -61,14 +61,14 @@ emptyCPUavgload = CPUavgload { cavCpuNumber = 1
 -- | This is the format of the data parsed by the input file.
 $(buildObject "CPUstat" "cs"
   [ simpleField "name"       [t| String |]
-  , simpleField "user"       [t| Int |]
-  , simpleField "nice"       [t| Int |]
-  , simpleField "system"     [t| Int |]
-  , simpleField "idle"       [t| Int |]
-  , simpleField "iowait"     [t| Int |]
-  , simpleField "irq"        [t| Int |]
-  , simpleField "softirq"    [t| Int |]
-  , simpleField "steal"      [t| Int |]
-  , simpleField "guest"      [t| Int |]
-  , simpleField "guest_nice" [t| Int |]
+  , simpleField "user"       [t| Integer |]
+  , simpleField "nice"       [t| Integer |]
+  , simpleField "system"     [t| Integer |]
+  , simpleField "idle"       [t| Integer |]
+  , simpleField "iowait"     [t| Integer |]
+  , simpleField "irq"        [t| Integer |]
+  , simpleField "softirq"    [t| Integer |]
+  , simpleField "steal"      [t| Integer |]
+  , simpleField "guest"      [t| Integer |]
+  , simpleField "guest_nice" [t| Integer |]
   ])
index ed13bde..1fe2fd7 100644 (file)
@@ -5,7 +5,7 @@
 
 {-
 
-Copyright (C) 2013 Google Inc.
+Copyright (C) 2013, 2016 Google Inc.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -111,17 +111,17 @@ dcReport colData =
   in buildDCReport cpuLoadData
 
 -- | Data stored by the collector in mond's memory.
-type Buffer = Seq.Seq (ClockTime, [Int])
+type Buffer = Seq.Seq (ClockTime, [Integer])
 
 -- | Compute the load from a CPU.
-computeLoad :: CPUstat -> Int
+computeLoad :: CPUstat -> Integer
 computeLoad cpuData =
   csUser cpuData + csNice cpuData + csSystem cpuData
   + csIowait cpuData + csIrq cpuData + csSoftirq cpuData
   + csSteal cpuData + csGuest cpuData + csGuestNice cpuData
 
 -- | Reads and Computes the load for each CPU.
-dcCollectFromFile :: FilePath -> IO (ClockTime, [Int])
+dcCollectFromFile :: FilePath -> IO (ClockTime, [Integer])
 dcCollectFromFile inputFile = do
   contents <-
     ((E.try $ readFile inputFile) :: IO (Either IOError String)) >>=
@@ -175,7 +175,7 @@ computeAverage s w ticks =
             (timestampR, listR) = rightmost
             workInWindow = zipWith (-) listL listR
             timediff = timestampL - timestampR
-            overall = fromInteger (timediff * ticks) / 1000000 :: Double
+            overall = fromIntegral (timediff * ticks) / 1000000 :: Double
         if overall > 0
           then BT.Ok $ map (flip (/) overall . fromIntegral) workInWindow
           else BT.Bad $ "Time covered by data is not sufficient."
index 3bd31b3..20386ce 100644 (file)
@@ -145,7 +145,7 @@ instance JSON DCVersion where
 
 -- | Type for the value field of the `CollectorMap` below.
 data CollectorData =
-  CPULoadData (Seq.Seq (ClockTime, [Int]))
+  CPULoadData (Seq.Seq (ClockTime, [Integer]))
   | InstanceCpuLoad (Map.Map String (Seq.Seq (ClockTime, Double)))
 
 instance NFData ClockTime where