summaryrefslogtreecommitdiffstats
path: root/rteval/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'rteval/__init__.py')
-rw-r--r--rteval/__init__.py243
1 files changed, 241 insertions, 2 deletions
diff --git a/rteval/__init__.py b/rteval/__init__.py
index e1c8289..f3d93fe 100644
--- a/rteval/__init__.py
+++ b/rteval/__init__.py
@@ -1,7 +1,246 @@
"""
-Copyright (c) 2008,2009,2010 Red Hat Inc.
+Copyright (c) 2008-2012 Red Hat Inc.
Realtime verification utility
"""
-__author__ = "Clark Williams <williams@redhat.com>"
+__author__ = "Clark Williams <williams@redhat.com>, David Sommerseth <davids@redhat.com>"
__license__ = "GPLv2 License"
+
+import os, signal, sys, threading, time
+from datetime import datetime
+from distutils import sysconfig
+from sysinfo import SystemInfo
+from modules.loads import LoadModules
+from modules.measurement import MeasurementModules, MeasurementProfile
+from rtevalReport import rtevalReport
+from rtevalXMLRPC import rtevalXMLRPC
+from Log import Log
+import rtevalConfig, rtevalMailer
+
+
+
+sigint_received = False
+def sigint_handler(signum, frame):
+ global sigint_received
+ sigint_received = True
+ print "*** SIGINT received - stopping rteval run ***"
+
+
+
+def sigterm_handler(signum, frame):
+ raise RuntimeError, "SIGTERM received!"
+
+
+
+class RtEval(rtevalReport):
+ def __init__(self, config, loadmods, measuremods, logger):
+ self.__version = "2.0_pre"
+
+ if not isinstance(config, rtevalConfig.rtevalConfig):
+ raise TypeError("config variable is not an rtevalConfig object")
+
+ if not isinstance(loadmods, LoadModules):
+ raise TypeError("loadmods variable is not a LoadModules object")
+
+ if not isinstance(measuremods, MeasurementModules):
+ raise TypeError("measuremods variable is not a MeasurementModules object")
+
+ if not isinstance(logger, Log):
+ raise TypeError("logger variable is not an Log object")
+
+ self.__cfg = config
+ self.__logger = logger
+ self._loadmods = loadmods
+ self._measuremods = measuremods
+
+ self.__rtevcfg = self.__cfg.GetSection('rteval')
+ self.__reportdir = None
+
+ self._sysinfo = SystemInfo(self.__rtevcfg, logger=self.__logger)
+
+ # prepare a mailer, if that's configured
+ if self.__cfg.HasSection('smtp'):
+ self.__mailer = rtevalMailer.rtevalMailer(self.__cfg.GetSection('smtp'))
+ else:
+ self.__mailer = None
+
+ # Prepare XSLT processing, if enabled
+ if not self.__rtevcfg.xslt_report.startswith(self.__rtevcfg.installdir):
+ self.__rtevcfg.xslt_report = os.path.join(self.__rtevcfg.installdir, "rteval_text.xsl")
+
+ if not os.path.exists(self.__rtevcfg.xslt_report):
+ raise RuntimeError("can't find XSL template (%s)!" % self.__rtevcfg.xslt_report)
+
+ # Add rteval directory into module search path
+ sys.path.insert(0, '%s/rteval' % sysconfig.get_python_lib())
+
+ # Initialise the report module
+ rtevalReport.__init__(self, self.__version,
+ self.__rtevcfg.installdir, self.__rtevcfg.annotate)
+
+ # If --xmlrpc-submit is given, check that we can access the server
+ if self.__rtevcfg.xmlrpc:
+ self.__xmlrpc = rtevalXMLRPC(self.__rtevcfg.xmlrpc, self.__logger, self.__mailer)
+ if not self.__xmlrpc.Ping():
+ if not self.__rtevcfg.xmlrpc_noabort:
+ print "ERROR: Could not reach XML-RPC server '%s'. Aborting." % \
+ self.__rtevcfg.xmlrpc
+ sys.exit(2)
+ else:
+ print "WARNING: Could not ping the XML-RPC server. Will continue anyway."
+ else:
+ self.__xmlrpc = None
+
+
+ def __show_remaining_time(self, remaining):
+ r = int(remaining)
+ days = r / 86400
+ if days: r = r - (days * 86400)
+ hours = r / 3600
+ if hours: r = r - (hours * 3600)
+ minutes = r / 60
+ if minutes: r = r - (minutes * 60)
+ print "rteval time remaining: %d days, %d hours, %d minutes, %d seconds" % (days, hours, minutes, r)
+
+
+ def Prepare(self, onlyload = False):
+ builddir = os.path.join(self.__rtevcfg.workdir, 'rteval-build')
+ if not os.path.isdir(builddir): os.mkdir(builddir)
+
+ # create our report directory
+ try:
+ # Only create a report dir if we're doing measurements
+ # or the loads logging is enabled
+ if not onlyload or self.__rtevcfg.logging:
+ self.__reportdir = self._make_report_dir(self.__rtevcfg.workdir, "summary.xml")
+ except Exception, e:
+ raise RuntimeError("Cannot create report directory (NFS with rootsquash on?) [%s]", str(e))
+
+ self.__logger.log(Log.INFO, "Preparing load modules")
+ params = {'workdir':self.__rtevcfg.workdir,
+ 'reportdir':self.__reportdir,
+ 'builddir':builddir,
+ 'srcdir':self.__rtevcfg.srcdir,
+ 'verbose': self.__rtevcfg.verbose,
+ 'debugging': self.__rtevcfg.debugging,
+ 'numcores':self._sysinfo.cpu_getCores(True),
+ 'logging':self.__rtevcfg.logging,
+ 'memsize':self._sysinfo.mem_get_size(),
+ 'numanodes':self._sysinfo.mem_get_numa_nodes(),
+ 'duration':self.__rtevcfg.duration,
+ }
+ self._loadmods.Setup(params)
+
+ self.__logger.log(Log.INFO, "Preparing measurement modules")
+ self._measuremods.Setup(params)
+
+
+ def __RunMeasurementProfile(self, measure_profile):
+ if not isinstance(measure_profile, MeasurementProfile):
+ raise Exception("measure_profile is not an MeasurementProfile object")
+
+ measure_start = None
+ (with_loads, run_parallel) = measure_profile.GetProfile()
+ self.__logger.log(Log.INFO, "Using measurement profile [loads: %s parallel: %s]" % (
+ with_loads, run_parallel))
+ try:
+ nthreads = 0
+
+ # start the loads
+ if with_loads:
+ self._loadmods.Start()
+
+ print "rteval run on %s started at %s" % (os.uname()[2], time.asctime())
+ print "started %d loads on %d cores" % (self._loadmods.ModulesLoaded(), self._sysinfo.cpu_getCores(True)),
+ if self._sysinfo.mem_get_numa_nodes() > 1:
+ print " with %d numa nodes" % self._sysinfo.mem_get_numa_nodes()
+ else:
+ print ""
+ print "Run duration: %d seconds" % self.__rtevcfg.duration
+
+ # start the cyclictest thread
+ measure_profile.Start()
+
+ # Uleash the loads and measurement threads
+ report_interval = int(self.__rtevcfg.report_interval)
+ nthreads = with_loads and self._loadmods.Unleash() or None
+ measure_profile.Unleash()
+ measure_start = datetime.now()
+
+ # wait for time to expire or thread to die
+ signal.signal(signal.SIGINT, sigint_handler)
+ signal.signal(signal.SIGTERM, sigterm_handler)
+ self.__logger.log(Log.INFO, "waiting for duration (%f)" % self.__rtevcfg.duration)
+ stoptime = (time.time() + self.__rtevcfg.duration)
+ currtime = time.time()
+ rpttime = currtime + report_interval
+ load_avg_checked = 5
+ while (currtime <= stoptime) and not sigint_received:
+ time.sleep(1.0)
+ if not measure_profile.isAlive():
+ stoptime = currtime
+ self.__logger.log(Log.WARN,
+ "Measurement threads did not use the full time slot. Doing a controlled stop.")
+
+ if with_loads:
+ if len(threading.enumerate()) < nthreads:
+ raise RuntimeError, "load thread died!"
+
+ if not load_avg_checked:
+ self._loadmods.SaveLoadAvg()
+ load_avg_checked = 5
+ else:
+ load_avg_checked -= 1
+
+ if currtime >= rpttime:
+ left_to_run = stoptime - currtime
+ self.__show_remaining_time(left_to_run)
+ rpttime = currtime + report_interval
+ print "load average: %.2f" % self._loadmods.GetLoadAvg()
+ currtime = time.time()
+
+ self.__logger.log(Log.DEBUG, "out of measurement loop")
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
+ signal.signal(signal.SIGTERM, signal.SIG_DFL)
+
+ except RuntimeError, e:
+ print "Runtime error during measurement: %s", e
+ raise
+
+ finally:
+ # stop measurement threads
+ measure_profile.Stop()
+
+ # stop the loads
+ if with_loads:
+ self._loadmods.Stop()
+
+ print "stopping run at %s" % time.asctime()
+
+ # wait for measurement modules to finish calculating stats
+ measure_profile.WaitForCompletion()
+
+ return measure_start
+
+
+ def Measure(self):
+ # Run the full measurement suite with reports
+ rtevalres = 0
+ measure_start = None
+ for meas_prf in self._measuremods:
+ mstart = self.__RunMeasurementProfile(meas_prf)
+ if measure_start is None:
+ measure_start = mstart
+
+ self._report(measure_start, self.__rtevcfg.xslt_report)
+ if self.__rtevcfg.sysreport:
+ self._sysinfo.run_sysreport(self.__reportdir)
+
+ # if --xmlrpc-submit | -X was given, send our report to the given host
+ if self.__xmlrpc:
+ retvalres = self.__xmlrpc.SendReport(self._XMLreport())
+
+ self._sysinfo.copy_dmesg(self.__reportdir)
+ self._tar_results()
+ return rtevalres
+