Bug 1499609 Convert cpstartup to a webextension r=mconley
authorAndrew Swan <aswan@mozilla.com>
Tue, 23 Oct 2018 21:39:17 +0000
changeset 491023 e19cd8da255dd2fedd21c69a99545d4b5f0f1ef3
parent 491022 3d84f10a7e99dd56fef9dcd48c5bfa9bcfa8a828
child 491024 3d22697d9c23a23087190225aa201a44bc1be130
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersmconley
bugs1499609
milestone65.0a1
Bug 1499609 Convert cpstartup to a webextension r=mconley Differential Revision: https://phabricator.services.mozilla.com/D9411
testing/talos/talos/test.py
testing/talos/talos/tests/cpstartup/bootstrap.js
testing/talos/talos/tests/cpstartup/chrome.manifest
testing/talos/talos/tests/cpstartup/content/cpstartup.html
testing/talos/talos/tests/cpstartup/content/target.html
testing/talos/talos/tests/cpstartup/cpstartup.html
testing/talos/talos/tests/cpstartup/cpstartup.manifest
testing/talos/talos/tests/cpstartup/extension/api.js
testing/talos/talos/tests/cpstartup/extension/framescript.js
testing/talos/talos/tests/cpstartup/extension/manifest.json
testing/talos/talos/tests/cpstartup/extension/schema.json
testing/talos/talos/tests/cpstartup/install.rdf
testing/talos/talos/tests/cpstartup/target.html
--- a/testing/talos/talos/test.py
+++ b/testing/talos/talos/test.py
@@ -280,24 +280,23 @@ class tpaint(PageloaderTest):
 
 @register_test()
 class cpstartup(PageloaderTest):
     """
     Tests the amount of time it takes to start up a new content process and
     initialize it to the point where it can start processing incoming URLs
     to load.
     """
-    extensions = ['${talos}/tests/cpstartup', '${talos}/pageloader']
+    extensions = ['${talos}/pageloader', '${talos}/tests/cpstartup/extension']
     tpmanifest = '${talos}/tests/cpstartup/cpstartup.manifest'
     tppagecycles = 20
     gecko_profile_entries = 1000000
     tploadnocache = True
     unit = 'ms'
     preferences = {
-        'addon.test.cpstartup.webserver': '${webserver}',
         # By default, Talos is configured to open links from
         # content in new windows. We're overriding them so that
         # they open in new tabs instead.
         # See http://kb.mozillazine.org/Browser.link.open_newwindow
         # and http://kb.mozillazine.org/Browser.link.open_newwindow.restriction
         'browser.link.open_newwindow': 3,
         'browser.link.open_newwindow.restriction': 2,
     }
deleted file mode 100644
--- a/testing/talos/talos/tests/cpstartup/chrome.manifest
+++ /dev/null
@@ -1,1 +0,0 @@
-content cpstartup content/ remoteenabled=yes contentaccessible=yes
\ No newline at end of file
rename from testing/talos/talos/tests/cpstartup/content/cpstartup.html
rename to testing/talos/talos/tests/cpstartup/cpstartup.html
--- a/testing/talos/talos/tests/cpstartup/content/cpstartup.html
+++ b/testing/talos/talos/tests/cpstartup/cpstartup.html
@@ -1,27 +1,43 @@
 <html>
-  <head>
-    <script>
+<head>
+<script>
 
