Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / DataCollectors / CPUload.hs @ 07e68848

History | View | Annotate | Download (5.8 kB)

1 2da679f7 Spyros Trigazis
{-| @/proc/stat@ data collector.
2 2da679f7 Spyros Trigazis
3 2da679f7 Spyros Trigazis
-}
4 2da679f7 Spyros Trigazis
5 2da679f7 Spyros Trigazis
{-
6 2da679f7 Spyros Trigazis
7 2da679f7 Spyros Trigazis
Copyright (C) 2013 Google Inc.
8 2da679f7 Spyros Trigazis
9 2da679f7 Spyros Trigazis
This program is free software; you can redistribute it and/or modify
10 2da679f7 Spyros Trigazis
it under the terms of the GNU General Public License as published by
11 2da679f7 Spyros Trigazis
the Free Software Foundation; either version 2 of the License, or
12 2da679f7 Spyros Trigazis
(at your option) any later version.
13 2da679f7 Spyros Trigazis
14 2da679f7 Spyros Trigazis
This program is distributed in the hope that it will be useful, but
15 2da679f7 Spyros Trigazis
WITHOUT ANY WARRANTY; without even the implied warranty of
16 2da679f7 Spyros Trigazis
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 2da679f7 Spyros Trigazis
General Public License for more details.
18 2da679f7 Spyros Trigazis
19 2da679f7 Spyros Trigazis
You should have received a copy of the GNU General Public License
20 2da679f7 Spyros Trigazis
along with this program; if not, write to the Free Software
21 2da679f7 Spyros Trigazis
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 2da679f7 Spyros Trigazis
02110-1301, USA.
23 2da679f7 Spyros Trigazis
24 2da679f7 Spyros Trigazis
-}
25 2da679f7 Spyros Trigazis
26 2da679f7 Spyros Trigazis
module Ganeti.DataCollectors.CPUload
27 2da679f7 Spyros Trigazis
  ( dcName
28 2da679f7 Spyros Trigazis
  , dcVersion
29 2da679f7 Spyros Trigazis
  , dcFormatVersion
30 2da679f7 Spyros Trigazis
  , dcCategory
31 2da679f7 Spyros Trigazis
  , dcKind
32 2da679f7 Spyros Trigazis
  , dcReport
33 2da679f7 Spyros Trigazis
  , dcUpdate
34 2da679f7 Spyros Trigazis
  ) where
35 2da679f7 Spyros Trigazis
36 2da679f7 Spyros Trigazis
import qualified Control.Exception as E
37 2da679f7 Spyros Trigazis
import Data.Attoparsec.Text.Lazy as A
38 2da679f7 Spyros Trigazis
import Data.Text.Lazy (pack, unpack)
39 2da679f7 Spyros Trigazis
import qualified Text.JSON as J
40 2da679f7 Spyros Trigazis
import qualified Data.Sequence as Seq
41 798582cf Spyros Trigazis
import System.Posix.Unistd (getSysVar, SysVar(ClockTick))
42 2da679f7 Spyros Trigazis
43 2da679f7 Spyros Trigazis
import qualified Ganeti.BasicTypes as BT
44 2da679f7 Spyros Trigazis
import qualified Ganeti.Constants as C
45 2da679f7 Spyros Trigazis
import Ganeti.Cpu.LoadParser(cpustatParser)
46 2da679f7 Spyros Trigazis
import Ganeti.DataCollectors.Types
47 2da679f7 Spyros Trigazis
import Ganeti.Utils
48 2da679f7 Spyros Trigazis
import Ganeti.Cpu.Types
49 2da679f7 Spyros Trigazis
50 2da679f7 Spyros Trigazis
-- | The default path of the CPU status file.
51 2da679f7 Spyros Trigazis
-- It is hardcoded because it is not likely to change.
52 2da679f7 Spyros Trigazis
defaultFile :: FilePath
53 2da679f7 Spyros Trigazis
defaultFile = C.statFile
54 2da679f7 Spyros Trigazis
55 2da679f7 Spyros Trigazis
-- | The buffer size of the values kept in the map.
56 2da679f7 Spyros Trigazis
bufferSize :: Int
57 2da679f7 Spyros Trigazis
bufferSize = C.cpuavgloadBufferSize
58 2da679f7 Spyros Trigazis
59 2da679f7 Spyros Trigazis
-- | The window size of the values that will export the average load.
60 2da679f7 Spyros Trigazis
windowSize :: Integer
61 2da679f7 Spyros Trigazis
windowSize = toInteger C.cpuavgloadWindowSize
62 2da679f7 Spyros Trigazis
63 2da679f7 Spyros Trigazis
-- | The default setting for the maximum amount of not parsed character to
64 2da679f7 Spyros Trigazis
-- print in case of error.
65 2da679f7 Spyros Trigazis
-- It is set to use most of the screen estate on a standard 80x25 terminal.
66 2da679f7 Spyros Trigazis
-- TODO: add the possibility to set this with a command line parameter.
67 2da679f7 Spyros Trigazis
defaultCharNum :: Int
68 2da679f7 Spyros Trigazis
defaultCharNum = 80*20
69 2da679f7 Spyros Trigazis
70 2da679f7 Spyros Trigazis
-- | The name of this data collector.
71 2da679f7 Spyros Trigazis
dcName :: String
72 2da679f7 Spyros Trigazis
dcName = "cpu-avg-load"
73 2da679f7 Spyros Trigazis
74 2da679f7 Spyros Trigazis
-- | The version of this data collector.
75 2da679f7 Spyros Trigazis
dcVersion :: DCVersion
76 2da679f7 Spyros Trigazis
dcVersion = DCVerBuiltin
77 2da679f7 Spyros Trigazis
78 2da679f7 Spyros Trigazis
-- | The version number for the data format of this data collector.
79 2da679f7 Spyros Trigazis
dcFormatVersion :: Int
80 2da679f7 Spyros Trigazis
dcFormatVersion = 1
81 2da679f7 Spyros Trigazis
82 2da679f7 Spyros Trigazis
-- | The category of this data collector.
83 2da679f7 Spyros Trigazis
dcCategory :: Maybe DCCategory
84 2da679f7 Spyros Trigazis
dcCategory = Nothing
85 2da679f7 Spyros Trigazis
86 2da679f7 Spyros Trigazis
-- | The kind of this data collector.
87 2da679f7 Spyros Trigazis
dcKind :: DCKind
88 2da679f7 Spyros Trigazis
dcKind = DCKPerf
89 2da679f7 Spyros Trigazis
90 2da679f7 Spyros Trigazis
-- | The data exported by the data collector, taken from the default location.
91 2da679f7 Spyros Trigazis
dcReport :: Maybe CollectorData -> IO DCReport
92 2da679f7 Spyros Trigazis
dcReport colData =
93 2da679f7 Spyros Trigazis
  let cpuLoadData =
