Bug 1503339 - try using a lower frame rate for low-end devices r=kats,mconley
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Fri, 14 Dec 2018 20:16:16 +0000
changeset 507677 195290355ea5cdd1efd3cf0d15a2d9f0bb497d15
parent 507676 5bcc96228ac80527f92a1c525f8a7253350e2b18
child 507678 d4d1f7ec6966b236e836380b85930b8f588369e1
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats, mconley
bugs1503339
milestone66.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 1503339 - try using a lower frame rate for low-end devices r=kats,mconley Differential Revision: https://phabricator.services.mozilla.com/D13260
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
gfx/thebes/gfxPrefs.h
modules/libpref/init/all.js
toolkit/components/gfx/SanityTest.js
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2938,16 +2938,21 @@ bool gfxPlatform::ContentUsesTiling() co
       gfxVars::UseOMTP() && (gfxPrefs::LayersOMTPPaintWorkers() == -1 ||
                              gfxPrefs::LayersOMTPPaintWorkers() > 1);
 
   return gfxPrefs::LayersTilesEnabled() ||
          (gfxPrefs::LayersTilesEnabledIfSkiaPOMTP() && contentUsesSkia &&
           contentUsesPOMTP);
 }
 
+/* static */ bool gfxPlatform::ShouldAdjustForLowEndMachine() {
+  return gfxPrefs::AdjustToMachine() && !gfxPrefs::ResistFingerprinting() &&
+         gfxPrefs::IsLowEndMachineDoNotUseDirectly();
+}
+
 /***
  * The preference "layout.frame_rate" has 3 meanings depending on the value:
  *
  * -1 = Auto (default), use hardware vsync or software vsync @ 60 hz if hw
  *      vsync fails.
  *  0 = ASAP mode - used during talos testing.
  *  X = Software vsync at a rate of X times per second.
  */
@@ -2962,29 +2967,31 @@ gfxPlatform::CreateHardwareVsyncSource()
   // 1 is that the refresh driver and compositor are in lock step
   // the second is that the compositor goes ASAP and the refresh driver
   // goes at whatever the configurated rate is. This only checks the version
   // talos uses, which is the refresh driver and compositor are in lockstep.
   return gfxPrefs::LayoutFrameRate() == 0;
 }
 
 /* static */ bool gfxPlatform::ForceSoftwareVsync() {
-  return gfxPrefs::LayoutFrameRate() > 0 ||
+  return ShouldAdjustForLowEndMachine() || gfxPrefs::LayoutFrameRate() > 0 ||
          recordreplay::IsRecordingOrReplaying();
 }
 
 /* static */ int gfxPlatform::GetSoftwareVsyncRate() {
   int preferenceRate = gfxPrefs::LayoutFrameRate();
   if (preferenceRate <= 0) {
     return gfxPlatform::GetDefaultFrameRate();
   }
   return preferenceRate;
 }
 