-      function init() {
-        if (document.location.hash.indexOf("#auto") == 0) {
-          let mm = window.docShell.messageManager;
+function init() {
+  window.addEventListener("CPStartup:FinalResults", function onResults(event) {
+    let results = event.detail;
+    tpRecordTime(results, 0, "content-process-startup");
+  }, {once: true});
 
-          mm.addMessageListener("CPStartup:FinalResults", function onResults(msg) {
-            mm.removeMessageListener("CPStartup:FinalResults", onResults);
-            let results = msg.data;
+  async function tryPing() {
+    let pingPromise = new Promise(resolve => {
+      window.addEventListener("CPStartup:Pong", resolve, {once: true});
+      dispatchEvent(new CustomEvent("CPStartup:Ping", {bubbles: true}));
+    });
+    let timeoutPromise = new Promise((resolve, reject) => setTimeout(reject, 500));
 
-            tpRecordTime(results, 0, "content-process-startup");
-          });
-
-          mm.sendAsyncMessage("CPStartup:Go");
-        }
-      }
+    try {
+      await Promise.race([pingPromise, timeoutPromise]);
+    } catch (e) {
+      return tryPing();
+    }
+    return null;
+  }
 
-    </script>
-  </head>
-  <body onload="init();">
-    Hello, Talos!
+  let target = document.location.href.replace(/cpstartup.html$/, "target.html");
+  tryPing().then(() => {
+    dispatchEvent(new CustomEvent("CPStartup:Go", {
+      bubbles: true,
+      detail: {target},
+    }));
+  });
+}
 
-    <a href="#" id="target" target="_blank">I'll open a new tab</a>
-  </body>
+</script>
+</head>
+
+<body onload="init();">
+  Hello, Talos!
+
+  <a href="#" id="target" target="_blank">I'll open a new tab</a>
+</body>
 </html>
--- a/testing/talos/talos/tests/cpstartup/cpstartup.manifest
+++ b/testing/talos/talos/tests/cpstartup/cpstartup.manifest
@@ -1,1 +1,1 @@
-% chrome://cpstartup/content/cpstartup.html#auto
+% http://localhost/tests/cpstartup/cpstartup.html
rename from testing/talos/talos/tests/cpstartup/bootstrap.js
rename to testing/talos/talos/tests/cpstartup/extension/api.js
--- a/testing/talos/talos/tests/cpstartup/bootstrap.js
+++ b/testing/talos/talos/tests/cpstartup/extension/api.js
@@ -1,75 +1,75 @@
 /* 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/. */
 
-ChromeUtils.import("resource://gre/modules/Services.jsm");
-
-const PREALLOCATED_PREF = "dom.ipc.processPrelaunch.enabled";
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
-const TARGET_PATH = "tests/cpstartup/content/target.html";
-const WEBSERVER = Services.prefs.getCharPref("addon.test.cpstartup.webserver");
-const TARGET_URI = `${WEBSERVER}/${TARGET_PATH}`;
 
 /**
- * The purpose of this test it to measure the performance of a content process startup.
+ * The purpose of this test it to measure the performance of a
+ * content process startup.
  *
- * In practice it measures a bit more than the content process startup. First the parent
- * process starts the clock and requests a new tab with a simple page and then the child
- * stops the clock in the frame script that will be able to process the URL to handle.
- * So it does measure a few things pre process creation (browser element and tab creation
- * on parent side) but does not measure the part where we actually parse and render the
- * page on the content side, just the overhead of spawning a new content process.
+ * In practice it measures a bit more than the content process startup. First
+ * the parent process starts the clock and requests a new tab with a simple
+ * page and then the child stops the clock in the frame script that will be
+ * able to process the URL to handle.  So it does measure a few things
+ * pre process creation (browser element and tab creation on parent side) but
+ * does not measure the part where we actually parse and render the page on
+ * the content side, just the overhead of spawning a new content process.
  */