94 2da679f7 Spyros Trigazis
        case colData of
95 2da679f7 Spyros Trigazis
          Nothing -> Seq.empty
96 2da679f7 Spyros Trigazis
          Just colData' ->
97 2da679f7 Spyros Trigazis
            case colData' of
98 2da679f7 Spyros Trigazis
              CPULoadData v -> v
99 2da679f7 Spyros Trigazis
  in buildDCReport cpuLoadData
100 2da679f7 Spyros Trigazis
-- | Data stored by the collector in mond's memory.
101 2da679f7 Spyros Trigazis
type Buffer = Seq.Seq (Integer, [Int])
102 2da679f7 Spyros Trigazis
103 2da679f7 Spyros Trigazis
-- | Compute the load from a CPU.
104 2da679f7 Spyros Trigazis
computeLoad :: CPUstat -> Int
105 2da679f7 Spyros Trigazis
computeLoad cpuData =
106 2da679f7 Spyros Trigazis
  csUser cpuData + csNice cpuData + csSystem cpuData
107 2da679f7 Spyros Trigazis
  + csIowait cpuData + csIrq cpuData + csSoftirq cpuData
108 2da679f7 Spyros Trigazis
  + csSteal cpuData + csGuest cpuData + csGuestNice cpuData
109 2da679f7 Spyros Trigazis
110 2da679f7 Spyros Trigazis
-- | Reads and Computes the load for each CPU.
111 2da679f7 Spyros Trigazis
dcCollectFromFile :: FilePath -> IO (Integer, [Int])
112 2da679f7 Spyros Trigazis
dcCollectFromFile inputFile = do
113 2da679f7 Spyros Trigazis
  contents <-
114 2da679f7 Spyros Trigazis
    ((E.try $ readFile inputFile) :: IO (Either IOError String)) >>=
115 2da679f7 Spyros Trigazis
      exitIfBad "reading from file" . either (BT.Bad . show) BT.Ok
116 2da679f7 Spyros Trigazis
  cpustatData <-
117 2da679f7 Spyros Trigazis
    case A.parse cpustatParser $ pack contents of
118 2da679f7 Spyros Trigazis
      A.Fail unparsedText contexts errorMessage -> exitErr $
119 2da679f7 Spyros Trigazis
        show (Prelude.take defaultCharNum $ unpack unparsedText) ++ "\n"
120 2da679f7 Spyros Trigazis
          ++ show contexts ++ "\n" ++ errorMessage
121 2da679f7 Spyros Trigazis
      A.Done _ cpustatD -> return cpustatD
122 2da679f7 Spyros Trigazis
  now <- getCurrentTime
123 2da679f7 Spyros Trigazis
  let timestamp = now :: Integer
124 2da679f7 Spyros Trigazis
  return (timestamp, map computeLoad cpustatData)
