Bug 1365970 - Move data collector timer in the content process to idle dispatch. r=mikedeboer
☠☠ backed out by dce4d3db04bf ☠ ☠
authorWill Wang <wiwang@mozilla.com>
Fri, 08 Sep 2017 18:05:42 +0800
changeset 429250 6ee4de08ac3767c4d15338f830dc3763d5da769a
parent 429249 7ac52205995fc6bc4f2d1439d8941f964c526771
child 429251 563cbdd108d601c788b6d9b32092a6244ab7dc7f
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmikedeboer
bugs1365970
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1365970 - Move data collector timer in the content process to idle dispatch. r=mikedeboer
browser/components/sessionstore/content/content-sessionStore.js
--- a/browser/components/sessionstore/content/content-sessionStore.js
+++ b/browser/components/sessionstore/content/content-sessionStore.js
@@ -46,16 +46,18 @@ var gCurrentEpoch = 0;
 
 // A bound to the size of data to store for DOM Storage.
 const DOM_STORAGE_LIMIT_PREF = "browser.sessionstore.dom_storage_limit";
 
 // This pref controls whether or not we send updates to the parent on a timeout
 // or not, and should only be used for tests or debugging.
 const TIMEOUT_DISABLED_PREF = "browser.sessionstore.debug.no_auto_updates";
 
+const PREF_INTERVAL = "browser.sessionstore.interval";
+
 const kNoIndex = Number.MAX_SAFE_INTEGER;
 const kLastIndex = Number.MAX_SAFE_INTEGER - 1;
 
 /**
  * A function that will recursively call |cb| to collected data for all
  * non-dynamic frames in the current frame/docShell tree.
  */
 function mapFrameTree(callback) {
@@ -728,16 +730,27 @@ var MessageQueue = {
 
   /**
    * The delay (in ms) used to delay sending changes after data has been
    * invalidated.
    */
   BATCH_DELAY_MS: 1000,
 
   /**
+   * The minimum idle period (in ms) we need for sending data to chrome process.
+   */
+  NEEDED_IDLE_PERIOD_MS: 5,
+
+  /**
+   * Timeout for waiting an idle period to send data. We will set this from
+   * the pref "browser.sessionstore.interval".
+   */
+  _timeoutWaitIdlePeriodMs: null,
+
+  /**
    * The current timeout ID, null if there is no queue data. We use timeouts
    * to damp a flood of data changes and send lots of changes as one batch.
    */
   _timeout: null,
 
   /**
    * Whether or not sending batched messages on a timer is disabled. This should
    * only be used for debugging or testing. If you need to access this value,
@@ -766,28 +779,42 @@ var MessageQueue = {
     }
 
     return val;
   },
 
   init() {
     this.timeoutDisabled =
       Services.prefs.getBoolPref(TIMEOUT_DISABLED_PREF);
+    this._timeoutWaitIdlePeriodMs =
+      Services.prefs.getIntPref(PREF_INTERVAL);
 
     Services.prefs.addObserver(TIMEOUT_DISABLED_PREF, this);
+    Services.prefs.addObserver(PREF_INTERVAL, this);
   },
 
   uninit() {
     Services.prefs.removeObserver(TIMEOUT_DISABLED_PREF, this);
   },
 
   observe(subject, topic, data) {
-    if (topic == "nsPref:changed" && data == TIMEOUT_DISABLED_PREF) {
-      this.timeoutDisabled =
-        Services.prefs.getBoolPref(TIMEOUT_DISABLED_PREF);
+    if (topic == "nsPref:changed") {
+      switch (data) {
+        case TIMEOUT_DISABLED_PREF:
+          this.timeoutDisabled =
+            Services.prefs.getBoolPref(TIMEOUT_DISABLED_PREF);
+          break;
+        case PREF_INTERVAL:
+          this._timeoutWaitIdlePeriodMs =
+            Services.prefs.getIntPref(PREF_INTERVAL);
+          break;
+        default:
+          debug("received unknown message '" + data + "'");
+          break;
+      }
     }
   },
 
   /**
    * Pushes a given |value| onto the queue. The given |key| represents the type
    * of data that is stored and can override data that has been queued before
    * but has not been sent to the parent process, yet.
    *
@@ -798,21 +825,39 @@ var MessageQueue = {
    *        process.
    */
   push(key, fn) {
     this._data.set(key, fn);
 
     if (!this._timeout && !this._timeoutDisabled) {
       // Wait a little before sending the message to batch multiple changes.
       this._timeout = setTimeoutWithTarget(
-        () => this.send(), this.BATCH_DELAY_MS, tabEventTarget);
+        () => this.sendWhenIdle(), this.BATCH_DELAY_MS, tabEventTarget);
     }
   },
 
   /**
+   * Sends queued data when the remaining idle time is enough or waiting too
+   * long; otherwise, request an idle time again. If the |deadline| is not
+   * given, this function is going to schedule the first request.
+   *
+   * @param deadline (object)
+   *        An IdleDeadline object passed by requestIdleCallback().
+   */
+  sendWhenIdle(deadline) {
+    if (deadline) {
+      if (deadline.didTimeout || deadline.timeRemaining() > MessageQueue.NEEDED_IDLE_PERIOD_MS) {
+        MessageQueue.send();
+        return;
+      }
+    }
+    content.requestIdleCallback(MessageQueue.sendWhenIdle, {timeout: MessageQueue._timeoutWaitIdlePeriodMs});
+   },
+
+  /**
    * Sends queued data to the chrome process.
    *
    * @param options (object)
    *        {flushID: 123} to specify that this is a flush
    *        {isFinal: true} to signal this is the final message sent on unload
    */
   send(options = {}) {
     // Looks like we have been called off a timeout after the tab has been