diff options
Diffstat (limited to 'testing/awsy/awsy/test_memory_usage.py')
-rw-r--r-- | testing/awsy/awsy/test_memory_usage.py | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/testing/awsy/awsy/test_memory_usage.py b/testing/awsy/awsy/test_memory_usage.py new file mode 100644 index 0000000000..e3daaf08dc --- /dev/null +++ b/testing/awsy/awsy/test_memory_usage.py @@ -0,0 +1,238 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import sys + +import mozinfo +import yaml +from marionette_driver.errors import JavascriptException, ScriptTimeoutException +from mozproxy import get_playback + +AWSY_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) +if AWSY_PATH not in sys.path: + sys.path.append(AWSY_PATH) + +from awsy import process_perf_data, webservers +from awsy.awsy_test_case import AwsyTestCase + + +class TestMemoryUsage(AwsyTestCase): + """Provides a test that collects memory usage at various checkpoints: + - "Start" - Just after startup + - "StartSettled" - After an additional wait time + - "TabsOpen" - After opening all provided URLs + - "TabsOpenSettled" - After an additional wait time + - "TabsOpenForceGC" - After forcibly invoking garbage collection + - "TabsClosed" - After closing all tabs + - "TabsClosedSettled" - After an additional wait time + - "TabsClosedForceGC" - After forcibly invoking garbage collection + """ + + def urls(self): + return self._urls + + def perf_suites(self): + return process_perf_data.PERF_SUITES + + def perf_checkpoints(self): + return process_perf_data.CHECKPOINTS + + def perf_extra_opts(self): + return self._extra_opts + + def setupTp5(self): + urls = None + default_tp5n_manifest = os.path.join( + self._webroot_dir, "page_load_test", "tp5n", "tp5n.manifest" + ) + tp5n_manifest = self.testvars.get("pageManifest", default_tp5n_manifest) + with open(tp5n_manifest) as fp: + urls = fp.readlines() + # pylint --py3k: W1636 + urls = list(map(lambda x: x.replace("localhost", "localhost:{}"), urls)) + + # We haven't set self._urls yet, so this value might be zero if + # 'entities' wasn't specified. + to_load = self.pages_to_load() + if not to_load: + to_load = len(urls) + self._webservers = webservers.WebServers( + "localhost", 8001, self._webroot_dir, to_load + ) + self._webservers.start() + for url, server in zip(urls, self._webservers.servers): + self._urls.append(url.strip().format(server.port)) + + def setupTp6(self): + # tp5n stores its manifest in the zip file that gets extracted, tp6 + # doesn't so we just keep one in our project dir for now. + default_tp6_pages_manifest = os.path.join(AWSY_PATH, "conf", "tp6-pages.yml") + tp6_pages_manifest = self.testvars.get( + "pageManifest", default_tp6_pages_manifest + ) + urls = [] + with open(tp6_pages_manifest) as f: + d = yaml.safe_load(f) + for r in d: + url = r["url"] + if isinstance(url, list): + urls.extend(url) + else: + urls.append(url) + + self._urls = urls + + # Indicate that we're using tp6 in the perf data. + self._extra_opts = ["tp6"] + + if self.marionette.get_pref("fission.autostart"): + self._extra_opts.append("fission") + + # Now we setup the mitm proxy with our tp6 pageset. + tp6_pageset_manifest = os.path.join(AWSY_PATH, "tp6-pageset.manifest") + config = { + "playback_tool": "mitmproxy", + "playback_version": "5.1.1", + "playback_files": [tp6_pageset_manifest], + "platform": mozinfo.os, + "obj_path": self._webroot_dir, + "binary": self._binary, + "run_local": self._run_local, + "app": "firefox", + "host": "127.0.0.1", + "ignore_mitmdump_exit_failure": True, + } + + self._playback = get_playback(config) + self._playback.start() + + # We need to reload after the mitmproxy cert is installed + self.marionette.restart(in_app=False, clean=False) + + # Setup WebDriver capabilities that we need + self.marionette.delete_session() + caps = { + "unhandledPromptBehavior": "dismiss", # Ignore page navigation warnings + } + self.marionette.start_session(caps) + self.marionette.set_context("chrome") + + def setUp(self): + AwsyTestCase.setUp(self) + self.logger.info("setting up") + self._webroot_dir = self.testvars["webRootDir"] + self._urls = [] + self._extra_opts = None + + if self.testvars.get("tp6", False): + self.setupTp6() + else: + self.setupTp5() + + self.logger.info( + "areweslimyet run by %d pages, %d iterations," + " %d perTabPause, %d settleWaitTime" + % ( + self._pages_to_load, + self._iterations, + self._perTabPause, + self._settleWaitTime, + ) + ) + self.logger.info("done setting up!") + + def tearDown(self): + self.logger.info("tearing down!") + + self.logger.info("tearing down webservers!") + + if self.testvars.get("tp6", False): + self._playback.stop() + else: + self._webservers.stop() + + AwsyTestCase.tearDown(self) + + self.logger.info("done tearing down!") + + def clear_preloaded_browser(self): + """ + Clears out the preloaded browser. + """ + self.logger.info("closing preloaded browser") + script = """ + if (window.NewTabPagePreloading) { + return NewTabPagePreloading.removePreloadedBrowser(window); + } + return "NewTabPagePreloading.removePreloadedBrowser not available"; + """ + try: + result = self.marionette.execute_script(script, script_timeout=180000) + except JavascriptException as e: + self.logger.error("removePreloadedBrowser() JavaScript error: %s" % e) + except ScriptTimeoutException: + self.logger.error("removePreloadedBrowser() timed out") + except Exception: + self.logger.error( + "removePreloadedBrowser() Unexpected error: %s" % sys.exc_info()[0] + ) + else: + if result: + self.logger.info(result) + + def test_open_tabs(self): + """Marionette test entry that returns an array of checkpoint arrays. + + This will generate a set of checkpoints for each iteration requested. + Upon successful completion the results will be stored in + |self.testvars["results"]| and accessible to the test runner via the + |testvars| object it passed in. + """ + # setup the results array + results = [[] for _ in range(self.iterations())] + + def create_checkpoint(name, iteration, minimize=False): + checkpoint = self.do_memory_report(name, iteration, minimize) + self.assertIsNotNone(checkpoint, "Checkpoint was recorded") + results[iteration].append(checkpoint) + + # The first iteration gets Start and StartSettled entries before + # opening tabs + create_checkpoint("Start", 0) + self.settle() + create_checkpoint("StartSettled", 0) + + for itr in range(self.iterations()): + self.open_pages() + + create_checkpoint("TabsOpen", itr) + self.settle() + create_checkpoint("TabsOpenSettled", itr) + create_checkpoint("TabsOpenForceGC", itr, minimize=True) + + # Close all tabs + self.reset_state() + + with self.marionette.using_context("content"): + self.logger.info("navigating to about:blank") + self.marionette.navigate("about:blank") + self.logger.info("navigated to about:blank") + self.signal_user_active() + + # Create checkpoint that may contain retained processes that will + # be reused. + create_checkpoint("TabsClosedExtraProcesses", itr) + + # Clear out the retained processes and measure again. + self.clear_preloaded_browser() + + create_checkpoint("TabsClosed", itr) + self.settle() + create_checkpoint("TabsClosedSettled", itr) + create_checkpoint("TabsClosedForceGC", itr, minimize=True) + + # TODO(ER): Temporary hack until bug 1121139 lands + self.logger.info("setting results") + self.testvars["results"] = results |