diff options
Diffstat (limited to 'rteval')
-rw-r--r-- | rteval/cputopology.py | 28 | ||||
-rw-r--r-- | rteval/cyclictest.py | 4 | ||||
-rw-r--r-- | rteval/dmi.py | 61 | ||||
-rw-r--r-- | rteval/hackbench.py | 9 | ||||
-rw-r--r-- | rteval/kcompile.py | 6 | ||||
-rw-r--r-- | rteval/rteval.py | 87 | ||||
-rw-r--r-- | rteval/rtevalConfig.py | 16 | ||||
-rw-r--r-- | rteval/rteval_text.xsl | 5 | ||||
-rw-r--r-- | rteval/xmlout.py | 126 |
9 files changed, 247 insertions, 95 deletions
diff --git a/rteval/cputopology.py b/rteval/cputopology.py index 61ef982..4b696f7 100644 --- a/rteval/cputopology.py +++ b/rteval/cputopology.py @@ -99,12 +99,24 @@ class CPUtopology: def getCPUsockets(self): return self.__cpu_sockets -if __name__ == '__main__': - cputop = CPUtopology() - n = cputop.parse() - - x = libxml2.newDoc('1.0') - x.setRootElement(n) - x.saveFormatFileEnc('-','UTF-8',1) +def unit_test(rootdir): + try: + cputop = CPUtopology() + n = cputop.parse() + + print " ---- XML Result ---- " + x = libxml2.newDoc('1.0') + x.setRootElement(n) + x.saveFormatFileEnc('-','UTF-8',1) + + print " ---- getCPUcores() / getCPUscokets() ---- " + print "CPU cores: %i (online: %i) - CPU sockets: %i" % (cputop.getCPUcores(False), + cputop.getCPUcores(True), + cputop.getCPUsockets()) + return 0 + except Exception, e: + print "** EXCEPTION %s", str(e) + return 1 - # print "CPU cores: %i (online: %i) - CPU sockets: %i" % (cputop.getCPUcores(False), cputop.getCPUcores(True), cputop.getCPUsockets()) +if __name__ == '__main__': + unit_test() diff --git a/rteval/cyclictest.py b/rteval/cyclictest.py index 5a3ffbf..7970f35 100644 --- a/rteval/cyclictest.py +++ b/rteval/cyclictest.py @@ -233,7 +233,8 @@ class Cyclictest(Thread): break time.sleep(1.0) self.debug("stopping") - os.kill(c.pid, signal.SIGINT) + if c.poll() == None: + os.kill(c.pid, signal.SIGINT) # now parse the histogram output for line in c.stdout: if line.startswith('#'): continue @@ -245,6 +246,7 @@ class Cyclictest(Thread): for n in self.data.keys(): self.data[n].reduce() self.finished.set() + os.close(null) def genxml(self, x): x.openblock('cyclictest') diff --git a/rteval/dmi.py b/rteval/dmi.py index cd1b05e..7d1ab19 100644 --- a/rteval/dmi.py +++ b/rteval/dmi.py @@ -33,6 +33,28 @@ import libxml2 import libxslt import dmidecode +def ProcessWarnings(): + if not hasattr(dmidecode, 'get_warnings'): + return + + warnings = dmidecode.get_warnings() + if warnings == None: + return + + for warnline in warnings.split('\n'): + # Ignore these warnings, as they are "valid" if not running as root + if warnline == '/dev/mem: Permission denied': + continue + if warnline == 'No SMBIOS nor DMI entry point found, sorry.': + continue + + # All other warnings will be printed + if len(warnline) > 0: + print "** DMI WARNING ** %s" % warnline + + dmidecode.clear_warnings() + + class DMIinfo(object): '''class used to obtain DMI info via python-dmidecode''' @@ -64,12 +86,35 @@ class DMIinfo(object): xml.AppendXMLnodes(node) -if __name__ == '__main__': +def unit_test(rootdir): from pprint import pprint - - d = DMIinfo('.') - x = xmlout.XMLOut('dmi_test', "0.0") - x.NewReport() - d.genxml(x) - x.close() - x.Write('-') + + class unittest_ConfigDummy(object): + def __init__(self, rootdir): + self.config = {'installdir': '%s/rteval'} + self.__update_vars() + + def __update_vars(self): + for k in self.config.keys(): + self.__dict__[k] = self.config[k] + + try: + ProcessWarnings() + if os.getuid() != 0: + print "** ERROR ** Must be root to run this unit_test()" + return 1 + + cfg = unittest_ConfigDummy(rootdir) + d = DMIinfo(cfg) + x = xmlout.XMLOut('dmi_test', "0.0") + x.NewReport() + d.genxml(x) + x.close() + x.Write('-') + return 0 + except Exception, e: + print "** EXCEPTION: %s" % str(e) + return 1 + +if __name__ == '__main__': + sys.exit(unit_test('.')) diff --git a/rteval/hackbench.py b/rteval/hackbench.py index 65d0133..685b8d6 100644 --- a/rteval/hackbench.py +++ b/rteval/hackbench.py @@ -30,6 +30,7 @@ import time import glob import subprocess from signal import SIGTERM +from signal import SIGKILL sys.pathconf = "." import load @@ -41,6 +42,7 @@ class Hackbench(load.Load): null = open("/dev/null", "w") subprocess.call(['killall', '-9', 'hackbench'], stdout=null, stderr=null) + os.close(null) def setup(self): # find our tarball @@ -93,6 +95,7 @@ class Hackbench(load.Load): raise RuntimeError, "Can't find hackbench executable: %s" % self.exe self.args = [self.exe, str(self.jobs)] self.ready = True + os.close(null) def runload(self): null = os.open("/dev/null", os.O_RDWR) @@ -104,15 +107,11 @@ class Hackbench(load.Load): p.wait() p = subprocess.Popen(self.args,stdin=null,stdout=null,stderr=null) self.debug("stopping") - os.kill(p.pid, SIGTERM) - count = 30 - while count > 0 and p.poll() == None: - time.sleep(1.0) - count -= 1 if p.poll() == None: os.kill(p.pid, SIGKILL) p.wait() self.debug("returning from runload()") + os.close(null) def genxml(self, x): x.taggedvalue('command_line', ' '.join(self.args), {'name':'hackbench'}) diff --git a/rteval/kcompile.py b/rteval/kcompile.py index 1e0863a..f57a18b 100644 --- a/rteval/kcompile.py +++ b/rteval/kcompile.py @@ -97,6 +97,7 @@ class Kcompile(load.Load): return self.debug("ready to run") self.ready = True + os.close(null) def runload(self): null = os.open("/dev/null", os.O_RDWR) @@ -118,7 +119,10 @@ class Kcompile(load.Load): p = subprocess.Popen(self.args, stdin=null,stdout=null,stderr=null) self.debug("stopping") - os.kill(p.pid, SIGTERM) + if p.poll() == None: + os.kill(p.pid, SIGTERM) + p.wait() + os.close(null) def genxml(self, x): x.taggedvalue('command_line', ' '.join(self.args), {'name':'kcompile'}) diff --git a/rteval/rteval.py b/rteval/rteval.py index 8522dbc..8fcaf1f 100644 --- a/rteval/rteval.py +++ b/rteval/rteval.py @@ -44,6 +44,7 @@ import optparse import tempfile import statvfs import shutil +import signal import rtevalclient import ethtool import xmlrpclib @@ -59,11 +60,17 @@ import rtevalConfig import rtevalMailer from cputopology import CPUtopology + +sigint_received = False +def sigint_handler(signum, frame): + global sigint_received + sigint_received = True + print "*** SIGINT received - stopping rteval run ***" + + class RtEval(object): def __init__(self, cmdargs): - if os.getuid() != 0: - raise RuntimeError, "must be root to run rteval" - self.version = "1.19" + self.version = "1.21" self.load_modules = [] self.workdir = os.getcwd() self.inifile = None @@ -134,6 +141,7 @@ class RtEval(object): self.kthreads = None self.xml = None self.baseos = "unknown" + self.annotate = self.cmd_options.annotate if not self.config.xslt_report.startswith(self.config.installdir): self.config.xslt_report = os.path.join(self.config.installdir, "rteval_text.xsl") @@ -156,18 +164,45 @@ class RtEval(object): res = None if self.config.xmlrpc: self.debug("Checking if XML-RPC server '%s' is reachable" % self.config.xmlrpc) - try: - client = rtevalclient.rtevalclient("http://%s/rteval/API1/" % self.config.xmlrpc) - res = client.Hello() - except xmlrpclib.ProtocolError: - # Server do not support Hello(), but is reachable - self.info("Got XML-RPC connection with %s but it did not support Hello()" - % self.config.xmlrpc) - res = None - except socket.error, err: - self.info("Could not establish XML-RPC contact with %s\n%s" - % (self.config.xmlrpc, str(err))) - sys.exit(2) + attempt = 0 + warning_sent = False + ping_failed = False + while attempt < 6: + try: + client = rtevalclient.rtevalclient("http://%s/rteval/API1/" % self.config.xmlrpc) + res = client.Hello() + attempt = 10 + ping_failed = False + except xmlrpclib.ProtocolError: + # Server do not support Hello(), but is reachable + self.info("Got XML-RPC connection with %s but it did not support Hello()" + % self.config.xmlrpc) + res = None + except socket.error, err: + self.info("Could not establish XML-RPC contact with %s\n%s" + % (self.config.xmlrpc, str(err))) + + if (self.mailer is not None) and (not warning_sent): + self.mailer.SendMessage("[RTEVAL:WARNING] Failed to ping XML-RPC server", + "Server %s did not respond. Not giving up yet." + % self.config.xmlrpc) + warning_sent = True + + # Do attempts handling + attempt += 1 + if attempt > 5: + break # To avoid sleeping before we abort + + print "Failed pinging XML-RPC server. Doing another attempt(%i) " % attempt + time.sleep(attempt*15) # Incremental sleep - sleep attempts*15 seconds + ping_failed = True + + if ping_failed: + if not self.cmd_options.xmlrpc_noabort: + print "ERROR: Could not reach XML-RPC server '%s'. Aborting." % self.config.xmlrpc + sys.exit(2) + else: + print "WARNING: Could not ping the XML-RPC server. Will continue anyway." if res: self.info("Verified XML-RPC connection with %s (XML-RPC API version: %i)" @@ -320,6 +355,9 @@ class RtEval(object): parser.add_option("-X", '--xmlrpc-submit', dest='xmlrpc', action='store', default=self.config.xmlrpc, metavar='HOST', help='Hostname to XML-RPC server to submit reports') + parser.add_option("-P", "--xmlrpc-no-abort", dest="xmlrpc_noabort", + action='store_true', default=False, + help="Do not abort if XML-RPC server do not respond to ping request"); parser.add_option("-Z", '--summarize', dest='summarize', action='store_true', default=False, help='summarize an already existing XML report') @@ -329,6 +367,9 @@ class RtEval(object): parser.add_option("-f", "--inifile", dest="inifile", type='string', default=None, help="initialization file for configuring loads and behavior") + parser.add_option("-a", "--annotate", dest="annotate", + type="string", default=None, + help="Add a little annotation which is stored in the report") (self.cmd_options, self.cmd_arguments) = parser.parse_args(args = cmdargs) if self.cmd_options.duration: @@ -398,6 +439,8 @@ class RtEval(object): 'seconds': seconds}) self.xmlreport.taggedvalue('date', self.start.strftime('%Y-%m-%d')) self.xmlreport.taggedvalue('time', self.start.strftime('%H:%M:%S')) + if self.annotate: + self.xmlreport.taggedvalue('annotate', self.annotate) self.xmlreport.closeblock() self.xmlreport.openblock('uname') self.xmlreport.taggedvalue('node', node) @@ -598,6 +641,7 @@ class RtEval(object): if minutes: r = r - (minutes * 60) print "rteval time remaining: %d days, %d hours, %d minutes, %d seconds" % (days, hours, minutes, r) + def measure(self): # Collect misc system info self.baseos = self.get_base_os() @@ -669,11 +713,12 @@ class RtEval(object): report_interval = int(self.config.GetSection('rteval').report_interval) # wait for time to expire or thread to die + signal.signal(signal.SIGINT, sigint_handler) self.info("waiting for duration (%f)" % self.config.duration) stoptime = (time.time() + self.config.duration) currtime = time.time() rpttime = currtime + report_interval - while currtime <= stoptime: + while (currtime <= stoptime) and not sigint_received: time.sleep(1.0) if not self.cyclictest.isAlive(): raise RuntimeError, "cyclictest thread died!" @@ -687,7 +732,7 @@ class RtEval(object): self.show_remaining_time(left_to_run) rpttime = currtime + report_interval currtime = time.time() - + signal.signal(signal.SIGINT, signal.SIG_DFL) finally: # stop cyclictest @@ -801,6 +846,9 @@ class RtEval(object): ''' main function for rteval''' retval = 0; + # Parse initial DMI decoding errors + dmi.ProcessWarnings() + # if --summarize was specified then just parse the XML, print it and exit if self.cmd_options.summarize or self.cmd_options.rawhistogram: if len(self.cmd_arguments) < 1: @@ -815,7 +863,7 @@ class RtEval(object): sys.exit(0) if os.getuid() != 0: - print "Must be root to run evaluator!" + print "Must be root to run rteval!" sys.exit(-1) self.debug('''rteval options: @@ -854,6 +902,9 @@ if __name__ == '__main__': import pwd, grp try: + # Parse initial DMI decoding errors + dmi.ProcessWarnings() + rteval = RtEval(sys.argv[1:]) ec = rteval.rteval() sys.exit(ec) diff --git a/rteval/rtevalConfig.py b/rteval/rtevalConfig.py index 5fad260..bb77da2 100644 --- a/rteval/rtevalConfig.py +++ b/rteval/rtevalConfig.py @@ -185,3 +185,19 @@ class rtevalConfig(rtevalCfgSection): return rtevalCfgSection(self.__config_data[section]) except KeyError, err: raise KeyError("The section '%s' does not exist in the config file" % section) + + +def unit_test(rootdir): + try: + cfg = rtevalConfig() + cfg.Load(rootdir + '/rteval/rteval.conf') + print cfg + return 0 + except Exception, e: + print "** EXCEPTION %s", str(e) + return 1 + + +if __name__ == '__main__': + import sys + sys.exit(unit_test('..')) diff --git a/rteval/rteval_text.xsl b/rteval/rteval_text.xsl index d11cda8..2e4d385 100644 --- a/rteval/rteval_text.xsl +++ b/rteval/rteval_text.xsl @@ -18,6 +18,11 @@ <xsl:value-of select="run_info/@hours"/><xsl:text>h </xsl:text> <xsl:value-of select="run_info/@minutes"/><xsl:text>m </xsl:text> <xsl:value-of select="run_info/@seconds"/><xsl:text>s</xsl:text> + <xsl:text> </xsl:text> + <xsl:if test="run_info/annotate"> + <xsl:text> Remarks: </xsl:text> + <xsl:value-of select="run_info/annotate"/> + </xsl:if> <xsl:text> </xsl:text> <xsl:text> Tested node: </xsl:text> diff --git a/rteval/xmlout.py b/rteval/xmlout.py index b4fe371..648131b 100644 --- a/rteval/xmlout.py +++ b/rteval/xmlout.py @@ -257,58 +257,76 @@ class XMLOut(object): return self.currtag.addChild(nodes) +def unit_test(rootdir): + try: + x = XMLOut('rteval', 'UNIT-TEST', None, 'UTF-8') + x.NewReport() + x.openblock('run_info', {'days': 0, 'hours': 0, 'minutes': 32, 'seconds': 18}) + x.taggedvalue('time', '11:22:33') + x.taggedvalue('date', '2000-11-22') + x.closeblock() + x.openblock('uname') + x.taggedvalue('node', u'testing - \xe6\xf8') + x.taggedvalue('kernel', 'my_test_kernel', {'is_RT': 0}) + x.taggedvalue('arch', 'mips') + x.closeblock() + x.openblock('hardware') + x.taggedvalue('cpu_cores', 2) + x.taggedvalue('memory_size', 1024*1024*2) + x.closeblock() + x.openblock('loads', {'load_average': 3.29}) + x.taggedvalue('command_line','./load/loader --extreme --ultimate --threads 4096', + {'name': 'heavyloader'}) + x.taggedvalue('command_line','dd if=/dev/zero of=/dev/null', {'name': 'lightloader'}) + x.closeblock() + x.close() + print "------------- XML OUTPUT ----------------------------" + x.Write("-") + print "------------- XSLT PARSED OUTPUT --------------------" + x.Write("-", "rteval_text.xsl") + print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + x.Write("/tmp/xmlout-test.xml") + del x + + print "------------- LOAD XML FROM FILE -----------------------------" + x = XMLOut('rteval','UNIT-TEST', None, 'UTF-8') + x.LoadReport("/tmp/xmlout-test.xml", True) + print "------------- LOADED XML DATA --------------------------------" + x.Write("-") + print "------------- XSLT PARSED OUTPUT FROM LOADED XML--------------" + x.Write("-", "rteval_text.xsl") + x.close() + + ## Test new data parser ... it eats most data types + print "------------- TESTING XMLOut::ParseData() --------------" + x.NewReport() + x.ParseData("ParseTest", "test string", {"type": "simple_string"}) + x.ParseData("ParseTest", 1234, {"type": "integer"}) + x.ParseData("ParseTest", 39.3904, {"type": "float"}) + x.ParseData("ParseTest", (11,22,33,44,55), {"type": "tuples"}) + x.ParseData("ParseTest", (99,88,77), {"type": "tuples", "comment": "Changed default tuple tag name"}, + "int_values") + test = {"var1": "value 1", + "var2": { "varA1": 1, + "pi": 3.1415926, + "varA3": (1, + 2, + {"test1": "val1"}, + (4.1,4.2,4.3), + 5), + "varA4": {'another_level': True, + 'another_value': "blabla"} + }, + "utf8 data": u'æøå', + u"løpe": True} + x.ParseData("ParseTest", test, {"type": "dict"}, prefix="test ") + x.close() + x.Write("-") + return 0 + except Exception, e: + print "** EXCEPTION %s", str(e) + return 1 + if __name__ == '__main__': - x = XMLOut('rteval', '0.6', None, 'UTF-8') - x.NewReport() - x.openblock('run_info', {'days': 0, 'hours': 0, 'minutes': 32, 'seconds': 18}) - x.taggedvalue('time', '11:22:33') - x.taggedvalue('date', '2000-11-22') - x.closeblock() - x.openblock('uname') - x.taggedvalue('node', u'testing - \xe6\xf8') - x.taggedvalue('kernel', 'my_test_kernel', {'is_RT': 0}) - x.taggedvalue('arch', 'mips') - x.closeblock() - x.openblock('hardware') - x.taggedvalue('cpu_cores', 2) - x.taggedvalue('memory_size', 1024*1024*2) - x.closeblock() - x.openblock('loads', {'load_average': 3.29}) - x.taggedvalue('command_line','./load/loader --extreme --ultimate --threads 4096', {'name': 'heavyloader'}) - x.taggedvalue('command_line','dd if=/dev/zero of=/dev/null', {'name': 'lightloader'}) - x.closeblock() - x.close() - print "------------- XML OUTPUT ----------------------------" - x.Write("-") - print "------------- XSLT PARSED OUTPUT --------------------" - x.Write("-", "rteval_text.xsl") - print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - x.LoadReport("latency.xml", True) - x.Write("-") - x.Write("-", "rteval_text.xsl") - x.close() - - ## Test new data parser ... it eats most data types - x.NewReport() - x.ParseData("ParseTest", "test string", {"type": "simple_string"}) - x.ParseData("ParseTest", 1234, {"type": "integer"}) - x.ParseData("ParseTest", 39.3904, {"type": "float"}) - x.ParseData("ParseTest", (11,22,33,44,55), {"type": "tuples"}) - x.ParseData("ParseTest", (99,88,77), {"type": "tuples", "comment": "Changed default tuple tag name"}, - "int_values") - test = {"var1": "value 1", - "var2": { "varA1": 1, - "pi": 3.1415926, - "varA3": (1, - 2, - {"test1": "val1"}, - (4.1,4.2,4.3), - 5), - "varA4": {'another_level': True, - 'another_value': "blabla"} - }, - "utf8 data": u'æøå', - u"løpe": True} - x.ParseData("ParseTest", test, {"type": "dict"}, prefix="test ") - x.close() - x.Write("-") + sys.exit(unit_test('..')) + |