125 2da679f7 Spyros Trigazis
126 2da679f7 Spyros Trigazis
-- | Returns the collected data in the appropriate type.
127 2da679f7 Spyros Trigazis
dcCollect :: IO Buffer
128 2da679f7 Spyros Trigazis
dcCollect  = do
129 2da679f7 Spyros Trigazis
  l <- dcCollectFromFile defaultFile
130 2da679f7 Spyros Trigazis
  return (Seq.singleton l)
131 2da679f7 Spyros Trigazis
132 2da679f7 Spyros Trigazis
-- | Formats data for JSON transformation.
133 2da679f7 Spyros Trigazis
formatData :: [Double] -> CPUavgload
134 2da679f7 Spyros Trigazis
formatData [] = CPUavgload (0 :: Int) [] (0 :: Double)
135 2da679f7 Spyros Trigazis
formatData l@(x:xs) = CPUavgload (length l - 1) xs x
136 2da679f7 Spyros Trigazis
137 2da679f7 Spyros Trigazis
-- | Update a Map Entry.
138 2da679f7 Spyros Trigazis
updateEntry :: Buffer -> Buffer -> Buffer
139 2da679f7 Spyros Trigazis
updateEntry newBuffer mapEntry =
140 2da679f7 Spyros Trigazis
  (Seq.><) newBuffer
141 2da679f7 Spyros Trigazis
  (if Seq.length mapEntry < bufferSize
142 2da679f7 Spyros Trigazis
    then mapEntry
143 2da679f7 Spyros Trigazis
    else Seq.drop 1 mapEntry)
144 2da679f7 Spyros Trigazis
145 2da679f7 Spyros Trigazis
-- | Updates the given Collector data.
146 2da679f7 Spyros Trigazis
dcUpdate :: Maybe CollectorData -> IO CollectorData
147 2da679f7 Spyros Trigazis
dcUpdate mcd = do
148 2da679f7 Spyros Trigazis
  v <- dcCollect
149 2da679f7 Spyros Trigazis
  let new_v =
150 2da679f7 Spyros Trigazis
        case mcd of
151 2da679f7 Spyros Trigazis
          Nothing -> v
152 2da679f7 Spyros Trigazis
          Just cd ->
153 2da679f7 Spyros Trigazis
            case cd of
154 2da679f7 Spyros Trigazis
              CPULoadData old_v -> updateEntry v old_v
155 2da679f7 Spyros Trigazis
  new_v `seq` return $ CPULoadData new_v
156 2da679f7 Spyros Trigazis
157 2da679f7 Spyros Trigazis
-- | Computes the average load for every CPU and the overall from data read
158 2da679f7 Spyros Trigazis
-- from the map.
159 798582cf Spyros Trigazis
computeAverage :: Buffer -> Integer -> Integer -> [Double]
160 798582cf Spyros Trigazis
computeAverage s w ticks =
161 2da679f7 Spyros Trigazis
  let window = Seq.takeWhileL ((> w) . fst) s
162 2da679f7 Spyros Trigazis
      go Seq.EmptyL          _                    = []
163 2da679f7 Spyros Trigazis
      go _                   Seq.EmptyR           = []
164 2da679f7 Spyros Trigazis
      go (leftmost Seq.:< _) (_ Seq.:> rightmost) = do
165 2da679f7 Spyros Trigazis
        let (timestampL, listL) = leftmost
166 2da679f7 Spyros Trigazis
            (timestampR, listR) = rightmost
167 2da679f7 Spyros Trigazis
            work = zipWith (-) listL listR
168 798582cf Spyros Trigazis
            overall = (timestampL - timestampR) * ticks
169 2da679f7 Spyros Trigazis
        map (\x -> fromIntegral x / fromIntegral overall) work
170 2da679f7 Spyros Trigazis
  in go (Seq.viewl window) (Seq.viewr window)
171 2da679f7 Spyros Trigazis
172 2da679f7 Spyros Trigazis
-- | This function computes the JSON representation of the CPU load.
173 2da679f7 Spyros Trigazis
buildJsonReport :: Buffer -> IO J.JSValue
174 798582cf Spyros Trigazis
buildJsonReport v = do
175 798582cf Spyros Trigazis
  ticks <- getSysVar ClockTick
176 798582cf Spyros Trigazis
  let res = computeAverage v windowSize ticks
177 798582cf Spyros Trigazis
  return . J.showJSON $ formatData res
178 2da679f7 Spyros Trigazis
179 2da679f7 Spyros Trigazis
-- | This function computes the DCReport for the CPU load.
180 2da679f7 Spyros Trigazis
buildDCReport :: Buffer -> IO DCReport
181 2da679f7 Spyros Trigazis
buildDCReport v  =
182 2da679f7 Spyros Trigazis
  buildJsonReport v >>=
183 2da679f7 Spyros Trigazis
    buildReport dcName dcVersion dcFormatVersion dcCategory dcKind