aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClark Williams <williams@redhat.com>2017-09-26 10:14:29 -0500
committerClark Williams <williams@redhat.com>2017-09-26 10:14:29 -0500
commitd20362ba7158aaddbd5af9dac76ed5d951fa1231 (patch)
tree1e72b6afed56a629e22883e2221160e7481ceb5e
parent74432794f6bf0bcb984cf53982e9495163b76b3a (diff)
downloadrteval-d20362ba7158aaddbd5af9dac76ed5d951fa1231.tar.gz
remove unused file rteval/rteval.py
Signed-off-by: Clark Williams <williams@redhat.com>
-rw-r--r--rteval/rteval.py1035
1 files changed, 0 insertions, 1035 deletions
diff --git a/rteval/rteval.py b/rteval/rteval.py
deleted file mode 100644
index 0d1b02f..0000000
--- a/rteval/rteval.py
+++ /dev/null
@@ -1,1035 +0,0 @@
-#!/usr/bin/python -tt
-#
-# 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,2010,2011,2012 Clark Williams <williams@redhat.com>
-# Copyright 2009,2010,2011,2012 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
-import os
-import os.path
-import time
-import string
-import threading
-import subprocess
-import socket
-import optparse
-import tempfile
-import statvfs
-import shutil
-import signal
-import rtevalclient
-import ethtool
-import xmlrpclib
-import platform
-import fnmatch
-import glob
-from datetime import datetime
-from distutils import sysconfig
-
-# put local path at start of list to overide installed methods
-sys.path.insert(0, "./rteval")
-import util
-import load
-import cyclictest
-import xmlout
-import dmi
-import rtevalConfig
-import rtevalMailer
-from cputopology import CPUtopology
-
-
-pathSave={}
-def getcmdpath(which):
- """
- getcmdpath is a method which allows finding an executable in the PATH
- directories to call it from full path
- """
- if not pathSave.has_key(which):
- for path in os.environ['PATH'].split(':'):
- cmdfile = os.path.join(path, which)
- if os.path.isfile(cmdfile) and os.access(cmdfile, os.X_OK):
- pathSave[which] = cmdfile
- break
- if not pathSave[which]:
- raise RuntimeError, "Command '%s' is unknown on this system" % which
- return pathSave[which]
-
-
-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(object):
- def __init__(self, cmdargs):
- self.version = "1.41"
- self.load_modules = []
- self.workdir = os.getcwd()
- self.reportdir = os.getcwd()
- self.inifile = None
- self.cmd_options = {}
- self.start = datetime.now()
- self.init = 'unknown'
-
- default_config = {
- 'rteval': {
- 'verbose' : False,
- 'keepdata' : True,
- 'debugging' : False,
- 'duration' : '60',
- 'sysreport' : False,
- 'reportdir' : None,
- 'reportfile' : None,
- 'installdir' : '/usr/share/rteval',
- 'srcdir' : '/usr/share/rteval/loadsource',
- 'xmlrpc' : None,
- 'xslt_report': '/usr/share/rteval/rteval_text.xsl',
- 'report_interval': '600',
- 'logging' : False,
- },
- 'loads' : {
- 'kcompile' : 'module',
- 'hackbench' : 'module',
- },
- 'kcompile' : {
- 'source' : 'linux-2.6.39.tar.bz2',
- 'jobspercore': '2',
- },
- 'hackbench' : {
- 'source' : 'hackbench.tar.bz2',
- 'jobspercore': '5',
- },
- 'cyclictest' : {
- 'interval' : '100',
- 'buckets' : '2000',
- }
- }
-
- # setup initial configuration
- self.config = rtevalConfig.rtevalConfig(default_config, logfunc=self.info)
-
- # parse command line options
- self.parse_options(cmdargs)
-
- # read in config file info
- self.inifile = self.config.Load(self.cmd_options.inifile)
-
- # copy the command line options into the rteval config section
- # (cmd line overrides config file values)
- self.config.AppendConfig('rteval', self.cmd_options)
-
- if self.cmd_options.cyclictest_interval != None:
- self.config.AppendConfig('cyclictest', { "interval":self.cmd_options.cyclictest_interval })
-
- if self.cmd_options.cyclictest_distance != None:
- self.config.AppendConfig('cyclictest', { "distance":self.cmd_options.cyclictest_distance })
-
- if self.cmd_options.cyclictest_buckets != None:
- self.config.AppendConfig('cyclictest', { "buckets":self.cmd_options.cyclictest_distance })
-
- if self.cmd_options.cyclictest_priority != None:
- self.config.AppendConfig('cyclictest', { "priority":self.cmd_options.cyclictest_priority })
-
- if self.cmd_options.hackbench_jobspercore != None:
- self.config.AppendConfig('hackbench', { "jobspercore":self.cmd_options.hackbench_jobspercore })
-
- if self.cmd_options.kcompile_jobspercore != None:
- self.config.AppendConfig('kcompile', { "jobspercore":self.cmd_options.kcompile_jobspercore })
-
- self.debug("workdir: %s" % self.workdir)
-
- # prepare a mailer, if that's configured
- if self.config.HasSection('smtp'):
- self.mailer = rtevalMailer.rtevalMailer(self.config.GetSection('smtp'))
- else:
- self.mailer = None
-
- self.loads = []
- self.cputopology = None
- self.numcores = None
- self.memsize = None
- self.current_clocksource = None
- self.available_clocksource = None
- self.services = None
- 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")
-
- if not os.path.exists(self.config.xslt_report):
- raise RuntimeError, "can't find XSL template (%s)!" % self.config.xslt_report
-
- # Add rteval directory into module search path
- sys.path.insert(0, '%s/rteval' % sysconfig.get_python_lib())
-
- # generate a set of "junk" characters to use for filtering later
- self.junk = ""
- for c in range(0, 0xff):
- s = chr(c)
- if s not in string.printable:
- self.junk += s
- self.transtable = string.maketrans("", "")
-
- # If --xmlrpc-submit is given, check that we can access the server
- res = None
- if self.config.xmlrpc:
- self.debug("Checking if XML-RPC server '%s' is reachable" % self.config.xmlrpc)
- 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)"
- % (res["server"], res["APIversion"]))
- self.debug("Recieved greeting: %s" % res["greeting"])
-
-
- def get_cpu_topology(self):
- ''' figure out how many processors we have available'''
-
- topology = CPUtopology()
- topology.parse()
-
- self.numcores = topology.getCPUcores(True)
- self.debug("counted %d cores (%d online) and %d sockets" %
- (topology.getCPUcores(False), self.numcores,
- topology.getCPUsockets()))
- return topology.getXMLdata()
-
- def __get_services_sysvinit(self):
- reject = ('functions', 'halt', 'killall', 'single', 'linuxconf', 'kudzu',
- 'skeleton', 'README', '*.dpkg-dist', '*.dpkg-old', 'rc', 'rcS',
- 'single', 'reboot', 'bootclean.sh')
- for sdir in ('/etc/init.d', '/etc/rc.d/init.d'):
- if os.path.isdir(sdir):
- servicesdir = sdir
- break
- if not servicesdir:
- raise RuntimeError, "No services dir (init.d) found on your system"
- self.debug("Services located in %s, going through each service file to check status" % servicesdir)
- ret_services = {}
- for service in glob.glob(os.path.join(servicesdir, '*')):
- servicename = os.path.basename(service)
- if not [1 for p in reject if fnmatch.fnmatch(servicename, p)] and os.access(service, os.X_OK):
- cmd = '%s -qs "\(^\|\W\)status)" %s' % (getcmdpath('grep'), service)
- c = subprocess.Popen(cmd, shell=True)
- c.wait()
- if c.returncode == 0:
- cmd = ['env', '-i', 'LANG="%s"' % os.environ['LANG'], 'PATH="%s"' % os.environ['PATH'], 'TERM="%s"' % os.environ['TERM'], service, 'status']
- c = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- c.wait()
- if c.returncode == 0 and (c.stdout.read() or c.stderr.read()):
- ret_services[servicename] = 'running'
- else:
- ret_services[servicename] = 'not running'
- else:
- ret_services[servicename] = 'unknown'
- return ret_services
-
- def __get_services_systemd(self):
- ret_services = {}
- cmd = '%s list-unit-files -t service --no-legend' % getcmdpath('systemctl')
- self.debug("cmd: %s" % cmd)
- c = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- for p in c.stdout:
- # p are lines like "servicename.service status"
- v = p.strip().split()
- ret_services[v[0].split('.')[0]] = v[1]
- return ret_services
-
- def get_services(self):
- cmd = [getcmdpath('ps'), '-ocomm=', '1']
- c = subprocess.Popen(cmd, stdout=subprocess.PIPE)
- self.init = c.stdout.read().strip()
- if self.init == 'systemd':
- self.debug("Using systemd to get services status")
- return self.__get_services_systemd()
- elif self.init == 'init':
- self.init = 'sysvinit'
- self.debug("Using sysvinit to get services status")
- return self.__get_services_sysvinit()
- else:
- raise RuntimeError, "Unknown init system (%s)" % self.init
- return {}
-
- def get_kthreads(self):
- policies = {'FF':'fifo', 'RR':'rrobin', 'TS':'other', '?':'unknown' }
- ret_kthreads = {}
- self.debug("getting kthread status")
- cmd = '%s -eocommand,pid,policy,rtprio,comm' % getcmdpath('ps')
- self.debug("cmd: %s" % cmd)
- c = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
- for p in c.stdout:
- v = p.strip().split()
- kcmd = v.pop(0)
- try:
- if int(v[0]) > 0 and kcmd.startswith('[') and kcmd.endswith(']'):
- ret_kthreads[v[0]] = {'policy' : policies[v[1]],
- 'priority' : v[2], 'name' : v[3] }
- except ValueError:
- pass # Ignore lines which don't have a number in the first row
- return ret_kthreads
-
- def get_modules(self):
- modlist = []
- try:
- fp = open('/proc/modules', 'r')
- line = fp.readline()
- while line:
- mod = line.split()
- modlist.append({"modname": mod[0],
- "modsize": mod[1],
- "numusers": mod[2],
- "usedby": mod[3],
- "modstate": mod[4]})
- line = fp.readline()
- fp.close()
- except Exception, err:
- raise err
- return modlist
-
- def parse_options(self, cmdargs):
- '''parse the command line arguments'''
- parser = optparse.OptionParser()
- parser.add_option("-d", "--duration", dest="duration",
- type="string", default=self.config.duration,
- help="specify length of test run (default: %default)")
- parser.add_option("-v", "--verbose", dest="verbose",
- action="store_true", default=self.config.verbose,
- help="turn on verbose prints (default: %default)")
- parser.add_option("-w", "--workdir", dest="workdir",
- type="string", default=self.workdir,
- help="top directory for rteval data (default: %default)")
- parser.add_option("-l", "--loaddir", dest="srcdir",
- type="string", default=self.config.srcdir,
- help="directory for load source tarballs (default: %default)")
- parser.add_option("-i", "--installdir", dest="installdir",
- type="string", default=self.config.installdir,
- help="place to locate installed templates (default: %default)")
- parser.add_option("-s", "--sysreport", dest="sysreport",
- action="store_true", default=self.config.sysreport,
- help='run sysreport to collect system data (default: %default)')
- parser.add_option("-D", '--debug', dest='debugging',
- action='store_true', default=self.config.debugging,
- help='turn on debug prints (default: %default)')
- 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')
- parser.add_option("-H", '--raw-histogram', dest='rawhistogram',
- action='store_true', default=False,
- help='Generate raw histogram data for an already existing XML report')
- 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")
- parser.add_option("-L", "--logging", dest="logging",
- action='store_true', default=False,
- help='log the output of the loads in the report directory')
- parser.add_option("-O", "--onlyload", dest="onlyload",
- action='store_true', default=False,
- help="only run the loads (don't run measurement threads)")
-
- # module options
- parser.add_option("", "--cyclictest-interval", dest="cyclictest_interval",
- action="store", type="int",
- help="cyclictest measurement interval in microseconds")
- parser.add_option("", "--cyclictest-distance", dest="cyclictest_distance",
- action="store", type="int",
- help="cyclictest measurement interval increment in microseconds")
- parser.add_option("", "--cyclictest-buckets", dest="cyclictest_buckets",
- action="store", type="int",
- help="number of cyclictest 1 microsecond histogram buckets")
- parser.add_option("", "--cyclictest-priority", dest="cyclictest_priority",
- action="store", type="int",
- help="SCHED_FIFO priority of measurement threads")
-
- parser.add_option("", "--hackbench-jobspercore", dest="hackbench_jobspercore",
- action="store", type="int",
- help="number of hackbench jobs per-core")
- parser.add_option("", "--kcompile-jobspercore", dest="kcompile_jobspercore",
- action="store", type="int",
- help="number of kernel compile jobs per-core")
-
-
- (self.cmd_options, self.cmd_arguments) = parser.parse_args(args = cmdargs)
- if self.cmd_options.duration:
- mult = 1.0
- v = self.cmd_options.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
- self.cmd_options.duration = float(v) * mult
- self.workdir = os.path.abspath(self.cmd_options.workdir)
-
-
- def debug(self, str):
- if self.config.debugging is True:
- print "rteval: %s" % str
-
- def info(self, str):
- if self.config.verbose is True:
- print str
-
- def run_sysreport(self):
- import glob
- if os.path.exists('/usr/sbin/sosreport'):
- exe = '/usr/sbin/sosreport'
- elif os.path.exists('/usr/sbin/sysreport'):
- exe = '/usr/sbin/sysreport'
- else:
- raise RuntimeError, "Can't find sosreport/sysreport"
-
- self.debug("report tool: %s" % exe)
- options = ['-k', 'rpm.rpmva=off',
- '--name=rteval',
- '--batch',
- '--no-progressbar']
-
- self.info("Generating SOS report")
- self.info("using command %s" % " ".join([exe]+options))
- subprocess.call([exe] + options)
- for s in glob.glob('/tmp/s?sreport-rteval-*'):
- self.debug("moving %s to %s" % (s, self.reportdir))
- shutil.move(s, self.reportdir)
-
-
- def genxml(self, duration, accum, samples, xslt = None):
- seconds = duration.seconds
- hours = seconds / 3600
- if hours: seconds -= (hours * 3600)
- minutes = seconds / 60
- if minutes: seconds -= (minutes * 60)
- (sys, node, release, ver, machine) = os.uname()
-
- # Start new XML report
- self.xmlreport = xmlout.XMLOut('rteval', self.version)
- self.xmlreport.NewReport()
-
- self.xmlreport.openblock('run_info', {'days': duration.days,
- 'hours': hours,
- 'minutes': minutes,
- '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)
- isrt = 1
- if ver.find(' RT ') == -1:
- isrt = 0
- self.xmlreport.taggedvalue('kernel', release, {'is_RT':isrt})
- self.xmlreport.taggedvalue('arch', machine)
- self.xmlreport.taggedvalue('baseos', self.baseos)
- self.xmlreport.closeblock()
-
- self.xmlreport.openblock("clocksource")
- self.xmlreport.taggedvalue('current', self.current_clocksource)
- self.xmlreport.taggedvalue('available', self.available_clocksource)
- self.xmlreport.closeblock()
-
- self.xmlreport.openblock('hardware')
- self.xmlreport.AppendXMLnodes(self.cputopology)
- self.xmlreport.taggedvalue('numa_nodes', self.numanodes)
- self.xmlreport.taggedvalue('memory_size', "%.3f" % self.memsize[0], {"unit": self.memsize[1]})
- self.xmlreport.closeblock()
-
- self.xmlreport.openblock('services', {'init': self.init})
- for s in self.services:
- self.xmlreport.taggedvalue("service", self.services[s], {"name": s})
- self.xmlreport.closeblock()
-
- keys = self.kthreads.keys()
- if len(keys):
- keys.sort()
- self.xmlreport.openblock('kthreads')
- for pid in keys:
- self.xmlreport.taggedvalue('thread', self.kthreads[pid]['name'],
- { 'policy' : self.kthreads[pid]['policy'],
- 'priority' : self.kthreads[pid]['priority'],
- })
- self.xmlreport.closeblock()
-
- modlist = util.get_modules()
- if len(modlist):
- self.xmlreport.openblock('kernelmodules')
- for mod in modlist:
- self.xmlreport.openblock('module')
- self.xmlreport.taggedvalue('info', mod['modname'],
- {'size': mod['modsize'],
- 'state': mod['modstate'],
- 'numusers': mod['numusers']})
- if mod['usedby'] != '-':
- self.xmlreport.openblock('usedby')
- for ub in mod['usedby'].split(','):
- if len(ub):
- self.xmlreport.taggedvalue('module', ub, None)
- self.xmlreport.closeblock()
- self.xmlreport.closeblock()
- self.xmlreport.closeblock()
-
- #
- # Retrieve configured IP addresses
- #
- self.xmlreport.openblock('network_config')
-
- # Get the interface name for the IPv4 default gw
- route = open('/proc/net/route')
- defgw4 = None
- if route:
- rl = route.readline()
- while rl != '' :
- rl = route.readline()
- splt = rl.split("\t")
- # Only catch default route
- if len(splt) > 2 and splt[2] != '00000000' and splt[1] == '00000000':
- defgw4 = splt[0]
- break
- route.close()
-
- # Make an interface tag for each device found
- if hasattr(ethtool, 'get_interfaces_info'):
- # Using the newer python-ethtool API (version >= 0.4)
- for dev in ethtool.get_interfaces_info(ethtool.get_devices()):
- if cmp(dev.device,'lo') == 0:
- continue
-
- self.xmlreport.openblock('interface',
- {'device': dev.device,
- 'hwaddr': dev.mac_address}
- )
-
- # Protcol configurations
- if dev.ipv4_address:
- self.xmlreport.openblock('IPv4',
- {'ipaddr': dev.ipv4_address,
- 'netmask': dev.ipv4_netmask,
- 'broadcast': dev.ipv4_broadcast,
- 'defaultgw': (defgw4 == dev.device) and '1' or '0'}
- )
- self.xmlreport.closeblock()
-
- for ip6 in dev.get_ipv6_addresses():
- self.xmlreport.openblock('IPv6',
- {'ipaddr': ip6.address,
- 'netmask': ip6.netmask,
- 'scope': ip6.scope}
- )
- self.xmlreport.closeblock()
- self.xmlreport.closeblock()
- else: # Fall back to older python-ethtool API (version < 0.4)
- ifdevs = ethtool.get_active_devices()
- ifdevs.remove('lo')
- ifdevs.sort()
-
- for dev in ifdevs:
- self.xmlreport.openblock('interface',
- {'device': dev,
- 'hwaddr': ethtool.get_hwaddr(dev)}
- )
- self.xmlreport.openblock('IPv4',
- {'ipaddr': ethtool.get_ipaddr(dev),
- 'netmask': ethtool.get_netmask(dev),
- 'defaultgw': (defgw4 == dev) and '1' or '0'}
- )
- self.xmlreport.closeblock()
- self.xmlreport.closeblock()
- self.xmlreport.closeblock()
-
- self.xmlreport.openblock('loads', {'load_average':str(accum / samples)})
- for load in self.loads:
- load.genxml(self.xmlreport)
- self.xmlreport.closeblock()
- self.cyclictest.genxml(self.xmlreport)
-
- # now generate the dmidecode data for this host
- d = dmi.DMIinfo(self.config.GetSection('rteval'))
- d.genxml(self.xmlreport)
-
- # Close the report - prepare for return the result
- self.xmlreport.close()
-
- # Write XML (or write XSLT parsed XML if xslt != None)
- if self.xml != None:
- self.xmlreport.Write(self.xml, xslt)
- else:
- # If no file is set, use stdout
- self.xmlreport.Write("-", xslt) # libxml2 defines a filename as "-" to be stdout
-
-
- def report(self):
- "Create a screen report, based on a predefined XSLT template"
- self.xmlreport.Write("-", self.config.xslt_report)
-
- def XMLreport(self):
- "Retrieves the complete rteval XML report as a libxml2.xmlDoc object"
- return self.xmlreport.GetXMLdocument()
-
- def show_report(self, xmlfile, xsltfile):
- '''summarize a previously generated xml file'''
- print "Loading %s for summarizing" % xmlfile
-
- xsltfullpath = os.path.join(self.config.installdir, xsltfile)
- if not os.path.exists(xsltfullpath):
- raise RuntimeError, "can't find XSL template (%s)!" % xsltfullpath
-
- xmlreport = xmlout.XMLOut('rteval', self.version)
- xmlreport.LoadReport(xmlfile)
- xmlreport.Write('-', xsltfullpath)
- del xmlreport
-
- def start_loads(self):
- if len(self.loads) == 0:
- raise RuntimeError, "start_loads: No loads defined!"
- self.info ("starting loads:")
- for l in self.loads:
- l.start()
- # now wait until they're all ready
- self.info("waiting for ready from all loads")
- ready=False
- while not ready:
- busy = 0
- for l in self.loads:
- if not l.isAlive():
- raise RuntimeError, "%s died" % l.name
- if not l.isReady():
- busy += 1
- self.debug("waiting for %s" % l.name)
- if busy:
- time.sleep(1.0)
- else:
- ready = True
-
- def stop_loads(self):
- if len(self.loads) == 0:
- raise RuntimeError, "stop_loads: No loads defined!"
- self.info("stopping loads: ")
- for l in self.loads:
- self.info("\t%s" % l.name)
- l.stopevent.set()
- l.join(2.0)
-
- def make_report_dir(self):
- t = self.start
- i = 1
- self.reportdir = os.path.join(self.workdir,
- t.strftime("rteval-%Y%m%d-"+str(i)))
- while os.path.exists(self.reportdir):
- i += 1
- self.reportdir = os.path.join(self.workdir,
- t.strftime('rteval-%Y%m%d-'+str(i)))
- if not os.path.isdir(self.reportdir):
- os.mkdir(self.reportdir)
- os.mkdir(os.path.join(self.reportdir, "logs"))
- return self.reportdir
-
- def get_dmesg(self):
- dpath = "/var/log/dmesg"
- if not os.path.exists(dpath):
- print "dmesg file not found at %s" % dpath
- return
- shutil.copyfile(dpath, os.path.join(self.reportdir, "dmesg"))
-
-
- 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 measure(self):
- # Collect misc system info
- self.baseos = util.get_base_os()
- self.cputopology = self.get_cpu_topology()
- self.numanodes = util.get_num_nodes()
- self.memsize = util.get_memory_size()
- (self.current_clocksource, self.available_clocksource) = util.get_clocksources()
- self.services = self.get_services()
- self.kthreads = self.get_kthreads()
-
- onlyload = self.cmd_options.onlyload
-
- builddir = os.path.join(self.workdir, 'rteval-build')
- if not os.path.isdir(builddir): os.mkdir(builddir)
- self.reportfile = os.path.join(self.reportdir, "summary.rpt")
- self.xml = os.path.join(self.reportdir, "summary.xml")
-
- # read in loads from the ini file
- self.load_modules = []
- loads = self.config.GetSection("loads")
- for l in loads:
- # hope to eventually have different kinds but module is only on
- # for now (jcw)
- if l[1].lower() == 'module':
- self.info("importing load module %s" % l[0])
- self.load_modules.append(__import__(l[0]))
-
- self.info("setting up loads")
- self.loads = []
- params = {'workdir':self.workdir,
- 'reportdir':self.reportdir,
- 'builddir':builddir,
- 'srcdir':self.config.srcdir,
- 'verbose': self.config.verbose,
- 'debugging': self.config.debugging,
- 'numcores':self.numcores,
- 'logging':self.config.logging,
- 'memsize':self.memsize,
- 'numanodes':self.numanodes,
- 'duration':self.config.duration,
- }
-
- for m in self.load_modules:
- self.config.AppendConfig(m.__name__, params)
- self.info("creating load instance for %s" % m.__name__)
- self.loads.append(m.create(self.config.GetSection(m.__name__)))
-
- if not onlyload:
- self.config.AppendConfig('cyclictest', params)
- self.info("setting up cyclictest")
- self.cyclictest = cyclictest.Cyclictest(params=self.config.GetSection('cyclictest'))
-
- nthreads = 0
- try:
- # start the loads
- self.start_loads()
-
- print "rteval run on %s started at %s" % (os.uname()[2], time.asctime())
- print "started %d loads on %d cores" % (len(self.loads), self.numcores),
- if self.numanodes > 1:
- print " with %d numa nodes" % self.numanodes
- else:
- print ""
- print "Run duration: %d seconds" % self.config.duration
-
- start = datetime.now()
-
- if not onlyload:
- # start the cyclictest thread
- self.info("starting cyclictest")
- self.cyclictest.start()
-
- # turn loose the loads
- self.info("sending start event to all loads")
- for l in self.loads:
- l.startevent.set()
- nthreads += 1
-
- accum = 0.0
- samples = 0
-
- report_interval = int(self.config.GetSection('rteval').report_interval)
-
- # wait for time to expire or thread to die
- signal.signal(signal.SIGINT, sigint_handler)
- signal.signal(signal.SIGTERM, sigterm_handler)
- self.info("waiting for duration (%f)" % self.config.duration)
- stoptime = (time.time() + self.config.duration)
- currtime = time.time()
- rpttime = currtime + report_interval
- loadcount = 5
- while (currtime <= stoptime) and not sigint_received:
- time.sleep(1.0)
- if not onlyload and not self.cyclictest.isAlive():
- raise RuntimeError, "cyclictest thread died!"
- if len(threading.enumerate()) < nthreads:
- raise RuntimeError, "load thread died!"
- if not loadcount:
- # open the loadavg /proc entry
- p = open("/proc/loadavg")
- load = float(p.readline().split()[0])
- p.close()
- accum += load
- samples += 1
- loadcount = 5
- #self.debug("current loadavg: %f, running avg: %f (load: %f, samples: %d)" % \
- # (load, accum/samples, load, samples))
- else:
- loadcount -= 1
- if currtime >= rpttime:
- left_to_run = stoptime - currtime
- self.show_remaining_time(left_to_run)
- rpttime = currtime + report_interval
- print "load average: %.2f" % (accum / samples)
- currtime = time.time()
- self.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:
- if not onlyload:
- # stop cyclictest
- self.cyclictest.stopevent.set()
-
- # stop the loads
- self.stop_loads()
-
- print "stopping run at %s" % time.asctime()
- if not onlyload:
- # wait for cyclictest to finish calculating stats
- self.cyclictest.finished.wait()
- self.genxml(datetime.now() - start, accum, samples)
- self.report()
- if self.config.sysreport:
- self.run_sysreport()
-
-
- def XMLRPC_Send(self):
- "Sends the report to a given XML-RPC host. Returns 0 on success or 2 on submission failure."
-
- if not self.config.xmlrpc:
- return 2
-
- url = "http://%s/rteval/API1/" % self.config.xmlrpc
- attempt = 0
- exitcode = 2 # Presume failure
- warning_sent = False
- while attempt < 6:
- try:
- client = rtevalclient.rtevalclient(url)
- print "Submitting report to %s" % url
- rterid = client.SendReport(self.xmlreport.GetXMLdocument())
- print "Report registered with submission id %i" % rterid
- attempt = 10
- exitcode = 0 # Success
- except socket.error:
- if (self.mailer is not None) and (not warning_sent):
- self.mailer.SendMessage("[RTEVAL:WARNING] Failed to submit report to XML-RPC server",
- "Server %s did not respond. Not giving up yet."
- % self.config.xmlrpc)
- warning_sent = True
-
- attempt += 1
- if attempt > 5:
- break # To avoid sleeping before we abort
-
- print "Failed sending report. Doing another attempt(%i) " % attempt
- time.sleep(attempt*5*60) # Incremental sleep - sleep attempts*5 minutes
-
- except Exception, err:
- raise err
-
- if (self.mailer is not None):
- # Send final result messages
- if exitcode == 2:
- self.mailer.SendMessage("[RTEVAL:FAILURE] Failed to submit report to XML-RPC server",
- "Server %s did not respond at all after %i attempts."
- % (self.config.xmlrpc, attempt - 1))
- elif (exitcode == 0) and warning_sent:
- self.mailer.SendMessage("[RTEVAL:SUCCESS] XML-RPC server available again",
- "Succeeded to submit the report to %s in the end."
- % (self.config.xmlrpc))
- return exitcode
-
-
- def tar_results(self):
- if not os.path.isdir(self.reportdir):
- raise RuntimeError, "no such directory: %s" % self.reportdir
- import tarfile
- dirname = os.path.dirname(self.reportdir)
- rptdir = os.path.basename(self.reportdir)
- cwd = os.getcwd()
- os.chdir(dirname)
- try:
- t = tarfile.open(rptdir + ".tar.bz2", "w:bz2")
- t.add(rptdir)
- t.close()
- except:
- os.chdir(cwd)
-
- def summarize(self, file):
- isarchive = False
- summary = file
- if file.endswith(".tar.bz2"):
- import tarfile
- try:
- t = tarfile.open(file)
- except:
- print "Don't know how to summarize %s (tarfile open failed)" % file
- 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" % file
- return
- tmp = tempfile.gettempdir()
- self.debug("extracting %s from %s for summarizing" % (element, file))
- t.extract(element, path=tmp)
- summary = os.path.join(tmp, element)
- isarchive = True
- self.show_report(summary, 'rteval_text.xsl')
- if isarchive:
- os.unlink(summary)
-
- def rteval(self):
- ''' 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:
- raise RuntimeError, "Must specify at least one XML file with --summarize!"
-
- for x in self.cmd_arguments:
- if self.cmd_options.summarize:
- self.summarize(x)
- elif self.cmd_options.rawhistogram:
- self.show_report(x, 'rteval_histogram_raw.xsl')
-
- sys.exit(0)
-
- if os.getuid() != 0:
- print "Must be root to run rteval!"
- sys.exit(-1)
-
- self.debug('''rteval options:
- workdir: %s
- loaddir: %s
- reportdir: %s
- verbose: %s
- debugging: %s
- logging: %s
- duration: %f
- sysreport: %s
- inifile: %s''' % (self.workdir, self.config.srcdir, self.reportdir, self.config.verbose,
- self.config.debugging, self.config.logging, self.config.duration,
- self.config.sysreport, self.inifile))
-
- if not os.path.isdir(self.workdir):
- raise RuntimeError, "work directory %d does not exist" % self.workdir
-
- # create our report directory
- try:
- self.make_report_dir()
- except:
- print "Cannot create the report dir!"
- print "(is this an NFS filesystem with rootsquash turned on?)"
- sys.exit(-1)
-
- self.measure()
-
- # if --xmlrpc-submit | -X was given, send our report to this host
- if self.config.xmlrpc:
- retval = self.XMLRPC_Send()
-
- self.get_dmesg()
- self.tar_results()
-
- return retval
-
-if __name__ == '__main__':
- import pwd, grp
-
- try:
- # Parse initial DMI decoding errors
- dmi.ProcessWarnings()
-
- rteval = RtEval(sys.argv[1:])
- ec = rteval.rteval()
- rteval.debug("exiting with exit code: %d" % ec)
- sys.exit(ec)
- except KeyboardInterrupt:
- sys.exit(0)