-/* static */ int gfxPlatform::GetDefaultFrameRate() { return 60; }
+/* static */ int gfxPlatform::GetDefaultFrameRate() {
+  return ShouldAdjustForLowEndMachine() ? 30 : 60;
+}
 
 void gfxPlatform::GetAzureBackendInfo(mozilla::widget::InfoObject& aObj) {
   if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
     aObj.DefineProperty("AzureCanvasBackend (UI Process)",
                         GetBackendName(mPreferredCanvasBackend));
     aObj.DefineProperty("AzureFallbackCanvasBackend (UI Process)",
                         GetBackendName(mFallbackCanvasBackend));
     aObj.DefineProperty("AzureContentBackend (UI Process)",
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -617,16 +617,25 @@ class gfxPlatform : public mozilla::laye
   void PurgeSkiaGPUCache();
   static void PurgeSkiaFontCache();
 
   static bool UsesOffMainThreadCompositing();
 
   bool HasEnoughTotalSystemMemoryForSkiaGL();
 
   /**
+   * Whether we want to adjust gfx parameters (currently just
+   * the framerate and whether we use software vs. hardware vsync)
+   * down because we've determined we're on a low-end machine.
+   * This will return false if the user has turned on fingerprinting
+   * resistance (to ensure consistent behavior across devices).
+   */
+  static bool ShouldAdjustForLowEndMachine();
+
+  /**
    * Get the hardware vsync source for each platform.
    * Should only exist and be valid on the parent process
    */
   virtual mozilla::gfx::VsyncSource* GetHardwareVsync() {
     MOZ_ASSERT(mVsyncSource != nullptr);
     MOZ_ASSERT(XRE_IsParentProcess() ||
                mozilla::recordreplay::IsRecordingOrReplaying());
     return mVsyncSource;
@@ -635,26 +644,26 @@ class gfxPlatform : public mozilla::laye
   /**
    * True if layout rendering should use ASAP mode, which means
    * the refresh driver and compositor should render ASAP.
    * Used for talos testing purposes
    */
   static bool IsInLayoutAsapMode();
 
   /**
+   * Returns whether or not a custom vsync rate is set.
+   */
+  static bool ForceSoftwareVsync();
+
+  /**
    * Returns the software vsync rate to use.
    */
   static int GetSoftwareVsyncRate();
 
   /**
-   * Returns whether or not a custom vsync rate is set.
-   */
-  static bool ForceSoftwareVsync();
-
-  /**
    * Returns the default frame rate for the refresh driver / software vsync.
    */
   static int GetDefaultFrameRate();
 
   /**
    * Used to test which input types are handled via APZ.
    */
   virtual bool SupportsApzWheelInput() const { return false; }
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -752,18 +752,25 @@ class gfxPrefs final {
                                                                MouseWheelRootScrollHorizontalFactor, int32_t, 0);
   DECL_GFX_PREF(Live, "mousewheel.system_scroll_override_on_root_content.vertical.factor",
                                                                MouseWheelRootScrollVerticalFactor, int32_t, 0);
   DECL_GFX_PREF(Live, "mousewheel.transaction.ignoremovedelay",MouseWheelIgnoreMoveDelayMs, int32_t, (int32_t)100);
   DECL_GFX_PREF(Live, "mousewheel.transaction.timeout",        MouseWheelTransactionTimeoutMs, int32_t, (int32_t)1500);
 
   DECL_GFX_PREF(Live, "nglayout.debug.widget_update_flashing", WidgetUpdateFlashing, bool, false);
 
+  DECL_GFX_PREF(Live, "performance.adjust_to_machine",         AdjustToMachine, bool, false);
+  // Use gfxPlatform::ShouldAdjustForLowEndMachine() to determine if you should use low-end
+  // machine code-paths, rather than checking this pref directly.
+  DECL_GFX_PREF(Live, "performance.low_end_machine",           IsLowEndMachineDoNotUseDirectly, bool, false);
+
   DECL_GFX_PREF(Live, "print.font-variations-as-paths",        PrintFontVariationsAsPaths, bool, true);
 
+  DECL_GFX_PREF(Live, "privacy.resistFingerprinting",          ResistFingerprinting, bool, false);
+
   DECL_GFX_PREF(Once, "slider.snapMultiplier",                 SliderSnapMultiplier, int32_t, 0);
 
   DECL_GFX_PREF(Live, "test.events.async.enabled",             TestEventsAsyncEnabled, bool, false);
   DECL_GFX_PREF(Live, "test.mousescroll",                      MouseScrollTestingEnabled, bool, false);
 
   DECL_GFX_PREF(Live, "toolkit.scrollbox.horizontalScrollDistance", ToolkitHorizontalScrollDistance, int32_t, 5);
   DECL_GFX_PREF(Live, "toolkit.scrollbox.verticalScrollDistance",   ToolkitVerticalScrollDistance, int32_t, 3);
 
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -951,16 +951,24 @@ pref("gfx.webrender.debug.echo-driver-me
 pref("gfx.webrender.debug.new-frame-indicator", false);
 pref("gfx.webrender.debug.new-scene-indicator", false);
 pref("gfx.webrender.debug.show-overdraw", false);
 pref("gfx.webrender.debug.slow-frame-indicator", false);
 pref("gfx.webrender.dl.dump-parent", false);
 pref("gfx.webrender.dl.dump-content", false);
 pref("gfx.webrender.picture-caching", false);
 
+#ifdef EARLY_BETA_OR_EARLIER
+pref("performance.adjust_to_machine", true);
+#else
+pref("performance.adjust_to_machine", false);
+#endif
+
+pref("performance.low_end_machine", false);
+
 pref("accessibility.browsewithcaret", false);
 pref("accessibility.warn_on_browsewithcaret", true);
 
 pref("accessibility.browsewithcaret_shortcut.enabled", true);
 
 #ifndef XP_MACOSX
 // Tab focus model bit field:
 // 1 focuses text controls, 2 focuses other form elements, 4 adds links.
--- a/toolkit/components/gfx/SanityTest.js
+++ b/toolkit/components/gfx/SanityTest.js
@@ -2,16 +2,19 @@
  * 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/. */
 
 "use strict";
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
+ChromeUtils.defineModuleGetter(this, "AppConstants",
+  "resource://gre/modules/AppConstants.jsm");
+
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const FRAME_SCRIPT_URL = "chrome://gfxsanity/content/gfxFrameScript.js";
 
 const PAGE_WIDTH = 160;
 const PAGE_HEIGHT = 234;
 const LEFT_EDGE = 8;
 const TOP_EDGE = 8;
 const CANVAS_WIDTH = 32;
@@ -21,16 +24,18 @@ const CANVAS_HEIGHT = 64;
 const VIDEO_WIDTH = 132;
 const VIDEO_HEIGHT = 132;
 const DRIVER_PREF = "sanity-test.driver-version";
 const DEVICE_PREF = "sanity-test.device-id";
 const VERSION_PREF = "sanity-test.version";
 const ADVANCED_LAYERS_PREF = "sanity-test.advanced-layers";
 const DISABLE_VIDEO_PREF = "media.hardware-video-decoding.failed";
 const RUNNING_PREF = "sanity-test.running";
+const PERF_ADJUSTMENT_PREF = "performance.adjust_to_machine";
+const LOWEND_DEVICE_PREF = "performance.low_end_machine";
 const TIMEOUT_SEC = 20;
 
 const AL_ENABLED_PREF = "layers.mlgpu.enabled";
 const AL_TEST_FAILED_PREF = "layers.mlgpu.sanity-test-failed";
 
 // GRAPHICS_SANITY_TEST histogram enumeration values
 const TEST_PASSED = 0;
 const TEST_FAILED_RENDER = 1;
@@ -327,28 +332,48 @@ SanityTest.prototype = {
     Services.prefs.setBoolPref(ADVANCED_LAYERS_PREF, hasAL);
 
     // Update the prefs so that this test doesn't run again until the next update.
     Services.prefs.setBoolPref(RUNNING_PREF, true);
     Services.prefs.savePrefFile(null);
     return true;
   },
 
+  _updateLowEndState() {
+    // If we want to adjust performance based on the machine characteristics...
+    if (Services.prefs.getBoolPref(PERF_ADJUSTMENT_PREF, AppConstants.EARLY_BETA_OR_EARLIER)) {
+      // ... treat any machines with 1-2 cores and a clock speed under 1.8GHz
+      // as "low-end". This will trigger use of a lower frame-rate to help free
+      // the CPU for other work by reducing the amount of painting/compositing
+      // we do.
+      // The cut-off here is based on a combination of telemetry info, running
+      // performance tests on the 2018 reference hardware, and gut instinct.
+      // Ideally, we should replace it with one that's entirely powered by
+      // data correlations from telemetry - see bug 1475242 for more.
+      let isLowEnd = Services.sysinfo.get("cpucores") <= 2 && Services.sysinfo.get("cpuspeed") < 1800;
+      Services.prefs.setBoolPref(LOWEND_DEVICE_PREF, isLowEnd);
+    } else {
+      Services.prefs.clearUserPref(LOWEND_DEVICE_PREF);
+    }
+  },
+
   observe(subject, topic, data) {
     if (topic != "profile-after-change") return;
 
     // profile-after-change fires only at startup, so we won't need
     // to use the listener again.
     let tester = listener;
     listener = null;
 
     if (!this.shouldRunTest()) return;
 
     annotateCrashReport();
 
+    this._updateLowEndState();
+
     // Open a tiny window to render our test page, and notify us when it's loaded
     var sanityTest = Services.ww.openWindow(null,
         "chrome://gfxsanity/content/sanityparent.html",
         "Test Page",
         "width=" + PAGE_WIDTH + ",height=" + PAGE_HEIGHT + ",chrome,titlebar=0,scrollbars=0,popup=1",
         null);
 
     // There's no clean way to have an invisible window and ensure it's always painted.