Bug 1341624 - Include shared handle totals in memory reports for images. r=tnikkel
authorAndrew Osmond <aosmond@mozilla.com>
Wed, 22 Feb 2017 09:30:22 -0500
changeset 393560 2c135b467344e72465ccf64f1cd24a18ad28f15d
parent 393559 23e4839619c87a0866adb69df4b04acc2bb141d2
child 393561 178687f32be689c4767451b2bce5462c1e7f65e2
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs1341624
milestone54.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 1341624 - Include shared handle totals in memory reports for images. r=tnikkel
gfx/layers/SourceSurfaceSharedData.h
image/AnimationSurfaceProvider.cpp
image/AnimationSurfaceProvider.h
image/Decoder.cpp
image/FrameAnimator.cpp
image/ISurfaceProvider.h
image/Image.h
image/SurfaceCache.cpp
image/imgFrame.cpp
image/imgFrame.h
image/imgLoader.cpp
--- a/gfx/layers/SourceSurfaceSharedData.h
+++ b/gfx/layers/SourceSurfaceSharedData.h
@@ -99,25 +99,37 @@ public:
    *   NS_ERROR_NOT_AVAILABLE -- handle was closed, need to reallocate.
    *   NS_ERROR_FAILURE -- failed to create a handle to share.
    */
   nsresult ShareToProcess(base::ProcessId aPid,
                           SharedMemoryBasic::Handle& aHandle);
 
   /**
    * Indicates the buffer is not expected to be shared with any more processes.
-   * May release the handle if possible (see CloseHandleInternal). */
+   * May release the handle if possible (see CloseHandleInternal).
+   */
   void FinishedSharing()
   {
     MutexAutoLock lock(mMutex);
     mShared = true;
     CloseHandleInternal();
   }
 
   /**
+   * Indicates whether or not the buffer can be shared with another process
+   * without reallocating. Note that this is racy and should only be used for
+   * informational/reporting purposes.
+   */
+  bool CanShare() const
+  {
+    MutexAutoLock lock(mMutex);
+    return !mClosed;
+  }
+
+  /**
    * Allocate a new shared memory buffer so that we can get a new handle for
    * sharing to new processes. ShareToProcess must have failed with
    * NS_ERROR_NOT_AVAILABLE in order for this to be safe to call. Returns true
    * if the operation succeeds. If it fails, there is no state change.
    */
   bool ReallocHandle();
 
   /**
@@ -145,17 +157,17 @@ private:
   }
 
   /**
    * Attempt to close the handle. Only if the buffer has been both finalized
    * and we have completed sharing will it be released.
    */
   void CloseHandleInternal();
 
-  Mutex mMutex;
+  mutable Mutex mMutex;
   int32_t mStride;
   int32_t mMapCount;
   IntSize mSize;
   RefPtr<SharedMemoryBasic> mBuf;
   RefPtr<SharedMemoryBasic> mOldBuf;
   SurfaceFormat mFormat;
   bool mClosed : 1;
   bool mFinalized : 1;
--- a/image/AnimationSurfaceProvider.cpp
+++ b/image/AnimationSurfaceProvider.cpp
@@ -113,25 +113,27 @@ AnimationSurfaceProvider::LogicalSizeInB
   // once bug 1289954 is complete.
   IntSize size = GetSurfaceKey().Size();
   return 3 * size.width * size.height * sizeof(uint32_t);
 }
 
 void
 AnimationSurfaceProvider::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                                                  size_t& aHeapSizeOut,
-                                                 size_t& aNonHeapSizeOut)
+                                                 size_t& aNonHeapSizeOut,
+                                                 size_t& aSharedHandlesOut)
 {
   // Note that the surface cache lock is already held here, and then we acquire
   // mFramesMutex. For this method, this ordering is unavoidable, which means
   // that we must be careful to always use the same ordering elsewhere.
   MutexAutoLock lock(mFramesMutex);
 
   for (const RawAccessFrameRef& frame : mFrames) {
-    frame->AddSizeOfExcludingThis(aMallocSizeOf, aHeapSizeOut, aNonHeapSizeOut);
+    frame->AddSizeOfExcludingThis(aMallocSizeOf, aHeapSizeOut,
+                                  aNonHeapSizeOut, aSharedHandlesOut);
   }
 }
 
 void
 AnimationSurfaceProvider::Run()
 {
   MutexAutoLock lock(mDecodingMutex);
 
--- a/image/AnimationSurfaceProvider.h
+++ b/image/AnimationSurfaceProvider.h
@@ -42,17 +42,18 @@ public:
   // We use the ISurfaceProvider constructor of DrawableSurface to indicate that
   // our surfaces are computed lazily.
   DrawableSurface Surface() override { return DrawableSurface(WrapNotNull(this)); }
 
   bool IsFinished() const override;
   size_t LogicalSizeInBytes() const override;
   void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                               size_t& aHeapSizeOut,
-                              size_t& aNonHeapSizeOut) override;
+                              size_t& aNonHeapSizeOut,
+                              size_t& aSharedHandlesOut) override;
 
 protected:
   DrawableFrameRef DrawableRef(size_t aFrame) override;
 
   // Animation frames are always locked. This is because we only want to release
   // their memory atomically (due to the surface cache discarding them). If they
   // were unlocked, the OS could end up releasing the memory of random frames
   // from the middle of the animation, which is not worth the complexity of
