diff options
author | pfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-11 17:37:38 +0000 |
---|---|---|
committer | pfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-11 17:37:38 +0000 |
commit | 8485bb64fa8ba1f314c8955ad3821f8431c6fbcb (patch) | |
tree | 01da7709a3fae93e549445dea138ebdd22385d5c /tools | |
parent | dc6623e242ee481766daa29c64c82fda4e0cf52a (diff) | |
download | chromium_src-8485bb64fa8ba1f314c8955ad3821f8431c6fbcb.zip chromium_src-8485bb64fa8ba1f314c8955ad3821f8431c6fbcb.tar.gz chromium_src-8485bb64fa8ba1f314c8955ad3821f8431c6fbcb.tar.bz2 |
DOM Perf: Python script for dromaeo benchmark automation.
Origianl review: http://codereview.chromium.org/503028
TBR=vitalyr
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@35910 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools')
-rw-r--r-- | tools/dromaeo_benchmark_runner/dromaeo_benchmark_runner.py | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/tools/dromaeo_benchmark_runner/dromaeo_benchmark_runner.py b/tools/dromaeo_benchmark_runner/dromaeo_benchmark_runner.py new file mode 100644 index 0000000..97c410c --- /dev/null +++ b/tools/dromaeo_benchmark_runner/dromaeo_benchmark_runner.py @@ -0,0 +1,263 @@ +#!/usr/bin/env python +# +# Copyright 2009 Google Inc. All Rights Reserved. + +"""Dromaeo benchmark automation script. + +Script runs dromaeo tests in browsers specified by --browser switch and saves +results to a spreadsheet on docs.google.com. + +Prerequisites: +1. Install Google Data APIs Python Client Library from + http://code.google.com/p/gdata-python-client. +2. Checkout Dromaeo benchmark from + http://src.chromium.org/svn/trunk/src/chrome/test/data/dromaeo and provide + local path to it in --dromaeo_home switch. +3. Create a spreadsheet at http://docs.google.com and specify it's name in + --spreadsheet switch + +Benchmark results are presented in the following format: +browser | date time +test 1 name|m11|...|m1n|test 1 average mean| |e11|...|e1n|test 1 average error +test 2 name|m21|...|m2n|test 2 average mean| |e21|...|e2n|test 2 average error +... + +Here mij is mean run/s in individual dromaeo test i during benchmark run j, +eij is error in individual dromaeo test i during benchmark run j. + +Example usage: +dromaeo_benchmark_runner.py -b "E:\chromium\src\chrome\Release\chrome.exe" + -b "C:\Program Files (x86)\Safari\safari.exe" + -b "C:\Program Files (x86)\Opera 10.50 pre-alpha\opera.exe" -n 1 + -d "E:\chromium\src\chrome\test\data\dromaeo" -f dom -e example@gmail.com + +""" + +import getpass +import json +import os +import re +import subprocess +import time +import urlparse +from optparse import OptionParser +from BaseHTTPServer import HTTPServer +import SimpleHTTPServer +import gdata.spreadsheet.service + +max_spreadsheet_columns = 20 +test_props = ['mean', 'error'] + +def ParseArguments(): + parser = OptionParser() + parser.add_option("-b", "--browser", + action="append", dest="browsers", + help="list of browsers to test") + parser.add_option("-n", "--run_count", dest="run_count", type="int", + default=5, help="number of runs") + parser.add_option("-d", "--dromaeo_home", dest="dromaeo_home", + help="directory with your dromaeo files") + parser.add_option("-p", "--port", dest="port", type="int", + default=8080, help="http server port") + parser.add_option("-f", "--filter", dest="filter", + default="dom", help="dromaeo suite filter") + parser.add_option("-e", "--email", dest="email", + help="your google docs account") + parser.add_option("-s", "--spreadsheet", dest="spreadsheet_title", + default="dromaeo", + help="your google docs spreadsheet name") + + options = parser.parse_args()[0] + + if not options.dromaeo_home: + raise Exception('please specify dromaeo_home') + + return options + + +def KillProcessByName(process_name): + process = subprocess.Popen('wmic process get processid, executablepath', + stdout=subprocess.PIPE) + stdout = str(process.communicate()[0]) + match = re.search(re.escape(process_name) + '\s+(\d+)', stdout) + if match: + pid = match.group(1) + subprocess.call('taskkill /pid %s' % pid) + + +class SpreadsheetWriter(object): + "Utility class for storing benchmarking results in Google spreadsheets." + + def __init__(self, email, spreadsheet_title): + '''Login to google docs and search for spreadsheet''' + + self.token_file = os.path.expanduser("~/.dromaeo_bot_auth_token") + self.gd_client = gdata.spreadsheet.service.SpreadsheetsService() + + authenticated = False + if os.path.exists(self.token_file): + token = '' + try: + file = open(self.token_file, 'r') + token = file.read() + file.close() + self.gd_client.SetClientLoginToken(token) + self.gd_client.GetSpreadsheetsFeed() + authenticated = True + except (IOError, gdata.service.RequestError): + pass + if not authenticated: + self.gd_client.email = email + self.gd_client.password = getpass.getpass('Password for %s: ' % email) + self.gd_client.source = 'python robot for dromaeo' + self.gd_client.ProgrammaticLogin() + token = self.gd_client.GetClientLoginToken() + try: + file = open(self.token_file, 'w') + file.write(token) + file.close() + except (IOError): + pass + os.chmod(self.token_file, 0600) + + # Search for the spreadsheet with title = spreadsheet_title. + spreadsheet_feed = self.gd_client.GetSpreadsheetsFeed() + for spreadsheet in spreadsheet_feed.entry: + if spreadsheet.title.text == spreadsheet_title: + self.spreadsheet_key = spreadsheet.id.text.rsplit('/', 1)[1] + if not self.spreadsheet_key: + raise Exception('Spreadsheet %s not found' % spreadsheet_title) + + # Get the key of the first worksheet in spreadsheet. + worksheet_feed = self.gd_client.GetWorksheetsFeed(self.spreadsheet_key) + self.worksheet_key = worksheet_feed.entry[0].id.text.rsplit('/', 1)[1] + + def _InsertRow(self, row): + row = dict([('c' + str(i), row[i]) for i in xrange(len(row))]) + self.gd_client.InsertRow(row, self.spreadsheet_key, self.worksheet_key) + + def _InsertBlankRow(self): + self._InsertRow('-' * self.columns_count) + + def PrepareSpreadsheet(self, run_count): + """Update cells in worksheet topmost row with service information. + + Calculate column count corresponding to run_count and create worksheet + column titles [c0, c1, ...] in the topmost row to speed up spreadsheet + updates (it allows to insert a whole row with a single request) + """ + + # Calculate the number of columns we need to present all test results. + self.columns_count = (run_count + 2) * len(test_props) + if self.columns_count > max_spreadsheet_columns: + # Google spreadsheet has just max_spreadsheet_columns columns. + max_run_count = max_spreadsheet_columns / len(test_props) - 2 + raise Exception('maximum run count is %i' % max_run_count) + # Create worksheet column titles [c0, c1, ..., cn]. + for i in xrange(self.columns_count): + self.gd_client.UpdateCell(1, i + 1, 'c' + str(i), self.spreadsheet_key, + self.worksheet_key) + + def WriteColumnTitles(self, run_count): + "Create titles for test results (mean 1, mean 2, ..., average mean, ...)" + row = [] + for prop in test_props: + row.append('') + for i in xrange(run_count): + row.append('%s %i' % (prop, i + 1)) + row.append('average ' + prop) + self._InsertRow(row) + + def WriteBrowserBenchmarkTitle(self, browser_name): + "Create browser benchmark title (browser name, date time)" + self._InsertBlankRow() + self._InsertRow([browser_name, time.strftime('%d.%m.%Y %H:%M:%S')]) + + def WriteBrowserBenchmarkResults(self, test_name, test_data): + "Insert a row with single test results" + row = [] + for prop in test_props: + if not row: + row.append(test_name) + else: + row.append('') + row.extend([str(x) for x in test_data[prop]]) + row.append(str(sum(test_data[prop]) / len(test_data[prop]))) + self._InsertRow(row) + + +class DromaeoHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): + + def do_POST(self): + self.send_response(200) + self.end_headers() + self.wfile.write("<HTML>POST OK.<BR><BR>"); + length = int(self.headers.getheader('content-length')) + parameters = urlparse.parse_qs(self.rfile.read(length)) + self.server.got_post = True + self.server.post_data = parameters['data'] + + +class BenchmarkResults(object): + "Storage class for dromaeo benchmark results" + + def __init__(self): + self.data = {} + + def ProcessBrowserPostData(self, data): + "Convert dromaeo test results in internal format" + tests = json.loads(data[0]) + for test in tests: + test_name = test['name'] + if test_name not in self.data: + # Test is encountered for the first time. + self.data[test_name] = dict([(prop, []) for prop in test_props]) + # Append current run results. + for prop in test_props: + value = -1 + if prop in test: value = test[prop] # workaround for Opera 10.5 + self.data[test_name][prop].append(value) + + +def main(): + options = ParseArguments() + + # Start sever with dromaeo. + os.chdir(options.dromaeo_home) + server = HTTPServer(('', options.port), DromaeoHandler) + + # Open and prepare spreadsheet on google docs. + spreadsheet_writer = SpreadsheetWriter(options.email, + options.spreadsheet_title) + spreadsheet_writer.PrepareSpreadsheet(options.run_count) + spreadsheet_writer.WriteColumnTitles(options.run_count) + + for browser in options.browsers: + browser_name = os.path.splitext(os.path.basename(browser))[0] + spreadsheet_writer.WriteBrowserBenchmarkTitle(browser_name) + benchmark_results = BenchmarkResults() + for run_number in xrange(options.run_count): + print '%s run %i' % (browser_name, run_number + 1) + # Run browser. + test_page = 'http://localhost:%i/index.html?%s&automated&post_json' % ( + options.port, options.filter) + browser_process = subprocess.Popen('%s "%s"' % (browser, test_page)) + server.got_post = False + server.post_data = None + # Wait until POST request from browser. + while not server.got_post: + server.handle_request() + benchmark_results.ProcessBrowserPostData(server.post_data) + # Kill browser. + KillProcessByName(browser) + browser_process.wait() + + # Insert test results into spreadsheet. + for (test_name, test_data) in benchmark_results.data.iteritems(): + spreadsheet_writer.WriteBrowserBenchmarkResults(test_name, test_data) + + server.socket.close() + +if __name__ == '__main__': + main() + |