#!/usr/bin/python -tt # -*- coding: utf-8 -*- # # rteval - script for evaluating platform suitability for RT Linux # # This program is used to determine the suitability of # a system for use in a Real Time Linux environment. # It starts up various system loads and measures event # latency while the loads are running. A report is generated # to show the latencies encountered during the run. # # Copyright 2009 - 2013 Clark Williams # Copyright 2009 - 2013 David Sommerseth # Copyright 2012 - 2013 Raphaƫl Beamonte # # 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 sys, os, time, optparse, tempfile import libxml2, lxml.etree from datetime import datetime from rteval.Log import Log from rteval import RtEval, rtevalConfig from rteval.modules.loads import LoadModules from rteval.modules.measurement import MeasurementModules def summarize(repfile, xslt): isarchive = False summaryfile = repfile if repfile.endswith(".tar.bz2"): import tarfile try: t = tarfile.open(repfile) except: print "Don't know how to summarize %s (tarfile open failed)" % repfile return element = None for f in t.getnames(): if f.find('summary.xml') != -1: element = f break if element == None: print "No summary.xml found in tar archive %s" % repfile return tmp = tempfile.gettempdir() t.extract(element, path=tmp) summaryfile = os.path.join(tmp, element) isarchive = True # Load the XSLT template xsltfp = open(xslt, "r") xsltdoc = lxml.etree.parse(xsltfp) xsltprs = lxml.etree.XSLT(xsltdoc) xsltfp.close() # Load the summay.xml report - with some simple sanity checks xmlfp = open(summaryfile, "r") xmldoc = lxml.etree.parse(xmlfp) xmlfp.close() if xmldoc.docinfo.root_name != 'rteval': raise RuntimeError("The report doesn't seem like a rteval summary report") # Parse and print the report through the XSLT template - preserve proper encoding resdoc = xsltprs(xmldoc) print unicode(resdoc).encode('UTF-8') # Clean up del resdoc del xmldoc del xsltprs del xsltdoc if isarchive: os.unlink(summaryfile) def parse_options(cfg, parser, cmdargs): '''parse the command line arguments''' rtevcfg = cfg.GetSection('rteval') # # All the destination variables here should go into the 'rteval' section, # thus they are prefixed with 'rteval___'. # See rteval/rtevalConfig::UpdateFromOptionParser() method for more info # parser.add_option("-d", "--duration", dest="rteval___duration", type="string", default=rtevcfg.duration, metavar="DURATION", help="specify length of test run (default: %default)") parser.add_option("-v", "--verbose", dest="rteval___verbose", action="store_true", default=rtevcfg.verbose, help="turn on verbose prints (default: %default)") parser.add_option("-q", "--quiet", dest="rteval___quiet", action="store_true", default=rtevcfg.quiet, help="turn on quiet mode (default: %default)") parser.add_option("-w", "--workdir", dest="rteval___workdir", type="string", default=rtevcfg.workdir, metavar="DIRECTORY", help="top directory for rteval data (default: %default)") parser.add_option("-l", "--loaddir", dest="rteval___srcdir", type="string", default=rtevcfg.srcdir, metavar="DIRECTORY", help="directory for load source tarballs (default: %default)") parser.add_option("-i", "--installdir", dest="rteval___installdir", type="string", default=rtevcfg.installdir, metavar="DIRECTORY", help="place to locate installed templates (default: %default)") parser.add_option("-s", "--sysreport", dest="rteval___sysreport", action="store_true", default=rtevcfg.sysreport, help='run sysreport to collect system data (default: %default)') parser.add_option("-D", '--debug', dest='rteval___debugging', action='store_true', default=rtevcfg.debugging, help='turn on debug prints (default: %default)') parser.add_option("-X", '--xmlrpc-submit', dest='rteval___xmlrpc', action='store', default=rtevcfg.xmlrpc, metavar='HOST', help='Hostname to XML-RPC server to submit reports') parser.add_option("-P", "--xmlrpc-no-abort", dest="rteval___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='rteval___summarize', action='store_true', default=False, help='summarize an already existing XML report') parser.add_option("-H", '--raw-histogram', dest='rteval___rawhistogram', action='store_true', default=False, help='Generate raw histogram data for an already existing XML report') parser.add_option("-f", "--inifile", dest="rteval___inifile", type='string', default=None, metavar="FILE", help="initialization file for configuring loads and behavior") parser.add_option("-a", "--annotate", dest="rteval___annotate", type="string", default=None, metavar="STRING", help="Add a little annotation which is stored in the report") parser.add_option("-L", "--logging", dest="rteval___logging", action='store_true', default=False, help='log the output of the loads in the report directory') parser.add_option("-O", "--onlyload", dest="rteval___onlyload", action='store_true', default=False, help="only run the loads (don't run measurement threads)") (cmd_opts, cmd_args) = parser.parse_args(args = cmdargs) if cmd_opts.rteval___duration: mult = 1.0 v = cmd_opts.rteval___duration.lower() if v.endswith('s'): v = v[:-1] elif v.endswith('m'): v = v[:-1] mult = 60.0 elif v.endswith('h'): v = v[:-1] mult = 3600.0 elif v.endswith('d'): v = v[:-1] mult = 3600.0 * 24.0 cmd_opts.rteval___duration = float(v) * mult # Update the config object with the parsed arguments cfg.UpdateFromOptionParser(parser) return cmd_args if __name__ == '__main__': from rteval.sysinfo import dmi dmi.ProcessWarnings() try: # Prepare logging logger = Log() logger.SetLogVerbosity(Log.NONE) # setup initial configuration config = rtevalConfig.rtevalConfig(logger=logger) # Before really parsing options, see if we have been given a config file in the args # and load it - just so that default values are according to the config file try: cfgfile = sys.argv[sys.argv.index('-f')+1] config.Load(cfgfile) except IndexError: # Missing file argument raise RuntimeError('The -f option requires a file name to the configuration file') except ValueError: # No configuration file given pass if not config.HasSection('loads'): config.AppendConfig('loads',{ 'kcompile' : 'module', 'hackbench' : 'module' }) if not config.HasSection('measurement'): config.AppendConfig('measurement', { 'cyclictest' : 'module', 'sysstat' : 'module'}) # Prepare log levels before loading modules, not to have unwanted log messages rtevcfg = config.GetSection('rteval') if (sys.argv.count('-v')+sys.argv.count('--verbose')) > 0: rtevcfg.verbose = True if (sys.argv.count('-D')+sys.argv.count('--debug')) > 0: rtevcfg.debugging = True if (sys.argv.count('-q')+sys.argv.count('--quiet')) > 0: rtevcfg.quiet = True loglev = (not rtevcfg.quiet and (Log.ERR | Log.WARN)) \ | (rtevcfg.verbose and Log.INFO) \ | (rtevcfg.debugging and Log.DEBUG) logger.SetLogVerbosity(loglev) # Load modules loadmods = LoadModules(config, logger=logger) measuremods = MeasurementModules(config, logger=logger) # parse command line options parser = optparse.OptionParser() loadmods.SetupModuleOptions(parser) measuremods.SetupModuleOptions(parser) cmd_args = parse_options(config, parser, sys.argv[1:]) logger.log(Log.DEBUG, "workdir: %s" % rtevcfg.workdir) # if --summarize was specified then just parse the XML, print it and exit if rtevcfg.summarize or rtevcfg.rawhistogram: if len(cmd_args) < 1: raise RuntimeError, "Must specify at least one XML file with --summarize!" for x in cmd_args: if rtevcfg.summarize: summarize(x, '%s/rteval_text.xsl' % rtevcfg.installdir) elif rtevcfg.rawhistogram: summarize(x, '%s/rteval_histogram_raw.xsl' % rtevcfg.installdir) sys.exit(0) if os.getuid() != 0: print "Must be root to run rteval!" sys.exit(-1) logger.log(Log.DEBUG, '''rteval options: workdir: %s loaddir: %s reportdir: %s verbose: %s debugging: %s logging: %s duration: %f sysreport: %s''' % ( rtevcfg.workdir, rtevcfg.srcdir, rtevcfg.reportdir, rtevcfg.verbose, rtevcfg.debugging, rtevcfg.logging, rtevcfg.duration, rtevcfg.sysreport)) if not os.path.isdir(rtevcfg.workdir): raise RuntimeError, "work directory %s does not exist" % rtevcfg.workdir rteval = RtEval(config, loadmods, measuremods, logger) rteval.Prepare(rtevcfg.onlyload) if rtevcfg.onlyload: # If --onlyload were given, just kick off the loads and nothing more # No reports will be created. loadmods.Start() nthreads = loadmods.Unleash() logger.log(Log.INFO, "Started %i load threads - will run for %f seconds" % ( nthreads, rtevcfg.duration)) logger.log(Log.INFO, "No measurements will be performed, due to the --onlyload option") time.sleep(rtevcfg.duration) loadmods.Stop() ec = 0 else: # ... otherwise, run the full measurement suite with loads ec = rteval.Measure() logger.log(Log.DEBUG, "exiting with exit code: %d" % ec) sys.exit(ec) except KeyboardInterrupt: sys.exit(0)