--- a/image/Decoder.cpp
+++ b/image/Decoder.cpp
@@ -330,17 +330,18 @@ Decoder::AllocateFrameInternal(uint32_t 
       aFrameRect.width <= 0 || aFrameRect.height <= 0) {
     NS_WARNING("Trying to add frame with zero or negative size");
     return RawAccessFrameRef();
   }
 
   NotNull<RefPtr<imgFrame>> frame = WrapNotNull(new imgFrame());
   bool nonPremult = bool(mSurfaceFlags & SurfaceFlags::NO_PREMULTIPLY_ALPHA);
   if (NS_FAILED(frame->InitForDecoder(aOutputSize, aFrameRect, aFormat,
-                                      aPaletteDepth, nonPremult))) {
+                                      aPaletteDepth, nonPremult,
+                                      aFrameNum > 0))) {
     NS_WARNING("imgFrame::Init should succeed");
     return RawAccessFrameRef();
   }
 
   RawAccessFrameRef ref = frame->RawAccessRef();
   if (!ref) {
     frame->Abort();
     return RawAccessFrameRef();
--- a/image/FrameAnimator.cpp
+++ b/image/FrameAnimator.cpp
@@ -348,20 +348,21 @@ DoCollectSizeOfCompositingSurfaces(const
   SurfaceKey key = RasterSurfaceKey(aSurface->GetImageSize(),
                                     DefaultSurfaceFlags(),
                                     PlaybackType::eStatic);
 
   // Create a counter for this surface.
   SurfaceMemoryCounter counter(key, /* aIsLocked = */ true, aType);
 
   // Extract the surface's memory usage information.
-  size_t heap = 0, nonHeap = 0;
-  aSurface->AddSizeOfExcludingThis(aMallocSizeOf, heap, nonHeap);
+  size_t heap = 0, nonHeap = 0, handles = 0;
+  aSurface->AddSizeOfExcludingThis(aMallocSizeOf, heap, nonHeap, handles);
   counter.Values().SetDecodedHeap(heap);
   counter.Values().SetDecodedNonHeap(nonHeap);
+  counter.Values().SetSharedHandles(handles);
 
   // Record it.
   aCounters.AppendElement(counter);
 }
 
 void
 FrameAnimator::CollectSizeOfCompositingSurfaces(
     nsTArray<SurfaceMemoryCounter>& aCounters,
--- a/image/ISurfaceProvider.h
+++ b/image/ISurfaceProvider.h
@@ -59,24 +59,26 @@ public:
   /// important that it be constant over the lifetime of this object.
   virtual size_t LogicalSizeInBytes() const = 0;
 
   /// @return the actual number of bytes of memory this ISurfaceProvider is
   /// using. May vary over the lifetime of the ISurfaceProvider. The default
   /// implementation is appropriate for static ISurfaceProviders.
   virtual void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                                       size_t& aHeapSizeOut,
-                                      size_t& aNonHeapSizeOut)
+                                      size_t& aNonHeapSizeOut,
+                                      size_t& aSharedHandlesOut)
   {
     DrawableFrameRef ref = DrawableRef(/* aFrame = */ 0);
     if (!ref) {
       return;
     }
 
-    ref->AddSizeOfExcludingThis(aMallocSizeOf, aHeapSizeOut, aNonHeapSizeOut);
+    ref->AddSizeOfExcludingThis(aMallocSizeOf, aHeapSizeOut,
+                                aNonHeapSizeOut, aSharedHandlesOut);
   }
 
   /// @return the availability state of this ISurfaceProvider, which indicates
   /// whether DrawableRef() could successfully return a surface. Should only be
   /// called from SurfaceCache code as it relies on SurfaceCache for
   /// synchronization.
   AvailabilityState& Availability() { return mAvailability; }
   const AvailabilityState& Availability() const { return mAvailability; }
--- a/image/Image.h
+++ b/image/Image.h
@@ -28,37 +28,42 @@ class Image;
 ///////////////////////////////////////////////////////////////////////////////
 
 struct MemoryCounter
 {
   MemoryCounter()
     : mSource(0)
     , mDecodedHeap(0)
     , mDecodedNonHeap(0)
+    , mSharedHandles(0)
   { }
 
   void SetSource(size_t aCount) { mSource = aCount; }
   size_t Source() const { return mSource; }
   void SetDecodedHeap(size_t aCount) { mDecodedHeap = aCount; }
   size_t DecodedHeap() const { return mDecodedHeap; }
   void SetDecodedNonHeap(size_t aCount) { mDecodedNonHeap = aCount; }
   size_t DecodedNonHeap() const { return mDecodedNonHeap; }
+  void SetSharedHandles(size_t aCount) { mSharedHandles = aCount; }
+  size_t SharedHandles() const { return mSharedHandles; }
 
   MemoryCounter& operator+=(const MemoryCounter& aOther)
   {
     mSource += aOther.mSource;
     mDecodedHeap += aOther.mDecodedHeap;
     mDecodedNonHeap += aOther.mDecodedNonHeap;
+    mSharedHandles += aOther.mSharedHandles;
     return *this;
   }
 
 private:
   size_t mSource;
   size_t mDecodedHeap;
   size_t mDecodedNonHeap;
+  size_t mSharedHandles;
 };
 
 enum class SurfaceMemoryCounterType
 {
   NORMAL,
   COMPOSITING,
   COMPOSITING_PREV
 };
