Added new measurement module, sysstat

This module runs in parallel with cyclictest and will every minute
use sysstat/sadc to collect all available system statistics.  These
statistics is both added as a single file to the tarball and embedded
into the summary.xml.

Also changed the polling time which checks if measurement and load modules
are alive from every second to every minute.

Signed-off-by: David Sommerseth <davids@redhat.com>
diff --git a/rteval-cmd b/rteval-cmd
index 4111e03..9ac2a52 100755
--- a/rteval-cmd
+++ b/rteval-cmd
@@ -210,7 +210,8 @@
 
         if not config.HasSection('measurement'):
             config.AppendConfig('measurement', {
-                    'cyclictest' : 'module'})
+                    'cyclictest' : 'module',
+                    'sysstat' : 'module'})
 
         # Prepare log levels before loading modules, not to have unwanted log messages
         rtevcfg = config.GetSection('rteval')
diff --git a/rteval/__init__.py b/rteval/__init__.py
index 7f90b82..e1f5556 100644
--- a/rteval/__init__.py
+++ b/rteval/__init__.py
@@ -200,7 +200,7 @@
             rpttime = currtime + report_interval
             load_avg_checked = 5
             while (currtime <= stoptime) and not sigint_received:
-                time.sleep(1.0)
+                time.sleep(60.0)
                 if not measure_profile.isAlive():
                     stoptime = currtime
                     self.__logger.log(Log.WARN,
diff --git a/rteval/modules/__init__.py b/rteval/modules/__init__.py
index 5d400fb..de70e03 100644
--- a/rteval/modules/__init__.py
+++ b/rteval/modules/__init__.py
@@ -191,7 +191,7 @@
                 if not self.WorkloadAlive():
                     self._log(Log.DEBUG, "%s workload stopped running." % self._module_type)
                     break
-                time.sleep(1.0)
+                time.sleep(60.0)
             self.__timestamps["runloop_stop"] = datetime.now()
             self._log(Log.DEBUG, "stopping %s workload" % self._module_type)
         else:
diff --git a/rteval/modules/measurement/sysstat.py b/rteval/modules/measurement/sysstat.py
new file mode 100644
index 0000000..033e882
--- /dev/null
+++ b/rteval/modules/measurement/sysstat.py
@@ -0,0 +1,157 @@
+#
+#   sysstat.py - rteval measurment module collecting system statistics
+#                using the sysstat utility
+#
+#   Copyright 2013          David Sommerseth <davids@redhat.com>
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program; if not, write to the Free Software Foundation, Inc.,
+#   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+#   For the avoidance of doubt the "preferred form" of this code is one which
+#   is in an open unpatent encumbered format. Where cryptographic key signing
+#   forms part of the process of creating an executable the information
+#   including keys needed to generate an equivalently functional executable
+#   are deemed to be part of the source code.
+#
+
+import os, sys, libxml2, tempfile, time, subprocess, base64, bz2, textwrap
+from rteval.Log import Log
+from rteval.modules import rtevalModulePrototype
+
+
+class sysstat(rtevalModulePrototype):
+    def __init__(self, config, logger=None):
+        rtevalModulePrototype.__init__(self, 'measurement', 'sysstat', logger)
+        self.__cfg      = config
+        self.__started  = False
+        self.__logentry = 0
+        self.__bin_sadc = "/usr/lib64/sa/sadc" # FIXME: Do dynamically
+        self.__datadir  =  os.path.join(self.__cfg.reportdir, 'sysstat')
+        self.__datafile = os.path.join(self.__datadir, "sysstat.dat")
+
+
+    def _WorkloadSetup(self):
+        # Nothing to do here for sysstat
+        pass
+
+
+    def _WorkloadBuild(self):
+        # Nothing to build
+        self._setReady()
+
+
+    def _WorkloadPrepare(self):
+        os.mkdir(self.__datadir)
+
+
+    def _WorkloadTask(self):
+        # This workload will actually not run any process, but
+        # it will update the data files each time rteval checks
+        # if this workload is alive.
+        #
+        # Just add a single notification that rteval started
+        if self.__logentry == 0:
+            cmd = [self.__bin_sadc, "-S", "XALL", "-C", "rteval started", self.__datafile]
+            subprocess.call(cmd)
+            self.__logentry += 1
+
+
+    def WorkloadAlive(self):
+        # Here the sysstat tool will be called, which will update
+        # the file containing the system information
+        cmd = [self.__bin_sadc, "-S", "XALL", "1", "1", self.__datafile]
+        subprocess.call(cmd)
+        self.__logentry += 1
+        return True
+
+
+    def _WorkloadCleanup(self):
+        # Add 'rteval stopped' comment line
+        cmd = [self.__bin_sadc, "-S", "XALL", "-C", "rteval stopped", self.__datafile]
+        subprocess.call(cmd)
+        self.__logentry += 1
+        self._setFinished()
+
+
+    def MakeReport(self):
+        rep_n = libxml2.newNode('sysstat')
+        rep_n.newProp('command_line', '(sysstat specifics)')
+        rep_n.newProp('num_entries', str(self.__logentry))
+
+        fp = open(self.__datafile, "rb")
+        compr = bz2.BZ2Compressor(9)
+        cmpr = compr.compress(fp.read())
+        data = base64.b64encode(cmpr + compr.flush())
+        data_n = rep_n.newTextChild(None, 'data', "\n"+"\n".join(textwrap.wrap(data,75))+"\n")
+        data_n.newProp('contents', 'sysstat/sar binary data')
+        data_n.newProp('encoding','base64')
+        data_n.newProp('compression','bz2')
+        fp.close()
+        del cmpr
+        del compr
+
+        # Return the report
+        return rep_n
+
+
+
+def ModuleInfo():
+    # sysstat features - run in parallel with outher measurement modules with loads
+    return {"parallel": True,
+            "loads": True}
+
+
+
+def ModuleParameters():
+    return {}  # No arguments available
+
+
+
+def create(params, logger):
+    return sysstat(params, logger)
+
+
+if __name__ == '__main__':
+    from rteval.rtevalConfig import rtevalConfig
+
+    l = Log()
+    l.SetLogVerbosity(Log.INFO|Log.DEBUG|Log.ERR|Log.WARN)
+
+    cfg = rtevalConfig({}, logger=l)
+    prms = {}
+    modprms = ModuleParameters()
+    for c, p in modprms.items():
+        prms[c] = p['default']
+    cfg.AppendConfig('MeasurementModuleTemplate', prms)
+
+    cfg_ct = cfg.GetSection('MeasurementModuleTemplate')
+    cfg_ct.reportdir = "."
+
+    runtime = 10
+
+    c = sysstat(cfg_ct, l)
+    c._WorkloadSetup()
+    c._WorkloadPrepare()
+    c._WorkloadTask()
+    print "Running for approx %i seconds" % runtime
+    while runtime > 0:
+        c.WorkloadAlive()
+        time.sleep(1)
+        runtime -= 1
+    c._WorkloadCleanup()
+    rep_n = c.MakeReport()
+
+    xml = libxml2.newDoc('1.0')
+    xml.setRootElement(rep_n)
+    xml.saveFormatFileEnc('-','UTF-8',1)
diff --git a/rteval/rteval_text.xsl b/rteval/rteval_text.xsl
index 2613189..e99c016 100644
--- a/rteval/rteval_text.xsl
+++ b/rteval/rteval_text.xsl
@@ -183,7 +183,7 @@
     <!--                                                                        -->
     <!--       select="cyclictest|new_foo_section|another_section"              -->
     <!--                                                                        -->
-    <xsl:apply-templates select="cyclictest|hwlatdetect[@format='1.0']"/>
+    <xsl:apply-templates select="cyclictest|hwlatdetect[@format='1.0']|sysstat"/>
     <xsl:text>&#10;</xsl:text>
   </xsl:template>
 
@@ -322,6 +322,22 @@
     <xsl:text>us&#10;</xsl:text>
   </xsl:template>
 
+  <!-- Format the cyclic test section of the report -->
+  <xsl:template match="/rteval/Measurements/Profile/sysstat">
+    <xsl:text>       sysstat measurements&#10;</xsl:text>
+
+    <xsl:text>          Started: </xsl:text>
+    <xsl:value-of select="timestamps/runloop_start"/>
+    <xsl:text>&#10;</xsl:text>
+
+    <xsl:text>          Stopped: </xsl:text>
+    <xsl:value-of select="timestamps/runloop_stop"/>
+    <xsl:text>&#10;</xsl:text>
+
+    <xsl:text>          Records saved: </xsl:text>
+    <xsl:value-of select="@num_entries"/>
+    <xsl:text>&#10;</xsl:text>
+  </xsl:template>
 
   <!-- Format information about aborts - if present -->
   <xsl:template match="abort_report">