Bug 1551890 - Cache GFXInfo WebRTC HW encode/decode result on Android. r=snorp
authorChris Pearce <cpearce@mozilla.com>
Thu, 16 May 2019 22:42:00 +0000
changeset 474270 f6d24071d2baeecac739a6a5d2853db19ee57e79
parent 474269 3ff35309eb24e349b2752522c082e9261988f52b
child 474271 f48939dc27b6418ffbc473cf8077f329d14f2a86
push id113144
push usershindli@mozilla.com
push dateFri, 17 May 2019 16:44:55 +0000
treeherdermozilla-inbound@f4c4b796f845 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp
bugs1551890
milestone68.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 1551890 - Cache GFXInfo WebRTC HW encode/decode result on Android. r=snorp Profiling shows that we're spending a lot of time on startup inside android.media.MediaCodecList.getCodecCount when GfxInfo::GetFeatureStatus calls over to Java to determine whether hardware accelerated video encoding is supported. Looking at the Java stacks in the profile, Android is spending most of our time creating a list of codecs. It doesn't look like there's a faster way to query for hardware accelerated video support. So to speed this up we can cache the value in the user's profile. We also store the OS version, which we can use to detect when the OS is updated so we can invalidate the cache then. Presumably an OS update is the only way a device can have its hardware acceleration support status change. With this change, the time we take figuring out the HW encode/decode status goes from ~100ms on a cold run to ~0.01ms on a cache hit on my HD8 tablet. Differential Revision: https://phabricator.services.mozilla.com/D31380
widget/android/GfxInfo.cpp
widget/android/GfxInfo.h
--- a/widget/android/GfxInfo.cpp
+++ b/widget/android/GfxInfo.cpp
@@ -11,16 +11,18 @@
 #include "nsExceptionHandler.h"
 #include "nsHashKeys.h"
 #include "nsICrashReporter.h"
 #include "nsVersionComparator.h"
 #include "AndroidBridge.h"
 #include "nsIWindowWatcher.h"
 #include "nsServiceManagerUtils.h"
 
+#include "mozilla/Preferences.h"
+
 #define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1"
 
 namespace mozilla {
 namespace widget {
 
 class GfxInfo::GLStrings {
   nsCString mVendor;
   nsCString mRenderer;
@@ -479,28 +481,24 @@ nsresult GfxInfo::GetFeatureStatusImpl(
           aFailureId = "FEATURE_FAILURE_4_3_SONY";
           return NS_OK;
         }
       }
     }
 
     if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION_ENCODE) {
       if (mozilla::AndroidBridge::Bridge()) {
-        *aStatus = mozilla::AndroidBridge::Bridge()->GetHWEncoderCapability()
-                       ? nsIGfxInfo::FEATURE_STATUS_OK
-                       : nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
+        *aStatus = WebRtcHwEncodeSupported();
         aFailureId = "FEATURE_FAILURE_WEBRTC_ENCODE";
         return NS_OK;
       }
     }
     if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION_DECODE) {
       if (mozilla::AndroidBridge::Bridge()) {
-        *aStatus = mozilla::AndroidBridge::Bridge()->GetHWDecoderCapability()
-                       ? nsIGfxInfo::FEATURE_STATUS_OK
-                       : nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
+        *aStatus = WebRtcHwDecodeSupported();
         aFailureId = "FEATURE_FAILURE_WEBRTC_DECODE";
         return NS_OK;
       }
     }
 
     if (aFeature == FEATURE_VP8_HW_DECODE ||
         aFeature == FEATURE_VP9_HW_DECODE) {
       NS_LossyConvertUTF16toASCII model(mModel);
@@ -517,16 +515,99 @@ nsresult GfxInfo::GetFeatureStatusImpl(
       return NS_OK;
     }
   }
 
   return GfxInfoBase::GetFeatureStatusImpl(
       aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
 }
 
