Bug 1180931 (Part 1) - Allow sync size decoding for single core devices. r=tn
authorSeth Fowler <mark.seth.fowler@gmail.com>
Wed, 08 Jul 2015 15:52:51 -0700
changeset 251975 6454f52da8b34327e500dae2a4e630b40324e83b
parent 251974 6e49d0bf08194956d48217e7dfe01131574b88cd
child 251976 7a8c177d73bd7022007584a1056a41d398333c61
push id29020
push usercbook@mozilla.com
push dateThu, 09 Jul 2015 15:56:37 +0000
treeherdermozilla-central@d656ef3c4936 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn
bugs1180931
milestone42.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 1180931 (Part 1) - Allow sync size decoding for single core devices. r=tn
image/DecodePool.cpp
image/DecodePool.h
image/RasterImage.cpp
--- a/image/DecodePool.cpp
+++ b/image/DecodePool.cpp
@@ -124,16 +124,17 @@ public:
 #endif // MOZ_NUWA_PROCESS
 
 
 ///////////////////////////////////////////////////////////////////////////////
 // DecodePool implementation.
 ///////////////////////////////////////////////////////////////////////////////
 
 /* static */ StaticRefPtr<DecodePool> DecodePool::sSingleton;
+/* static */ uint32_t DecodePool::sNumCores = 0;
 
 NS_IMPL_ISUPPORTS(DecodePool, nsIObserver)
 
 struct Work
 {
   enum class Type {
     DECODE,
     SHUTDOWN
@@ -296,40 +297,47 @@ public:
 private:
   nsRefPtr<DecodePoolImpl> mImpl;
 };
 
 /* static */ void
 DecodePool::Initialize()
 {
   MOZ_ASSERT(NS_IsMainThread());
+  sNumCores = PR_GetNumberOfProcessors();
   DecodePool::Singleton();
 }
 
 /* static */ DecodePool*
 DecodePool::Singleton()
 {
   if (!sSingleton) {
     MOZ_ASSERT(NS_IsMainThread());
     sSingleton = new DecodePool();
     ClearOnShutdown(&sSingleton);
   }
 
   return sSingleton;
 }
 
+/* static */ uint32_t
+DecodePool::NumberOfCores()
+{
+  return sNumCores;
+}
+
 DecodePool::DecodePool()
   : mImpl(new DecodePoolImpl)
   , mMutex("image::DecodePool")
 {
   // Determine the number of threads we want.
   int32_t prefLimit = gfxPrefs::ImageMTDecodingLimit();
   uint32_t limit;
   if (prefLimit <= 0) {
-    int32_t numCores = PR_GetNumberOfProcessors();
+    int32_t numCores = NumberOfCores();
     if (numCores <= 1) {
       limit = 1;
     } else if (numCores == 2) {
       // On an otherwise mostly idle system, having two image decoding threads
       // doubles decoding performance, so it's worth doing on dual-core devices,
       // even if under load we can't actually get that level of parallelism.
       limit = 2;
     } else {
--- a/image/DecodePool.h
+++ b/image/DecodePool.h
@@ -44,16 +44,20 @@ public:
   NS_DECL_NSIOBSERVER
 
   /// Initializes the singleton instance. Should be called from the main thread.
   static void Initialize();
 
   /// Returns the singleton instance.
   static DecodePool* Singleton();
 
+  /// @return the number of processor cores we have available. This is not the
+  /// same as the number of decoding threads we're actually using.
+  static uint32_t NumberOfCores();
+
   /// Ask the DecodePool to run @aDecoder asynchronously and return immediately.
   void AsyncDecode(Decoder* aDecoder);
 
   /**
    * Run @aDecoder synchronously if the image it's decoding is small. If the
    * image is too large, or if the source data isn't complete yet, run @aDecoder
    * asynchronously instead.
    */
@@ -81,16 +85,17 @@ private:
   DecodePool();
   virtual ~DecodePool();
 
   void Decode(Decoder* aDecoder);
   void NotifyDecodeComplete(Decoder* aDecoder);
   void NotifyProgress(Decoder* aDecoder);
 
   static StaticRefPtr<DecodePool> sSingleton;
+  static uint32_t sNumCores;
 
   nsRefPtr<DecodePoolImpl>    mImpl;
 
   // mMutex protects mThreads and mIOThread.
   Mutex                     mMutex;
   nsCOMArray<nsIThread>     mThreads;
   nsCOMPtr<nsIThread>       mIOThread;
 };
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -1191,17 +1191,22 @@ RasterImage::OnImageDataComplete(nsIRequ
   MOZ_ASSERT(NS_IsMainThread());
 
   // Record that we have all the data we're going to get now.
   mHasSourceData = true;
 
   // Let decoders know that there won't be any more data coming.
   mSourceBuffer->Complete(aStatus);
 
-  if (mSyncLoad && !mHasSize) {
+  // Do a synchronous size decode if mSyncLoad was set, or if we're running on a
+  // single thread (in which case waiting for the async size decoder could delay
+  // this image's load event quite a bit).
+  bool canSyncSizeDecode = mSyncLoad || DecodePool::NumberOfCores() < 2;
+
+  if (canSyncSizeDecode && !mHasSize) {
     // We're loading this image synchronously, so it needs to be usable after
     // this call returns.  Since we haven't gotten our size yet, we need to do a
     // synchronous size decode here.
     Decode(Nothing(), FLAG_SYNC_DECODE);
   }
 
   // Determine our final status, giving precedence to Necko failure codes. We
   // check after running the size decode above in case it triggered an error.
@@ -1214,17 +1219,17 @@ RasterImage::OnImageDataComplete(nsIRequ
   if (NS_FAILED(finalStatus)) {
     DoError();
   }
 
   Progress loadProgress = LoadCompleteProgress(aLastPart, mError, finalStatus);
 
   if (!mHasSize && !mError) {
     // We don't have our size yet, so we'll fire the load event in SetSize().
-    MOZ_ASSERT(!mSyncLoad, "Firing load asynchronously but mSyncLoad is set?");
+    MOZ_ASSERT(!canSyncSizeDecode, "Firing load async but canSyncSizeDecode?");
     NotifyProgress(FLAG_ONLOAD_BLOCKED);
     mLoadProgress = Some(loadProgress);
     return finalStatus;
   }
 
   NotifyForLoadEvent(loadProgress);
 
   return finalStatus;