blob: 3aaacef80a193640d4dc0a56b7f6156962e5ee0d [file] [log] [blame]
import cPickle
import os
import re
import math
import time
def format_hist(h, units=1):
retval = []
if not h:
h[0] = 0
total = sum(h.values())
keys = sorted(h.keys())
min_key = min(keys)
max_key = max(keys)
for i in range(min_key, max_key + 1):
n = h.get(i, 0)
if total > 0:
percentage = " %8.2f%%" % (n * 100. / total)
else:
percentage = ''
retval.append("%3i: %8i%s"
% (i * units, n, percentage))
return "\n".join(retval)
def scan_builder(builder, starttime, endtime, minutes_per_block, times, change_as_submittime=True):
"""Scans the build pickle files in the builder directory, and updates the dictionary `times`."""
if not os.path.exists(builder):
return
for f in os.listdir(builder):
if re.match("^\d+$", f):
try:
b = cPickle.load(open('%s/%s' % (builder, f)))
except:
continue
if 'rebuild' in b.reason:
# Skip rebuilds, they mess up the wait times
continue
if change_as_submittime:
if len(b.changes) == 0:
continue
submittime = b.changes[0].when
else:
submittime = b.requests[0].submittedAt
if starttime < submittime < endtime:
w = int(math.floor(
(b.started - submittime) / (minutes_per_block * 60.0)))
times[w] = times.get(w, 0) + 1
if __name__ == "__main__":
from optparse import OptionParser
parser = OptionParser()
parser.set_defaults(
minutes_per_block=15,
change_as_submittime=True,
name=os.uname()[1],
builders={},
directory=None,
starttime=time.time() - 24 * 3600,
endtime=time.time(),
)
def add_builder(option, opt_str, value, parser, *args, **kwargs):
if ":" in value:
platform, builders = value.split(":", 1)
builders = [b.strip() for b in builders.split(",")]
else:
platform = value
builders = [platform]
if platform not in parser.values.builders:
parser.values.builders[platform] = []
parser.values.builders[platform].extend(builders)
parser.add_option("-m", "--minutes-per-block", type="int", help="How many minutes per block", dest="minutes_per_block")
parser.add_option("-r", "--request-as-submittime",
action="store_false", dest="change_as_submittime")
parser.add_option("-n", "--name", dest="name")
parser.add_option("-b", "--builders", dest="builders", action="callback", nargs=1, type="string", callback=add_builder, help="platform:builder1,builder2,...")
parser.add_option("-d", "--directory", dest="directory")
parser.add_option("-s", "--start-time", dest="starttime", type="int")
parser.add_option("-e", "--end-time", dest="endtime", type="int")
parser.add_option("-a", "--address", dest="addresses", action="append")
parser.add_option("-S", "--smtp", dest="smtp")
parser.add_option("-f", "--from", dest="sender")
options, args = parser.parse_args()
if not options.builders:
parser.error("Must specify some builders")
if options.directory:
os.chdir(options.directory)
text = []
text.append("Wait time report for %s for jobs submitted since %s\n"
% (options.name, time.ctime(options.starttime)))
hist = {}
for platform, builders in options.builders.items():
hist[platform] = {}
for builder in builders:
scan_builder(builder, options.starttime, options.endtime,
options.minutes_per_block, hist[platform],
options.change_as_submittime)
allhist = {}
for i in set([x for y in hist.keys() for x in hist[y]]):
allhist[i] = sum([p.get(i, 0) for p in hist.values()])
total = sum(allhist.values())
text.append("Total Jobs: %i\n" % total)
text.append("Wait Times")
text.append(format_hist(allhist, options.minutes_per_block))
text.append("\nPlatform break down\n")
for platform, builders in options.builders.items():
text.append("%s: %i" % (platform, sum(hist[platform].values())))
text.append(format_hist(hist[platform], options.minutes_per_block))
text.append("\n")
text.append("The number on the left is how many minutes a build waited to start, rounded down")
if not options.addresses:
print "\n".join(text)
else:
import smtplib
import sys
zero_wait = 0
if total > 0:
zero_wait = allhist.get(0, 0) * 100. / total
subject = "Wait: %i/%.2f%% (%s)" % (total, zero_wait, options.name)
server = options.smtp or 'localhost'
sender = options.sender or 'cltbld@build.mozilla.com'
headers = []
headers.append("Subject: %s" % subject)
headers.append("From: %s" % sender)
headers.append("To: %s" % (", ".join(options.addresses)))
message = "\n".join(headers) + "\n" + "\n".join(text)
try:
smtp = smtplib.SMTP(server)
smtp.sendmail(sender, options.addresses, message)
except SMTPException:
print "Error: unable to send email"
sys.exit(1)