[Pkg-ganeti-devel] [ganeti] 46/165: Add a data collector for xentop

Apollon Oikonomopoulos apoikos at moszumanska.debian.org
Tue Aug 11 13:53:12 UTC 2015


This is an automated email from the git hooks/post-receive script.

apoikos pushed a commit to branch master
in repository ganeti.

commit 83973f12acbc05403a905f15b1c6f0037dc928f9
Author: Klaus Aehlig <aehlig at google.com>
Date:   Mon Feb 16 15:54:11 2015 +0100

    Add a data collector for xentop
    
    We already have a CPU load collector based on /proc/stat; however,
    in a Xen setup this only measures the dom0 CPU load which is not
    that useful, if we're interested in the activity of the instances
    on that node. Therefore add a xen-specific CPU-load data collector,
    based on xentop.
    
    From xentop we can obtain the total amount of vCPU seconds used since
    an arbitrary start point. We collect those observations together with
    time stamps over the averaging period for CPU load. When asked for CPU
    average, it can be easily computed from the first and last data point
    kept.
    
    Signed-off-by: Klaus Aehlig <aehlig at google.com>
    Reviewed-by: Hrvoje Ribicic <riba at google.com>
---
 Makefile.am                             |   1 +
 src/Ganeti/Constants.hs                 |   3 +
 src/Ganeti/DataCollectors/XenCpuLoad.hs | 145 ++++++++++++++++++++++++++++++++
 3 files changed, 149 insertions(+)

diff --git a/Makefile.am b/Makefile.am
index 6f970d6..e2e620b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -880,6 +880,7 @@ HS_LIB_SRCS = \
 	src/Ganeti/DataCollectors/Lv.hs \
 	src/Ganeti/DataCollectors/Program.hs \
 	src/Ganeti/DataCollectors/Types.hs \
+	src/Ganeti/DataCollectors/XenCpuLoad.hs \
 	src/Ganeti/Errors.hs \
 	src/Ganeti/HTools/AlgorithmParams.hs \
 	src/Ganeti/HTools/Backend/IAlloc.hs \
diff --git a/src/Ganeti/Constants.hs b/src/Ganeti/Constants.hs
index 3b79595..9f6bf1b 100644
--- a/src/Ganeti/Constants.hs
+++ b/src/Ganeti/Constants.hs
@@ -5270,6 +5270,9 @@ ipv4NetworkMaxSize = 30
 dataCollectorCPULoad    :: String
 dataCollectorCPULoad    = "cpu-avg-load"
 
+dataCollectorXenCpuLoad :: String
+dataCollectorXenCpuLoad = "xen-cpu-avg-load"
+
 dataCollectorDiskStats  :: String
 dataCollectorDiskStats  = "diskstats"
 
