https://bugs.webkit.org/show_bug.cgi?id=144038
[WebKit-https.git] / Tools / Scripts / webkitpy / benchmark_runner / benchmark_runner.py
1 #!/usr/bin/env python
2
3 import json
4 import logging
5 import shutil
6 import signal
7 import subprocess
8 import tempfile
9 import time
10 import types
11 import os
12 import urlparse
13
14 from benchmark_builder.benchmark_builder_factory import BenchmarkBuilderFactory
15 from browser_driver.browser_driver_factory import BrowserDriverFactory
16 from http_server_driver.http_server_driver_factory import HTTPServerDriverFactory
17 from utils import loadModule, getPathFromProjectRoot
18 from utils import timeout
19
20
21 _log = logging.getLogger(__name__)
22
23
24 class BenchmarkRunner(object):
25
26     def __init__(self, planFile, buildDir, outputFile, platform, browser):
27         _log.info('Initializing benchmark running')
28         try:
29             with open(planFile, 'r') as fp:
30                 self.plan = json.load(fp)
31                 self.browserDriver = BrowserDriverFactory.create([platform, browser])
32                 self.httpServerDriver = HTTPServerDriverFactory.create([self.plan['http_server_driver']])
33                 self.benchmarks = self.plan['benchmarks']
34                 self.buildDir = os.path.abspath(buildDir)
35                 self.outputFile = outputFile if outputFile else 'benchmark.result'
36         except IOError:
37             _log.error('Can not open plan file: %s' % planFile)
38         except ValueError:
39             _log.error('Plan file:%s may not follow json format' % planFile)
40         except:
41             raise
42
43     def execute(self):
44         _log.info('Start to execute the plan')
45         for benchmark in self.benchmarks:
46             _log.info('Start a new benchmark')
47             results = []
48             benchmarkBuilder = BenchmarkBuilderFactory.create([benchmark['benchmark_builder']])
49             webRoot = benchmarkBuilder.prepare(benchmark['original_benchmark'], benchmark['benchmark_patch'] if 'benchmark_patch' in benchmark else None)
50             for x in xrange(int(benchmark['count'])):
51                 _log.info('Start the iteration %d of current benchmark' % (x + 1))
52                 self.httpServerDriver.serve(webRoot)
53                 self.browserDriver.prepareEnv()
54                 self.browserDriver.launchUrl(urlparse.urljoin(self.httpServerDriver.baseUrl(), benchmark['entry_point']), self.buildDir)
55                 try:
56                     with timeout(benchmark['timeout']):
57                         result = json.loads(self.httpServerDriver.fetchResult())
58                         assert(result)
59                 except:
60                     _log.error('No result. Something went wrong. Will skip current benchmark.')
61                     self.browserDriver.closeBrowsers()
62                     break
63                 finally:
64                     self.browserDriver.closeBrowsers()
65                     _log.info('End of %d iteration of current benchmark' % (x + 1))
66             results = self.wrap(results)
67             self.dump(results, benchmark['output_file'] if benchmark['output_file'] else self.outputFile)
68             benchmarkBuilder.clean()
69
70     @classmethod
71     def dump(cls, results, outputFile):
72         _log.info('Dumpping the results to file')
73         try:
74             with open(outputFile, 'w') as fp:
75                 json.dump(results, fp)
76         except IOError:
77             _log.error('Cannot open output file: %s' % outputFile)
78             _log.error('Results are:\n %s', json.dumps(results))
79
80     @classmethod
81     def wrap(cls, dicts):
82         if not dicts:
83             return None
84         ret = {}
85         for dic in dicts:
86             ret = cls.merge(ret, dic)
87         return ret
88
89     @classmethod
90     def merge(cls, a, b):
91         assert(isinstance(a, type(b)))
92         argType = type(a)
93         # special handle for list type, and should be handle before equal check
94         if argType == types.ListType:
95             return a + b
96         if a == b:
97             return a
98         if argType == types.DictType:
99             result = {}
100             for key, value in a.items():
101                 if key in b:
102                     result[key] = cls.merge(value, b[key])
103                 else:
104                     result[key] = value
105             for key, value in b.items():
106                 if key not in result:
107                     result[key] = value
108             return result
109         # for other types
110         return a + b