Bug 685516: Instead of decoding small images synchronously and large images asynchronously, always decode synchronously for some time, and post the remainder to the event loop if necessary. r=joe
authorKyle Huey <khuey@kylehuey.com>
Mon, 13 Aug 2012 11:12:15 -0700
changeset 102325 3bb125057939
parent 102324 a33215aa549c
child 102326 d3829aea9cd1
push id23279
push userkhuey@mozilla.com
push date2012-08-15 13:26 +0000
treeherdermozilla-central@a0bddf5fcb91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjoe
bugs685516
milestone17.0a1
Bug 685516: Instead of decoding small images synchronously and large images asynchronously, always decode synchronously for some time, and post the remainder to the event loop if necessary. r=joe
content/base/src/nsNodeUtils.cpp
image/src/RasterImage.cpp
image/src/RasterImage.h
modules/libpref/src/init/all.js
--- a/content/base/src/nsNodeUtils.cpp
+++ b/content/base/src/nsNodeUtils.cpp
@@ -23,17 +23,16 @@
 #ifdef MOZ_XUL
 #include "nsXULElement.h"
 #endif
 #include "nsBindingManager.h"
 #include "nsGenericHTMLElement.h"
 #ifdef MOZ_MEDIA
 #include "nsHTMLMediaElement.h"
 #endif // MOZ_MEDIA
-#include "nsImageLoadingContent.h"
 #include "jsgc.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsObjectLoadingContent.h"
 #include "nsDOMMutationObserver.h"
 
 using namespace mozilla::dom;
 
 // This macro expects the ownerDocument of content_ to be in scope as
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -50,27 +50,24 @@ static PRLogModuleInfo *gCompressedImage
 #endif
 
 // Tweakable progressive decoding parameters.  These are initialized to 0 here
 // because otherwise, we have to initialize them in a static initializer, which
 // makes us slower to start up.
 static bool gInitializedPrefCaches = false;
 static PRUint32 gDecodeBytesAtATime = 0;
 static PRUint32 gMaxMSBeforeYield = 0;
-static PRUint32 gMaxBytesForSyncDecode = 0;
 
 static void
 InitPrefCaches()
 {
   Preferences::AddUintVarCache(&gDecodeBytesAtATime,
                                "image.mem.decode_bytes_at_a_time", 200000);
   Preferences::AddUintVarCache(&gMaxMSBeforeYield,
                                "image.mem.max_ms_before_yield", 400);
-  Preferences::AddUintVarCache(&gMaxBytesForSyncDecode,
-                               "image.mem.max_bytes_for_sync_decode", 150000);
   gInitializedPrefCaches = true;
 }
 
 /* We define our own error checking macros here for 2 reasons:
  *
  * 1) Most of the failures we encounter here will (hopefully) be
  * the result of decoding failures (ie, bad data) and not code
  * failures. As such, we don't want to clutter up debug consoles
@@ -2457,19 +2454,23 @@ RasterImage::RequestDecode()
     rv = InitDecoder(/* aDoSizeDecode = */ false);
     CONTAINER_ENSURE_SUCCESS(rv);
   }
 
   // If we've read all the data we have, we're done
   if (mBytesDecoded == mSourceData.Length())
     return NS_OK;
 
-  // If it's a smallish image, it's not worth it to do things async
-  if (!mDecoded && !mInDecoder && mHasSourceData && (mSourceData.Length() < gMaxBytesForSyncDecode))
-    return SyncDecode();
+  // If we can do decoding now, do so.  Small images will decode completely,
+  // large images will decode a bit and post themselves to the event loop
+  // to finish decoding.
+  if (!mDecoded && !mInDecoder && mHasSourceData) {
+    DecodeWorker::Singleton()->DecodeABitOf(this);
+    return NS_OK;
+  }
 
   // If we get this far, dispatch the worker. We do this instead of starting
   // any immediate decoding to guarantee that all our decode notifications are
   // dispatched asynchronously, and to ensure we stay responsive.
   DecodeWorker::Singleton()->RequestDecode(this);
 
   return NS_OK;
 }
@@ -2892,16 +2893,35 @@ RasterImage::DecodeWorker::AddDecodeRequ
 void
 RasterImage::DecodeWorker::RequestDecode(RasterImage* aImg)
 {
   AddDecodeRequest(&aImg->mDecodeRequest);
   EnsurePendingInEventLoop();
 }
 
 void
+RasterImage::DecodeWorker::DecodeABitOf(RasterImage* aImg)
+{
+  TimeStamp eventStart = TimeStamp::Now();
+
+  do {
+    DecodeSomeOfImage(aImg);
+
+    // If we aren't yet finished decoding and we have more data in hand, add
+    // this request to the back of the priority list.
+    if (aImg->mDecoder &&
+        !aImg->mError &&
+        !aImg->IsDecodeFinished() &&
+        aImg->mSourceData.Length() > aImg->mBytesDecoded) {
+      RequestDecode(aImg);
+    }
+  } while ((TimeStamp::Now() - eventStart).ToMilliseconds() <= gMaxMSBeforeYield);
+}
+
+void
 RasterImage::DecodeWorker::EnsurePendingInEventLoop()
 {
   if (!mPendingInEventLoop) {
     mPendingInEventLoop = true;
     NS_DispatchToCurrentThread(this);
   }
 }
 
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -390,16 +390,22 @@ private:
     static DecodeWorker* Singleton();
 
     /**
      * Ask the DecodeWorker to asynchronously decode this image.
      */
     void RequestDecode(RasterImage* aImg);
 
     /**
+     * Decode aImg for a short amount of time, and post the remainder to the
+     * queue.
+     */
+    void DecodeABitOf(RasterImage* aImg);
+
+    /**
      * Give this image ASAP priority; it will be decoded before all non-ASAP
      * images.  You can call MarkAsASAP before or after you call RequestDecode
      * for the image, but if you MarkAsASAP before you call RequestDecode, you
      * still need to call RequestDecode.
      *
      * StopDecoding() resets the image's ASAP flag.
      */
     void MarkAsASAP(RasterImage* aImg);
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3504,19 +3504,16 @@ pref("image.mem.decodeondraw", true);
 pref("image.mem.min_discard_timeout_ms", 10000);
 
 // Chunk size for calls to the image decoders
 pref("image.mem.decode_bytes_at_a_time", 4096);
 
 // The longest time we can spend in an iteration of an async decode
 pref("image.mem.max_ms_before_yield", 5);
 
-// The maximum source data size for which we auto sync decode
-pref("image.mem.max_bytes_for_sync_decode", 150000);
-
 // The maximum amount of decoded image data we'll willingly keep around (we
 // might keep around more than this, but we'll try to get down to this value).
 pref("image.mem.max_decoded_image_kb", 51200);
 
 // WebGL prefs
 pref("webgl.force-enabled", false);
 pref("webgl.disabled", false);
 pref("webgl.shader_validator", true);