| #!/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 <williams@redhat.com> |
| # Copyright 2009 - 2013 David Sommerseth <davids@redhat.com> |
| # Copyright 2012 - 2013 Raphaƫl Beamonte <raphael.beamonte@gmail.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 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 %d 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) |