Bug 458093 - Update Talos to send graph server new test information

p=anodelman, r=bhearsum


git-svn-id: svn://10.0.0.236/trunk@256264 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
anodelman%mozilla.com 2009-02-20 16:16:23 +00:00
parent ae932d41e6
commit 3d84a1abd5
7 changed files with 260 additions and 51 deletions

View File

@ -25,7 +25,7 @@ defaultTitle = "qm-pxp01"
help_message = '''
This is the buildbot performance runner's YAML configurator.bean
USAGE: python PerfConfigurator.py --title title --executablePath path --configFilePath cpath --buildid id --branch branch --testDate date --resultsServer server --resultsLink link --activeTests testlist
USAGE: python PerfConfigurator.py --title title --executablePath path --configFilePath cpath --buildid id --branch branch --testDate date --resultsServer server --resultsLink link --activeTests testlist --oldresultsServer oldserver --oldresultsLink oldlink --branchName branchFullName --fast
example testlist: tp:tsspider:tdhtml:twinopen
'''
@ -36,6 +36,7 @@ class PerfConfigurator:
outputName = ""
title = ""
branch = ""
branchName = ""
buildid = ""
currentDate = ""
verbose = False
@ -43,8 +44,11 @@ class PerfConfigurator:
useId = False
resultsServer = ''
resultsLink = ''
oldresultsServer = ''
oldresultsLink = ''
activeTests = ''
noChrome = False
fast = False
def _dumpConfiguration(self):
"""dump class configuration for convenient pickup or perusal"""
@ -54,11 +58,14 @@ class PerfConfigurator:
print " - configPath = " + self.configPath
print " - outputName = " + self.outputName
print " - branch = " + self.branch
print " - branchName = " + self.branchName
print " - buildid = " + self.buildid
print " - currentDate = " + self.currentDate
print " - testDate = " + self.testDate
print " - resultsServer = " + self.resultsServer
print " - resultsLink = " + self.resultsLink
print " - oldresultsServer = " + self.oldresultsServer
print " - oldresultsLink = " + self.oldresultsLink
print " - activeTests = " + self.activeTests
def _getCurrentDateString(self):
@ -120,6 +127,21 @@ class PerfConfigurator:
elif self.useId:
newline += '\n'
newline += 'testdate: "%s"\n' % self._getTimeFromBuildId()
if self.oldresultsServer:
newline += '\n'
newline += 'old_results_server: %s\n' % self.oldresultsServer
if self.oldresultsLink:
newline += '\n'
newline += 'old_results_link: %s\n' % self.oldresultsLink
if self.branchName:
newline += '\n'
newline += 'branch_name: %s\n' % self.branchName
if self.noChrome:
newline += '\n'
newline += "test_name_extension: _nochrome\n"
if self.fast:
newline += '\n'
newline += "test_name_estension: _fast\n"
if 'buildid:' in line:
newline = 'buildid: ' + buildidString
if 'testbranch' in line:
@ -162,6 +184,8 @@ class PerfConfigurator:
self.title = kwargs['title']
if 'branch' in kwargs:
self.branch = kwargs['branch']
if 'branchName' in kwargs:
self.branchName = kwargs['branchName']
if 'executablePath' in kwargs:
self.exePath = kwargs['executablePath']
if 'configFilePath' in kwargs:
@ -178,10 +202,16 @@ class PerfConfigurator:
self.resultsServer = kwargs['resultsServer']
if 'resultsLink' in kwargs:
self.resultsLink = kwargs['resultsLink']
if 'oldresultsServer' in kwargs:
self.oldresultsServer = kwargs['oldresultsServer']
if 'oldresultsLink' in kwargs:
self.oldresultsLink = kwargs['oldresultsLink']
if 'activeTests' in kwargs:
self.activeTests = kwargs['activeTests']
if 'noChrome' in kwargs:
self.noChrome = kwargs['noChrome']
if 'fast' in kwargs:
self.fast = kwargs['fast']
self.currentDate = self._getCurrentDateString()
if not self.buildid:
self.buildid = self._getCurrentBuildId()
@ -203,14 +233,18 @@ def main(argv=None):
output = ""
title = defaultTitle
branch = ""
branchName = ""
testDate = ""
verbose = False
buildid = ""
useId = False
resultsServer = ''
resultsLink = ''
oldresultsServer = ''
oldresultsLink = ''
activeTests = ''
noChrome = False
fast = False
if argv is None:
argv = sys.argv
@ -218,7 +252,7 @@ def main(argv=None):
try:
opts, args = getopt.getopt(argv[1:], "hvue:c:t:b:o:i:d:s:l:a:n",
["help", "verbose", "useId", "executablePath=", "configFilePath=", "title=",
"branch=", "output=", "id=", "testDate=", "resultsServer=", "resultsLink=", "activeTests=", "noChrome"])
"branch=", "output=", "id=", "testDate=", "resultsServer=", "resultsLink=", "activeTests=", "noChrome", "oldresultsServer=", "oldresultsLink=", "branchName=", "fast"])
except getopt.error, msg:
raise Usage(msg)
@ -236,6 +270,8 @@ def main(argv=None):
title = value
if option in ("-b", "--branch"):
branch = value
if option in ("--branchName"):
branchName = value
if option in ("-o", "--output"):
output = value
if option in ("-i", "--id"):
@ -248,10 +284,16 @@ def main(argv=None):
resultsServer = value
if option in ("-l", "--resultsLink"):
resultsLink = value
if option in ("--oldresultsServer"):
oldresultsServer = value
if option in ("--oldresultsLink"):
oldresultsLink = value
if option in ("-a", "--activeTests"):
activeTests = value
if option in ("-n", "--noChrome"):
noChrome = True
if option in ("--fast"):
fast = True
except Usage, err:
print >> sys.stderr, sys.argv[0].split("/")[-1] + ": " + str(err.msg)
@ -263,14 +305,18 @@ def main(argv=None):
configFilePath=configPath,
buildid=buildid,
branch=branch,
branchName=branchName,
verbose=verbose,
testDate=testDate,
outputName=output,
useId=useId,
resultsServer=resultsServer,
resultsLink=resultsLink,
oldresultsServer=oldresultsServer,
oldresultsLink=oldresultsLink,
activeTests=activeTests,
noChrome=noChrome)
noChrome=noChrome,
fast=fast)
try:
configurator.writeConfigFile()
except Configuration, err:

View File

@ -219,6 +219,7 @@ class CounterManager(threading.Thread):
self.registeredCounters[counter][0](self.pid))
except:
# if a counter throws an exception, remove it
self.unregisterCounters([counter])
#self.unregisterCounters([counter])
print "Error in collecting counter: " + counter
time.sleep(self.pollInterval)

View File

@ -197,6 +197,7 @@ class CounterManager(threading.Thread):
self.registeredCounters[counter][0](self.pid))
except:
# if a counter throws an exception, remove it
self.unregisterCounters([counter])
#self.unregisterCounters([counter]) #don't remove, let it try and resolve on next cycle
print "Error in collecting counter: " + counter
time.sleep(self.pollInterval)

View File

@ -39,6 +39,7 @@ def post_multipart(host, selector, fields, files):
h.putrequest('POST', selector)
h.putheader('content-type', content_type)
h.putheader('content-length', str(len(body)))
h.putheader('Host', host)
h.endheaders()
h.send(body)
errcode, errmsg, headers = h.getreply()

View File

@ -55,7 +55,35 @@ from utils import talosError
import post_file
import ttest
def shortNames(name):
def shortName(name):
if name == "Working Set":
return "memset"
elif name == "% Processor Time":
return "%cpu"
elif name == "Private Bytes":
return "pbytes"
elif name == "RSS":
return "rss"
def process_tpformat(line):
# each line of the string is of the format i;page_name;median;mean;min;max;time vals\n
r = line.split(';')
#skip this line if it isn't the correct format
if len(r) == 1:
return -1, ''
r[1] = r[1].rstrip('/')
if r[1].find('/') > -1 :
page = r[1].split('/')[0]
else:
page = r[1]
try:
val = float(r[2])
except ValueError:
print 'WARNING: value error for median in tp'
val = 0
return val, page
def old_shortName(name):
if name == "tp_loadtime":
return "tp"
elif name == "tp_js_loadtime":
@ -69,15 +97,24 @@ def shortNames(name):
else:
return name
def process_Request(post):
def old_process_Request(post):
str = ""
lines = post.split('\n')
for line in lines:
if line.find("RETURN:") > -1:
str += line.split(":")[3] + ":" + shortNames(line.split(":")[1]) + ":" + line.split(":")[2] + '\n'
str += line.split(":")[3] + ":" + old_shortName(line.split(":")[1]) + ":" + line.split(":")[2] + '\n'
utils.debug("process_Request line: " + line.replace("RETURN", ""))
return str
def process_Request(post):
links = ""
lines = post.split('\n')
for line in lines:
if line.find("RETURN\t") > -1:
links += line.replace("RETURN\t", "") + '\n'
utils.debug("process_Request line: " + line.replace("RETURN\t", ""))
return links
def send_to_csv(csv_dir, results):
import csv
for res in results:
@ -118,7 +155,7 @@ def send_to_csv(csv_dir, results):
writer.writerow([i, val])
i += 1
def post_chunk(results_server, results_link, id, filename):
def post_test_result(results_server, results_link, filename):
tmpf = open(filename, "r")
file_data = tmpf.read()
try:
@ -126,22 +163,7 @@ def post_chunk(results_server, results_link, id, filename):
except:
print "FAIL: error in post data"
sys.exit(0)
links = process_Request(ret)
utils.debug(id + ": sent results")
return links
def chunk_list(val_list):
"""
divide up a list into manageable chunks
currently set at length 500
this is for a failure on mac os x with python 2.4.4
"""
chunks = []
end = 500
while (val_list != []):
chunks.append(val_list[0:end])
val_list = val_list[end:len(val_list)]
return chunks
return ret
def filesizeformat(bytes):
"""
@ -157,7 +179,73 @@ def filesizeformat(bytes):
return "%.1fMB" % (bytes / (1024 * 1024))
return "%.1fGB" % (bytes / (1024 * 1024 * 1024))
def send_to_graph(results_server, results_link, title, date, browser_config, results):
def construct_file (machine, testname, branch, sourcestamp, buildid, date, vals):
"""
Creates file formated for the collector script of the graph server
Returns the filename
"""
#machine_name,test_name,branch_name,sourcestamp,buildid,date_run
info_format = "%s,%s,%s,%s,%s,%s\n"
filename = tempfile.mktemp()
tmpf = open(filename, "w")
tmpf.write("START\n")
tmpf.write("VALUES\n")
tmpf.write(info_format % (machine, testname, branch, sourcestamp, buildid, date))
i = 0
for val, page in vals:
tmpf.write("%d,%.2f,%s\n" % (i,float(val), page))
i += 1
tmpf.write("END")
tmpf.flush()
tmpf.close()
return filename
def send_to_graph(results_server, results_link, machine, date, browser_config, results):
links = ''
files = []
#construct all the files of data, one file per test and one file per counter
for testname in results:
vals = []
fullname = testname
browser_dump, counter_dump = results[testname]
utils.debug("Working with test: " + testname)
utils.debug("Sending results: " + " ".join(browser_dump))
utils.stamped_msg("Generating results file: " + testname, "Started")
if testname in ('ts', 'twinopen'):
#non-tpformat results
for bd in browser_dump:
vals.extend([[x, 'NULL'] for x in bd.split('|')])
else:
#tpformat results
fullname += browser_config['test_name_extension']
for bd in browser_dump:
bd.rstrip('\n')
page_results = bd.splitlines()
for line in page_results:
val, page = process_tpformat(line)
if val > -1 :
vals.append([val, page])
files.append(construct_file(machine, fullname, browser_config['branch_name'], browser_config['sourcestamp'], browser_config['buildid'], date, vals))
utils.stamped_msg("Generating results file: " + testname, "Stopped")
for cd in counter_dump:
for count_type in cd:
vals = [[x, 'NULL'] for x in cd[count_type]]
counterName = testname + '_' + shortName(count_type) + browser_config['test_name_extension']
utils.stamped_msg("Generating results file: " + counterName, "Started")
files.append(construct_file(machine, counterName, browser_config['branch_name'], browser_config['sourcestamp'], browser_config['buildid'], date, vals))
utils.stamped_msg("Generating results file: " + counterName, "Stopped")
#send all the files along to the graph server
for filename in files:
links += process_Request(post_test_result(results_server, results_link, filename))
os.remove(filename)
utils.stamped_msg("Transmitting test: " + testname, "Stopped")
return links
#To be removed when we stop sending data to the old graph server
def old_send_to_graph(results_server, results_link, title, date, browser_config, results):
tbox = title
url_format = "http://%s/%s"
link_format= "<a href=\"%s\">%s</a>"
@ -174,8 +262,8 @@ def send_to_graph(results_server, results_link, title, date, browser_config, res
filename = tempfile.mktemp()
tmpf = open(filename, "w")
if res in ('ts', 'twinopen'):
i = 0
for val in browser_dump:
i = 0
for val in browser_dump:
val_list = val.split('|')
for v in val_list:
tmpf.write(result_format % (float(v), res, tbox, i, date, browser_config['branch'], browser_config['buildid'], "discrete", "ms"))
@ -208,30 +296,25 @@ def send_to_graph(results_server, results_link, title, date, browser_config, res
i += 1
tmpf.flush()
tmpf.close()
links += post_chunk(results_server, results_link, res, filename)
links += old_process_Request(post_test_result(results_server, results_link, filename))
os.remove(filename)
for cd in counter_dump:
for count_type in cd:
val_list = cd[count_type]
chunks = chunk_list(val_list)
chunk_link = ''
i = 0
for chunk in chunks:
filename = tempfile.mktemp()
tmpf = open(filename, "w")
for val in chunk:
tmpf.write(result_format2 % (float(val), res + "_" + count_type.replace("%", "Percent"), tbox, i, date, browser_config['branch'], browser_config['buildid'], "discrete"))
i += 1
tmpf.flush()
tmpf.close()
chunk_link = post_chunk(results_server, results_link, '%s_%s (%d values)' % (res, count_type, len(chunk)), filename)
os.remove(filename)
links += chunk_link
filename = tempfile.mktemp()
tmpf = open(filename, "w")
for val in cd[count_type]:
tmpf.write(result_format2 % (float(val), res + "_" + count_type.replace("%", "Percent"), tbox, i, date, browser_config['branch'], browser_config['buildid'], "discrete"))
i += 1
tmpf.flush()
tmpf.close()
links += old_process_Request(post_test_result(results_server, results_link, filename))
os.remove(filename)
utils.stamped_msg("Transmitting test: " + res, "Stopped")
first_results = 'RETURN:<br>'
last_results = ''
full_results = '\nRETURN:<p style="font-size:smaller;">Details:<br>'
last_results = ''
full_results = '\nRETURN:<p style="font-size:smaller;">Details:<br>'
lines = links.split('\n')
for line in lines:
if line == "":
@ -253,10 +336,50 @@ def send_to_graph(results_server, results_link, title, date, browser_config, res
link = link_format % (url, linkName)
last_results = last_results + '| ' + link + ' '
full_results = first_results + full_results + last_results + '|</p>'
print 'RETURN: graph links'
print full_results
def results_from_graph(links, results_server):
#take the results from the graph server collection script and put it into a pretty format for the waterfall
url_format = "http://%s/%s"
link_format= "<a href=\'%s\'>%s</a>"
first_results = 'RETURN:<br>'
last_results = ''
full_results = '\nRETURN:<p style="font-size:smaller;">Details:<br>'
lines = links.split('\n')
for line in lines:
if line == "":
continue
linkvalue = -1
linkdetail = ""
values = line.split("\t")
linkName = values[0]
if len(values) == 2:
linkdetail = values[1]
else:
linkvalue = float(values[1])
linkdetail = values[2]
if linkName in ('tp_pbytes', 'tp_%cpu', 'tp_pbytes_nochrome', 'tp_%cpu_nochrome'):
continue
if linkvalue > -1:
if linkName in ('tp_memset', 'tp_rss', 'tp_memset_nochrome', 'tp_rss_nochrome'): #measured in bytes
linkName += ": " + filesizeformat(linkvalue)
else:
linkName += ": " + str(linkvalue)
url = url_format % (results_server, linkdetail)
link = link_format % (url, linkName)
first_results = first_results + "\nRETURN:" + link + "<br>"
else:
url = url_format % (results_server, linkdetail)
link = link_format % (url, linkName)
last_results = last_results + '| ' + link + ' '
full_results = first_results + full_results + last_results + '|</p>'
print 'RETURN: new graph links'
print full_results
def browserInfo(browser_config):
"""Get the buildid and changeset from the application.ini (if it exists)
"""Get the buildid and sourcestamp from the application.ini (if it exists)
"""
appIniFileName = "application.ini"
appIniPath = os.path.join(os.path.dirname(browser_config['browser_path']), appIniFileName)
@ -280,10 +403,13 @@ def browserInfo(browser_config):
browser_config['sourcestamp'] = match.group(1)
if ('repository' in browser_config) and ('sourcestamp' in browser_config):
print 'RETURN:<a href = "' + browser_config['repository'] + '/rev/' + browser_config['sourcestamp'] + '">rev:' + browser_config['sourcestamp'] + '</a>'
else:
browser_config['repository'] = 'NULL'
browser_config['sourcestamp'] = 'NULL'
return browser_config
def test_file(filename):
"""Runs the Ts and Tp tests on the given config file and generates a report.
"""Runs the talos tests on the given config file and generates a report.
Args:
filename: the name of the file to run the tests on
@ -296,6 +422,8 @@ def test_file(filename):
csv_dir = ''
results_server = ''
results_link = ''
old_results_server = ''
old_results_link = ''
results = {}
# Read in the profile info from the YAML config file
@ -316,9 +444,16 @@ def test_file(filename):
results_server = yaml_config[item]
elif item == 'results_link' :
results_link = yaml_config[item]
elif item == 'old_results_server':
old_results_server = yaml_config[item]
elif item == 'old_results_link' :
old_results_link = yaml_config[item]
if (results_link != results_server != ''):
if not post_file.link_exists(results_server, results_link):
sys.exit(0)
if (old_results_link != old_results_server != ''):
if not post_file.link_exists(old_results_server, old_results_link):
sys.exit(0)
browser_config = {'preferences' : yaml_config['preferences'],
'extensions' : yaml_config['extensions'],
'browser_path' : yaml_config['browser_path'],
@ -331,6 +466,12 @@ def test_file(filename):
'env' : yaml_config['env'],
'dirs' : yaml_config['dirs'],
'init_url' : yaml_config['init_url']}
if 'branch_name' in yaml_config:
browser_config['branch_name'] = yaml_config['branch_name']
if 'test_name_extension' in yaml_config:
browser_config['test_name_extension'] = yaml_config['test_name_extension']
else:
browser_config['test_name_extension'] = ''
#normalize paths to work accross platforms
browser_config['browser_path'] = os.path.normpath(browser_config['browser_path'])
if browser_config['profile_path'] != {}:
@ -348,6 +489,7 @@ def test_file(filename):
#pull buildid & sourcestamp from browser
browser_config = browserInfo(browser_config)
utils.startTimer()
utils.stamped_msg(title, "Started")
for test in tests:
testname = test['name']
@ -365,13 +507,22 @@ def test_file(filename):
if csv_dir != '':
send_to_csv(csv_dir, {testname : results[testname]})
utils.stamped_msg("Completed test " + testname, "Stopped")
elapsed = utils.stopTimer()
print "RETURN: cycle time: " + elapsed + "<br>"
utils.stamped_msg(title, "Stopped")
#process the results
if (results_server != '') and (results_link != ''):
#send results to the graph server
utils.stamped_msg("Sending results", "Started")
send_to_graph(results_server, results_link, title, date, browser_config, results)
links = send_to_graph(results_server, results_link, title, date, browser_config, results)
results_from_graph(links, results_server)
utils.stamped_msg("Completed sending results", "Stopped")
#process the results, yet again
if (old_results_server != '') and (old_results_link != ''):
#send results to the old graph server
utils.stamped_msg("Sending results", "Started")
old_send_to_graph(old_results_server, old_results_link, title, date, browser_config, results)
utils.stamped_msg("Completed sending results", "Stopped")
if __name__=='__main__':

View File

@ -7,8 +7,8 @@ title: firefox_testing
#uncomment to turn on dump to csv option
#csv_dir: 'output'
#comment out next two lines to disable send to graph server
results_server: 'url.of.graphserver'
results_link: '/bulk.cgi'
#results_server: 'url.of.graphserver'
#results_link: '/bulk.cgi'
# browser info
process : firefox

View File

@ -40,8 +40,17 @@ import os
import time
DEBUG = 0
NOISY = 0
START_TIME = 0
saved_environment = {}
def startTimer():
global START_TIME
START_TIME = time.time()
def stopTimer():
stop_time = time.time()
return time.strftime("%H:%M:%S", time.gmtime(stop_time-START_TIME))
def setdebug(val):
global DEBUG
DEBUG = val