diff --git a/src/Ganeti/DataCollectors/XenCpuLoad.hs b/src/Ganeti/DataCollectors/XenCpuLoad.hs
new file mode 100644
index 0000000..88cb673
--- /dev/null
+++ b/src/Ganeti/DataCollectors/XenCpuLoad.hs
@@ -0,0 +1,145 @@
+{-| xentop CPU data collector
+
+-}
+
+{-
+
+Copyright (C) 2015 Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-}
+
+module Ganeti.DataCollectors.XenCpuLoad
+  ( dcName
+  , dcVersion
+  , dcFormatVersion
+  , dcCategory
+  , dcKind
+  , dcReport
+  , dcUpdate
+  ) where
+
+import Control.Monad (liftM, when)
+import Control.Monad.IO.Class (liftIO)
+import qualified Data.Map as Map
+import Data.Maybe (mapMaybe)
+import qualified Data.Sequence as Seq
+import System.Process (readProcess)
+import qualified Text.JSON as J
+import System.Time (getClockTime, ClockTime)
+
+import Ganeti.BasicTypes (GenericResult(..), Result, genericResult, runResultT)
+import qualified Ganeti.Constants as C
+import Ganeti.DataCollectors.Types
+import Ganeti.Utils (readMaybe, clockTimeToUSec)
+
+-- | The name of this data collector.
+dcName :: String
+dcName = C.dataCollectorXenCpuLoad
+
+-- | The version of this data collector.
+dcVersion :: DCVersion
+dcVersion = DCVerBuiltin
+
+-- | The version number for the data format of this data collector.
+dcFormatVersion :: Int
+dcFormatVersion = 1
+
+-- | The category of this data collector.
+dcCategory :: Maybe DCCategory
+dcCategory = Nothing
+
+-- | The kind of this data collector.
+dcKind :: DCKind
+dcKind = DCKPerf
+
+-- | Read xentop output, if this program is available.
+readXentop :: IO (Result String)
+readXentop =
+  runResultT . liftIO $ readProcess C.xentopCommand ["-f", "-b", "-i", "1"] ""
+
+-- | Parse output of xentop command.
+parseXentop :: String -> Result (Map.Map String Double)
+parseXentop s = do
+  let values = map words $ lines s
+  case values of
+    [] -> Bad "No output received"
+    (name_header:_:cpu_header:_):vals -> do
+      when (name_header /= "NAME" || cpu_header /= "CPU(sec)")
+        $ Bad "Unexpected data format"
+      return . Map.fromList
+        $ mapMaybe
+            (\ dom -> case dom of
+                        name:_:cpu:_ -> if name /= "Domain-0"
+                                          then liftM ((,) name) $ readMaybe cpu
+                                          else Nothing
+                        _ -> Nothing
+            )
+            vals
+    _ -> Bad "Insufficient number of output columns"
+
+-- | Updates the given Collector data.
+dcUpdate :: Maybe CollectorData -> IO CollectorData
+dcUpdate maybeCollector = do
+  let oldData = case maybeCollector of
+                  Just (InstanceCpuLoad x) -> x
+                  _ -> Map.empty
+  now <- getClockTime
+  newResult <- liftM (>>= parseXentop) readXentop
+  let newValues = Map.map (Seq.singleton . (,) now)
+                  $ genericResult (const Map.empty) id newResult
+      sampleSizeUSec = fromIntegral C.cpuavgloadWindowSize * 1000000
+      combinedValues = Map.unionWith (Seq.><) newValues oldData
+      withinRange = Map.map
+                      (Seq.dropWhileR
+                        ((<) sampleSizeUSec
+                         . (clockTimeToUSec now -)
+                         . clockTimeToUSec . fst))
+                      combinedValues
+  return $ InstanceCpuLoad withinRange
+
+-- | From a list of timestamps and cumulative CPU data, compute the
+-- average CPU activity in vCPUs.
+loadAverage :: Seq.Seq (ClockTime, Double) -> Maybe Double
+loadAverage observations = do
+  when (Seq.null observations) Nothing
+  let (t2, cpu2) = Seq.index observations 0
+      (t1, cpu1) = Seq.index observations $ Seq.length observations - 1
+      tUsec2 = clockTimeToUSec t2
+      tUsec1 = clockTimeToUSec t1
+  when (tUsec2 - tUsec1 < (fromIntegral C.xentopAverageThreshold * 1000000))
+    Nothing
+  return $ 1000000 * (cpu2 - cpu1) / fromIntegral (tUsec2 - tUsec1)
+
+-- | The data exported by the data collector, taken from the default location.
+dcReport :: Maybe CollectorData -> IO DCReport
+dcReport maybeCollector =
+  let collectedData = case maybeCollector of
+                        Just (InstanceCpuLoad x) -> x
+                        _ -> Map.empty
+      loads = Map.mapMaybe loadAverage collectedData
+  in buildReport dcName dcVersion dcFormatVersion dcCategory dcKind
+      . J.JSObject . J.toJSObject . Map.toAscList $ Map.map J.showJSON loads

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ganeti/ganeti.git



More information about the Pkg-ganeti-devel mailing list