--- a/image/SurfaceCache.cpp
+++ b/image/SurfaceCache.cpp
@@ -192,20 +192,22 @@ public:
       }
 
       // Record the memory used by the ISurfaceProvider. This may not have a
       // straightforward relationship to the size of the surface that
       // DrawableRef() returns if the surface is generated dynamically. (i.e.,
       // for surfaces with PlaybackType::eAnimated.)
       size_t heap = 0;
       size_t nonHeap = 0;
+      size_t handles = 0;
       aCachedSurface->mProvider
-        ->AddSizeOfExcludingThis(mMallocSizeOf, heap, nonHeap);
+        ->AddSizeOfExcludingThis(mMallocSizeOf, heap, nonHeap, handles);
       counter.Values().SetDecodedHeap(heap);
       counter.Values().SetDecodedNonHeap(nonHeap);
+      counter.Values().SetSharedHandles(handles);
 
       mCounters.AppendElement(counter);
     }
 
   private:
     nsTArray<SurfaceMemoryCounter>& mCounters;
     MallocSizeOf                    mMallocSizeOf;
   };
--- a/image/imgFrame.cpp
+++ b/image/imgFrame.cpp
@@ -927,30 +927,39 @@ imgFrame::SetCompositingFailed(bool val)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mCompositingFailed = val;
 }
 
 void
 imgFrame::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                                  size_t& aHeapSizeOut,
-                                 size_t& aNonHeapSizeOut) const
+                                 size_t& aNonHeapSizeOut,
+                                 size_t& aSharedHandlesOut) const
 {
   MonitorAutoLock lock(mMonitor);
 
   if (mPalettedImageData) {
     aHeapSizeOut += aMallocSizeOf(mPalettedImageData);
   }
   if (mLockedSurface) {
     aHeapSizeOut += aMallocSizeOf(mLockedSurface);
   }
   if (mOptSurface) {
     aHeapSizeOut += aMallocSizeOf(mOptSurface);
   }
   if (mRawSurface) {
     aHeapSizeOut += aMallocSizeOf(mRawSurface);
     mRawSurface->AddSizeOfExcludingThis(aMallocSizeOf, aHeapSizeOut,
                                         aNonHeapSizeOut);
+
+    if (mRawSurface->GetType() == SurfaceType::DATA_SHARED) {
+      auto sharedSurface =
+        static_cast<SourceSurfaceSharedData*>(mRawSurface.get());
+      if (sharedSurface->CanShare()) {
+        ++aSharedHandlesOut;
+      }
+    }
   }
 }
 
 } // namespace image
 } // namespace mozilla
--- a/image/imgFrame.h
+++ b/image/imgFrame.h
@@ -343,17 +343,18 @@ public:
   void SetCompositingFailed(bool val);
 
   void SetOptimizable();
 
   void FinalizeSurface();
   already_AddRefed<SourceSurface> GetSourceSurface();
 
   void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut,
-                              size_t& aNonHeapSizeOut) const;
+                              size_t& aNonHeapSizeOut,
+                              size_t& aSharedHandlesOut) const;
 
 private: // methods
 
   ~imgFrame();
 
   nsresult LockImageData();
   nsresult UnlockImageData();
   nsresult Optimize(gfx::DrawTarget* aTarget);
--- a/image/imgLoader.cpp
+++ b/image/imgLoader.cpp
@@ -275,16 +275,21 @@ private:
     for (const SurfaceMemoryCounter& counter : aCounter.Surfaces()) {
       nsAutoCString surfacePathPrefix(aPathPrefix);
       surfacePathPrefix.Append(counter.IsLocked() ? "locked/" : "unlocked/");
       surfacePathPrefix.Append("surface(");
       surfacePathPrefix.AppendInt(counter.Key().Size().width);
       surfacePathPrefix.Append("x");
       surfacePathPrefix.AppendInt(counter.Key().Size().height);
 
+      if (counter.Values().SharedHandles() > 0) {
+        surfacePathPrefix.Append(", shared:");
+        surfacePathPrefix.AppendInt(uint32_t(counter.Values().SharedHandles()));
+      }
+
       if (counter.Type() == SurfaceMemoryCounterType::NORMAL) {
         PlaybackType playback = counter.Key().Playback();
         surfacePathPrefix.Append(playback == PlaybackType::eAnimated
                                  ? " (animation)"
                                  : "");
 
         if (counter.Key().Flags() != DefaultSurfaceFlags()) {
           surfacePathPrefix.Append(", flags:");