+static nsCString FeatureCacheOsVerPrefName(int32_t aFeature) {
+  nsCString osPrefName;
+  osPrefName.AppendASCII("gfxinfo.cache.");
+  osPrefName.AppendInt(aFeature);
+  osPrefName.AppendASCII(".osver");
+  return osPrefName;
+}
+
+static nsCString FeatureCacheValuePrefName(int32_t aFeature) {
+  nsCString osPrefName;
+  osPrefName.AppendASCII("gfxinfo.cache.");
+  osPrefName.AppendInt(aFeature);
+  osPrefName.AppendASCII(".value");
+  return osPrefName;
+}
+
+static bool GetCachedFeatureVal(int32_t aFeature, uint32_t aExpectedOsVer,
+                                int32_t& aOutStatus) {
+  uint32_t osVer = 0;
+  nsresult rv =
+      Preferences::GetUint(FeatureCacheOsVerPrefName(aFeature).get(), &osVer);
+  if (NS_FAILED(rv) || osVer != aExpectedOsVer) {
+    return false;
+  }
+  int32_t status = 0;
+  rv = Preferences::GetInt(FeatureCacheValuePrefName(aFeature).get(), &status);
+  if (NS_FAILED(rv)) {
+    return false;
+  }
+  aOutStatus = status;
+  return true;
+}
+
+static void SetCachedFeatureVal(int32_t aFeature, uint32_t aOsVer,
+                                int32_t aStatus) {
+  // Ignore failures; not much we can do anyway.
+  Preferences::SetUint(FeatureCacheOsVerPrefName(aFeature).get(), aOsVer);
+  Preferences::SetInt(FeatureCacheValuePrefName(aFeature).get(), aStatus);
+}
+
+int32_t GfxInfo::WebRtcHwEncodeSupported() {
+  MOZ_ASSERT(mozilla::AndroidBridge::Bridge());
+
+  // The Android side of this caclulation is very slow, so we cache the result
+  // in preferences, invalidating if the OS version changes.
+
+  int32_t status = 0;
+  if (GetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_ENCODE,
+                          mOSVersionInteger, status)) {
+    return status;
+  }
+
+  status = mozilla::AndroidBridge::Bridge()->GetHWEncoderCapability()
+               ? nsIGfxInfo::FEATURE_STATUS_OK
+               : nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
+
+  SetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_ENCODE, mOSVersionInteger,
+                      status);
+
+  return status;
+}
+
+int32_t GfxInfo::WebRtcHwDecodeSupported() {
+  MOZ_ASSERT(mozilla::AndroidBridge::Bridge());
+
+  // The Android side of this caclulation is very slow, so we cache the result
+  // in preferences, invalidating if the OS version changes.
+
+  int32_t status = 0;
+  if (GetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_DECODE,
+                          mOSVersionInteger, status)) {
+    return status;
+  }
+
+  status = mozilla::AndroidBridge::Bridge()->GetHWDecoderCapability()
+               ? nsIGfxInfo::FEATURE_STATUS_OK
+               : nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
+
+  SetCachedFeatureVal(FEATURE_WEBRTC_HW_ACCELERATION_DECODE, mOSVersionInteger,
+                      status);
+
+  return status;
+}
 #ifdef DEBUG
 
 // Implement nsIGfxInfoDebug
 
 NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString& aVendorID) {
   mGLStrings->SpoofVendor(NS_LossyConvertUTF16toASCII(aVendorID));
   return NS_OK;
 }
--- a/widget/android/GfxInfo.h
+++ b/widget/android/GfxInfo.h
@@ -72,16 +72,18 @@ class GfxInfo : public GfxInfoBase {
   virtual nsresult GetFeatureStatusImpl(
       int32_t aFeature, int32_t* aStatus, nsAString& aSuggestedDriverVersion,
       const nsTArray<GfxDriverInfo>& aDriverInfo, nsACString& aFailureId,
       OperatingSystem* aOS = nullptr) override;
   virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo() override;
 
  private:
   void AddCrashReportAnnotations();
+  int32_t WebRtcHwEncodeSupported();
+  int32_t WebRtcHwDecodeSupported();
 
   bool mInitialized;
 
   class GLStrings;
   UniquePtr<GLStrings> mGLStrings;
 
   nsCString mAdapterDescription;