#!/usr/bin/python
# profile reporter
import sys, os, operator, string
from optparse import OptionParser
from glob import glob
from subprocess import Popen, PIPE
import tarfile
class GlobalVars:
def __init__(self):
pass
class MyWriter:
def __init__(self, stdout, filename):
self.stdout = stdout
self.logfile = file(filename, 'w')
def write(self, text):
self.stdout.write(text)
self.logfile.write(text)
def close(self):
self.stdout.close()
self.logfile.close()
def parse_options(opts):
""" parse cmd line opts """
parser = OptionParser()
parser.add_option("-f","--filename", dest="filename",
help="write report to FILENAME")
parser.add_option("-t", "--time", dest="rtime",
help="set minimum RUNTIME to report", action="store",
default=float(0.1), type="float")
parser.add_option("-i", "--input", dest="rpt_dir",
help="define directory of sosreport archives",
action="store", default=False)
GlobalVars.cmdlineopts, GlobalVars.cmdlineargs = parser.parse_args(opts)
if not GlobalVars.cmdlineopts.rpt_dir:
raise SystemExit("\nPlease make sure to specify --input FILES\n")
def uncompress_reports(fname):
""" uncompresses the sosreport """
p = Popen(["xz","-d", fname], stdout=PIPE, stdin=PIPE)
out, err = p.communicate()
if err:
print "Problem extracting %s" % (fname,)
return
def read_archive(fname):
""" reads tarfile archive and grabs the sosprofile.log fileobj """
tar = tarfile.open(os.path.abspath(fname), "r:")
for tarinfo in tar.getmembers():
if 'sosprofile.log' in tarinfo.name:
fobj = tar.extractfile(tarinfo)
buf = fobj.read()
tar.close()
return buf
def timeoutput(secs):
if secs > 60:
secs = round(secs) / 60
return (secs, 'm')
elif secs < 60:
return (secs, 's')
def sort_profile():
""" provide reports on sosreport profiling """
# uncompress reports from input files
for rpt in glob(GlobalVars.cmdlineopts.rpt_dir+"/*.xz"):
uncompress_reports(os.path.abspath(rpt))
GlobalVars.rpt_count = 0
GlobalVars.timecount = 0
GlobalVars.lrc = {}
for rpt in glob(GlobalVars.cmdlineopts.rpt_dir+"/*.tar"):
buf = read_archive(rpt)
time_sorts=[]
if not buf:
continue
for line in buf.split("\n"):
try:
cmd, rtime = line.split("time:")
try:
# cmds that span multiple lines still need time calculated
cmd = cmd.split(":")[1]
except IndexError:
cmd, rtime = line.split("time:")
time_sorts.append((cmd.strip(), rtime.strip()))
except ValueError:
continue
time_count = 0
b_val_count = 0
write_stats = open(rpt + ".profile_report", 'w')
write_stats.write(28 * ' ' + 'SOSreport Profile Report' + 27 * ' ' + "\n")
write_stats.write(79 * '.' + "\n")
for a,b in sorted(time_sorts, key=operator.itemgetter(1)):
b_val = float(b)
time_count += b_val
if b_val > float(GlobalVars.cmdlineopts.rtime):
b_val_count += b_val
write_stats.write("%-79s %s\n" % (a[:78], b))
if GlobalVars.lrc.has_key(a) and \
GlobalVars.lrc[a] < b_val:
GlobalVars.lrc[a] = b_val
else:
GlobalVars.lrc[a] = b_val
# Keep up with total run time for all reports
GlobalVars.timecount += time_count
# Write out totals per report
write_stats.write(79 * '.' + "\n")
write_stats.write("Totals:\n")
secs, fmt = timeoutput(b_val_count)
write_stats.write("cumulative > %s: \t%f%s\n" % (GlobalVars.cmdlineopts.rtime, secs, fmt))
secs, fmt = timeoutput(time_count)
write_stats.write("cumulative total:\t%f%s\n" % (secs,fmt))
write_stats.close()
# increment report count so we can get an average runtime
GlobalVars.rpt_count += 1
if __name__ == "__main__":
parse_options(sys.argv[1:])
if GlobalVars.cmdlineopts.filename:
writer = MyWriter(sys.stdout, GlobalVars.cmdlineopts.filename)
sys.stdout = writer
print "Building reports ..."
sort_profile()
print 79 * "-"
print "Total runtime for %d reports is %fs" % (round(GlobalVars.rpt_count, 2), GlobalVars.timecount)
print "Average total runtime of %d reports is %fs" % (round(GlobalVars.rpt_count, 2), GlobalVars.timecount / GlobalVars.rpt_count)
print 79 * "-"
print
print "Longest running commands > %s:" % (GlobalVars.cmdlineopts.rtime,)
print 79 * "-"
for cmd, rtime in sorted(GlobalVars.lrc.iteritems(), key=operator.itemgetter(1)):
print "%-75s %s" % (cmd[:69], rtime)
if GlobalVars.cmdlineopts.filename:
print 79 * "-"
print "Report log written to: %s" % (GlobalVars.cmdlineopts.filename,)
writer.close()