haikuwebkit/PerformanceTests/LaunchTime/thirdparty/__init__.py

144 lines
5.8 KiB
Python
Raw Permalink Normal View History

Add benchmark for WebKit process launch times https://bugs.webkit.org/show_bug.cgi?id=186414 Patch by Ben Richards <benton_richards@apple.com> on 2018-07-19 Reviewed by Ryosuke Niwa. Added two benchmarks, one for measuring browser new tab launch time and one for browser startup time. * LaunchTime/.gitignore: Added. * LaunchTime/feedback_client.html: Added. Displays benchmark progress in browser * LaunchTime/feedback_server.py: Added. (FeedbackServer): Sends data to feedback_client via websocket (FeedbackServer.__init__): (FeedbackServer._create_app): (FeedbackServer._start_server): (FeedbackServer._send_all_messages): (FeedbackServer.start): (FeedbackServer.stop): (FeedbackServer.send_message): Send a message to the feedback_client (FeedbackServer.wait_until_client_has_loaded): Wait until the feedback_client has opened a websocket connection to the feedback_server (FeedbackServer.MainHandler): Handler factory to create handler that serves feedback_client.html (FeedbackServer.MainHandler.Handler): (FeedbackServer.MainHandler.Handler.get): (FeedbackServer.WSHandler): Handler factory to create handler that sends data to feedback client (FeedbackServer.WSHandler.Handler): (FeedbackServer.WSHandler.Handler.open): On websocket connection opened (FeedbackServer.WSHandler.Handler.on_close): On websocket connection closed * LaunchTime/launch_time.py: Added. (DefaultLaunchTimeHandler): Abstract HTTP request handler for launch time benchmarks (DefaultLaunchTimeHandler.get_test_page): Default test page to be overridden by benchmarks (DefaultLaunchTimeHandler.get_blank_page): (DefaultLaunchTimeHandler.on_receive_stop_time): (DefaultLaunchTimeHandler.do_HEAD): (DefaultLaunchTimeHandler.do_GET): (DefaultLaunchTimeHandler.do_POST): (DefaultLaunchTimeHandler.log_message): Suppresses HTTP logs from SimpleHTTPRequestHandler (LaunchTimeBenchmark): Abstract class which launch time benchmarks inherit from and override methods desired to customize (LaunchTimeBenchmark.__init__): (LaunchTimeBenchmark._parse_browser_bundle_path): Parser for bundle path option (LaunchTimeBenchmark._parse_args): (LaunchTimeBenchmark._run_server): Target function for main server thread (LaunchTimeBenchmark._setup_servers): (LaunchTimeBenchmark._clean_up): (LaunchTimeBenchmark._exit_due_to_exception): (LaunchTimeBenchmark._geometric_mean): (LaunchTimeBenchmark._standard_deviation): (LaunchTimeBenchmark._compute_results): Returns mean and std dev of list of results and pretty prints if should_print=True is specified (LaunchTimeBenchmark._wait_times): Mimic numpy.linspace (LaunchTimeBenchmark.open_tab): Open a browser tab with the html given by self.response_handler.get_test_page (LaunchTimeBenchmark.launch_browser): Open a broser to either the feedback client (if option is set) or a blank page (LaunchTimeBenchmark.quit_browser): (LaunchTimeBenchmark.quit_browser.quit_app): (LaunchTimeBenchmark.quit_browser.is_app_closed): (LaunchTimeBenchmark.close_tab): (LaunchTimeBenchmark.wait): (LaunchTimeBenchmark.log): Print to console and send to feedback client if --feedback-in-browser flag is used (LaunchTimeBenchmark.log_verbose): Only logs if --verbose flag is used (LaunchTimeBenchmark.run): (LaunchTimeBenchmark.group_init): Initialization done before each round of iterations (LaunchTimeBenchmark.run_iteration): (LaunchTimeBenchmark.initialize): Convenience method to be overriden by subclasses which is called at the end of __init__ (LaunchTimeBenchmark.will_parse_arguments): Called before argparse.parse_args to let subclasses add new command line arguments (LaunchTimeBenchmark.did_parse_arguments): Called after argparse.parse_args to let subclass initialize based on command line arguments * LaunchTime/new_tab.py: Added (NewTabBenchmark): (NewTabBenchmark._parse_wait_time): Parser for wait time option (NewTabBenchmark.initialize): (NewTabBenchmark.run_iteration): (NewTabBenchmark.group_init): (NewTabBenchmark.will_parse_arguments): (NewTabBenchmark.did_parse_arguments): (NewTabBenchmark.ResponseHandler): (NewTabBenchmark.ResponseHandler.Handler): (NewTabBenchmark.ResponseHandler.Handler.get_test_page): * LaunchTime/startup.py: Added (StartupBenchmark): This benchmark measures browser startup time and initial page load time (StartupBenchmark.initialize): (StartupBenchmark.run_iteration): (StartupBenchmark.ResponseHandler): (StartupBenchmark.ResponseHandler.Handler): (StartupBenchmark.ResponseHandler.Handler.get_test_page): * LaunchTime/thirdparty/__init__.py: Added. (AutoinstallImportHook): Auto installs tornado package for feedback server (AutoinstallImportHook.__init__): (AutoinstallImportHook._ensure_autoinstalled_dir_is_in_sys_path): (AutoinstallImportHook.find_module): (AutoinstallImportHook._install_tornado): (AutoinstallImportHook.greater_than_equal_to_version): (AutoinstallImportHook._install): (AutoinstallImportHook.get_latest_pypi_url): (AutoinstallImportHook.install_binary): (autoinstall_everything): (get_os_info): Canonical link: https://commits.webkit.org/203012@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@234006 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-07-19 21:54:48 +00:00
# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
# Copyright (C) 2018 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# This module is required for Python to treat this directory as a package.
"""Autoinstalls third-party code required by WebKit."""
import codecs
import json
import os
import re
import sys
import urllib2
import imp
from collections import namedtuple
from distutils import spawn
webkitpy_path = os.path.join(os.path.dirname(__file__), '../../../Tools/Scripts/webkitpy')
autoinstall_path = os.path.join(webkitpy_path, 'common/system/autoinstall.py')
filesystem_path = os.path.join(webkitpy_path, 'common/system/filesystem.py')
AutoInstaller = imp.load_source('autoinstall', autoinstall_path).AutoInstaller
FileSystem = imp.load_source('filesystem', filesystem_path).FileSystem
_THIRDPARTY_DIR = os.path.dirname(__file__)
_AUTOINSTALLED_DIR = os.path.join(_THIRDPARTY_DIR, "autoinstalled")
# Putting the autoinstall code into LaunchTime/thirdparty/__init__.py
# ensures that no autoinstalling occurs until a caller imports from
# webkitpy.thirdparty. This is useful if the caller wants to configure
# logging prior to executing autoinstall code.
# FIXME: If any of these servers is offline, webkit-patch breaks (and maybe
# other scripts do, too). See <http://webkit.org/b/42080>.
# We put auto-installed third-party modules in this directory--
#
# LaunchTime/thirdparty/autoinstalled
fs = FileSystem()
fs.maybe_make_directory(_AUTOINSTALLED_DIR)
init_path = fs.join(_AUTOINSTALLED_DIR, "__init__.py")
if not fs.exists(init_path):
fs.write_text_file(init_path, "")
readme_path = fs.join(_AUTOINSTALLED_DIR, "README")
if not fs.exists(readme_path):
fs.write_text_file(readme_path,
"This directory is auto-generated by WebKit and is "
"safe to delete.\nIt contains needed third-party Python "
"packages automatically downloaded from the web.")
class AutoinstallImportHook(object):
def __init__(self, filesystem=None):
self._fs = filesystem or FileSystem()
def _ensure_autoinstalled_dir_is_in_sys_path(self):
# Some packages require that the are being put somewhere under a directory in sys.path.
if not _AUTOINSTALLED_DIR in sys.path:
sys.path.insert(0, _AUTOINSTALLED_DIR)
def find_module(self, fullname, _):
# This method will run before each import. See http://www.python.org/dev/peps/pep-0302/
if '.autoinstalled' not in fullname:
return
# Note: all of the methods must follow the "_install_XXX" convention in
# order for autoinstall_everything(), below, to work properly.
if '.tornado' in fullname:
self._install_tornado()
def _install_tornado(self):
self._ensure_autoinstalled_dir_is_in_sys_path()
self._install("https://files.pythonhosted.org/packages/45/ec/f2a03a0509bcfca336bef23a3dab0d07504893af34fd13064059ba4a0503/tornado-5.1.tar.gz",
"tornado-5.1/tornado")
@staticmethod
def greater_than_equal_to_version(minimum, version):
for i in xrange(len(minimum.split('.'))):
if int(version.split('.')[i]) > int(minimum.split('.')[i]):
return True
if int(version.split('.')[i]) < int(minimum.split('.')[i]):
return False
return True
def _install(self, url, url_subpath=None, target_name=None):
installer = AutoInstaller(target_dir=_AUTOINSTALLED_DIR)
installer.install(url=url, url_subpath=url_subpath, target_name=target_name)
def get_latest_pypi_url(self, package_name, url_subpath_format='{name}-{version}/{lname}'):
json_url = "https://pypi.python.org/pypi/%s/json" % package_name
response = urllib2.urlopen(json_url)
data = json.load(response)
url = data['urls'][1]['url']
subpath = url_subpath_format.format(name=package_name, version=data['info']['version'], lname=package_name.lower())
return (url, subpath)
def install_binary(self, url, name):
self._install(url=url, target_name=name)
directory = os.path.join(_AUTOINSTALLED_DIR, name)
os.chmod(os.path.join(directory, name), 0755)
open(os.path.join(directory, '__init__.py'), 'w+').close()
_hook = AutoinstallImportHook()
sys.meta_path.append(_hook)
def autoinstall_everything():
install_methods = [method for method in dir(_hook.__class__) if method.startswith('_install_')]
for method in install_methods:
getattr(_hook, method)()
def get_os_info():
import platform
os_name = platform.system()
os_type = platform.machine()[-2:]
return (os_name, os_type)