-var CPStartup = {
-  MESSAGES: [
-    "CPStartup:Go",
-    "Content:BrowserChildReady",
-  ],
+
+XPCOMUtils.defineLazyScriptGetter(this, "TalosParentProfiler",
+                                  "resource://talos-powers/TalosParentProfiler.js");
 
-  readyCallback: null,
-
-  startStamp: null,
+ChromeUtils.defineModuleGetter(this, "Services",
+                               "resource://gre/modules/Services.jsm");
 
-  tab: null,
-  /**
-   * Shortcut to getting at the TalosParentProfiler.
-   */
-  get Profiler() {
-    delete this.Profiler;
-    let context = {};
-    Services.scriptloader.loadSubScript("resource://talos-powers/TalosParentProfiler.js", context);
-    return this.Profiler = context.TalosParentProfiler;
-  },
+const PREALLOCATED_PREF = "dom.ipc.processPrelaunch.enabled";
+const MESSAGES = [
+  "CPStartup:Go",
+  "Content:BrowserChildReady",
+];
 
-  init() {
-    for (let msgName of this.MESSAGES) {
+/* global ExtensionAPI */
+
+this.cpstartup = class extends ExtensionAPI {
+  onStartup() {
+    for (let msgName of MESSAGES) {
       Services.mm.addMessageListener(msgName, this);
     }
 
+    this.framescriptURL = this.extension.baseURI.resolve("/framescript.js");
+    Services.mm.loadFrameScript(this.framescriptURL, true);
+
     this.originalPreallocatedEnabled = Services.prefs.getBoolPref(PREALLOCATED_PREF);
     Services.prefs.setBoolPref(PREALLOCATED_PREF, false);
-  },
+
+    this.readyCallback = null;
+    this.startStamp = null;
+    this.tab = null;
+  }
 
-  uninit() {
-    for (let msgName of this.MESSAGES) {
+  onShutdown() {
+    Services.prefs.setBoolPref(PREALLOCATED_PREF, this.originalPreallocatedEnabled);
+    Services.mm.removeDelayedFrameScript(this.framescriptURL);
+
+    for (let msgName of MESSAGES) {
       Services.mm.removeMessageListener(msgName, this);
     }
-
-    Services.prefs.setBoolPref(PREALLOCATED_PREF, this.originalPreallocatedEnabled);
-  },
+  }
 
   receiveMessage(msg) {
     let browser = msg.target;
     let gBrowser = browser.ownerGlobal.gBrowser;
 
     switch (msg.name) {
       case "CPStartup:Go": {
-        this.openTab(gBrowser).then(results =>
+        this.openTab(gBrowser, msg.data.target).then(results =>
           this.reportResults(results));
         break;
       }
 
       case "Content:BrowserChildReady": {
         // Content has reported that it's ready to process an URL.
         if (!this.readyCallback) {
           throw new Error("Content:BrowserChildReady fired without a readyCallback set");
@@ -81,64 +81,46 @@ var CPStartup = {
         }
         // The child stopped the timer when it was ready to process the first URL, it's time to
         // calculate the difference and report it.
         let delta = msg.data.time - this.startStamp;
         this.readyCallback({tab, delta});
         break;
       }
     }
-  },
+  }
 
-  openTab(gBrowser) {
-    return new Promise((resolve) => {
-      // Start the timer and the profiler right before the tab open on the parent side.
-      this.Profiler.resume("tab opening starts");
-      this.startStamp = Services.telemetry.msSystemNow();
-      this.tab = gBrowser.selectedTab = gBrowser.addTab(TARGET_URI, {
-        triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
-      });
+  async openTab(gBrowser, url) {
+    // Start the timer and the profiler right before the tab open on the parent side.
+    TalosParentProfiler.resume("tab opening starts");
+    this.startStamp = Services.telemetry.msSystemNow();
+    this.tab = gBrowser.selectedTab = gBrowser.addTrustedTab(url);
 
-      this.whenTabReady().then(({tab, delta}) => {
-        this.Profiler.pause("tab opening end");
-        this.removeTab(tab).then(() => {
-          resolve(delta);
-        });
-      });
-    });
-  },
+    let {tab, delta} = await this.whenTabReady();
+    TalosParentProfiler.pause("tab opening end");
+    await this.removeTab(tab);
+    return delta;
+  }
 
   whenTabReady() {
     return new Promise((resolve) => {
       this.readyCallback = resolve;
     });
-  },
+  }
 
   removeTab(tab) {
     return new Promise((resolve) => {
       let {messageManager: mm, frameLoader} = tab.linkedBrowser;
       mm.addMessageListener("SessionStore:update", function onMessage(msg) {
         if (msg.targetFrameLoader == frameLoader && msg.data.isFinal) {
           mm.removeMessageListener("SessionStore:update", onMessage);
           resolve();
         }
       }, true);
 
       tab.ownerGlobal.gBrowser.removeTab(tab);
     });
-  },
+  }
 
   reportResults(results) {
     Services.mm.broadcastAsyncMessage("CPStartup:FinalResults", results);
-  },
+  }
 };
-
-function install(aData, aReason) {}
-
-function startup(aData, aReason) {
-  CPStartup.init();
-}
-
-function shutdown(aData, aReason) {
-  CPStartup.uninit();
-}
-
-function uninstall(aData, aReason) {}
new file mode 100644
--- /dev/null
+++ b/testing/talos/talos/tests/cpstartup/extension/framescript.js
@@ -0,0 +1,19 @@
+(function() {
+  addEventListener("CPStartup:Ping", e => {
+    let evt = new content.CustomEvent("CPStartup:Pong", {bubbles: true});
+    content.dispatchEvent(evt);
+  }, false, true);
+
+  addEventListener("CPStartup:Go", e => {
+    sendAsyncMessage("CPStartup:Go", e.detail);
+  }, false, true);
+
+  addMessageListener("CPStartup:FinalResults", msg => {
+    let evt = Cu.cloneInto({
+      bubbles: true,
+      detail: msg.data,
+    }, content);
+
+    content.dispatchEvent(new content.CustomEvent("CPStartup:FinalResults", evt));
+  });
+})();
rename from testing/talos/talos/tests/cpstartup/install.rdf
rename to testing/talos/talos/tests/cpstartup/extension/manifest.json
--- a/testing/talos/talos/tests/cpstartup/install.rdf
+++ b/testing/talos/talos/tests/cpstartup/extension/manifest.json
@@ -1,24 +1,23 @@
-<?xml version="1.0"?>
-<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
-  <Description about="urn:mozilla:install-manifest">
-    <em:id>cpstartup-test@mozilla.org</em:id>
-    <em:type>2</em:type>
-    <em:name>cpstartup test</em:name>
-    <em:version>1.0.0</em:version>
-    <em:bootstrap>true</em:bootstrap>
-    <em:description>Measures the performance of starting and initializing new content processes</em:description>
-    <em:creator>Gabor Krizsanits</em:creator>
-    <em:multiprocessCompatible>true</em:multiprocessCompatible>
+{
+  "manifest_version": 2,
+  "name": "cpstartup test",
+  "description": "Measures the performance of starting and initializing new content processes",
+  "version": "1.1",
+
+  "applications": {
+    "gecko": {
+      "id": "cpstartup-test@mozilla.org"
+    }
+  },
 
-    <!-- Desktop -->
-    <em:targetApplication>
-      <Description>
-        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
-        <em:minVersion>55.0</em:minVersion>
-        <em:maxVersion>*</em:maxVersion>
-      </Description>
-    </em:targetApplication>
-    <em:description>https://wiki.mozilla.org/Buildbot/Talos/Tests</em:description>
-    <em:homepageURL>https://wiki.mozilla.org/Buildbot/Talos/Tests</em:homepageURL>
-  </Description>
-</RDF>
+  "experiment_apis": {
+    "cpstartup": {
+      "schema": "schema.json",
+      "parent": {
+        "scopes": ["addon_parent"],
+        "script": "api.js",
+        "events": ["startup"]
+      }
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/testing/talos/talos/tests/cpstartup/extension/schema.json
@@ -0,0 +1,1 @@
+[]
rename from testing/talos/talos/tests/cpstartup/content/target.html
rename to testing/talos/talos/tests/cpstartup/target.html