From 3aedcdc6498be5c7f572187424816a31f81ed25a Mon Sep 17 00:00:00 2001 From: Andrew Osmond Date: Tue, 25 Sep 2018 09:13:51 -0400 Subject: [PATCH] Bug 1492930 - Part 1. Expose composition of shared surfaces cache to allow memory reporting. r=nical This exposes methods to capture a snapshot of the SharedSurfacesParent cache for memory reporting purposes. It yields the identifiers, image properties and references to images mapped in the cache. This will be used by the compositor process to list everything it has mapped into its memory space. It will also be used by the content processes / main process to list images that specific process had mapped into the compositor process. This will allow us to easily identify what images remain in the compositor process, but are missing from the surface cache. --- gfx/layers/SourceSurfaceSharedData.h | 22 ++++- gfx/layers/ipc/CompositorManagerParent.cpp | 9 ++ gfx/layers/ipc/CompositorManagerParent.h | 1 + gfx/layers/ipc/PCompositorManager.ipdl | 2 + gfx/layers/ipc/SharedSurfacesChild.cpp | 18 +++- gfx/layers/ipc/SharedSurfacesChild.h | 11 +++ gfx/layers/ipc/SharedSurfacesMemoryReport.h | 93 +++++++++++++++++++++ gfx/layers/ipc/SharedSurfacesParent.cpp | 62 ++++++++++++-- gfx/layers/ipc/SharedSurfacesParent.h | 9 +- gfx/layers/moz.build | 1 + 10 files changed, 220 insertions(+), 8 deletions(-) create mode 100644 gfx/layers/ipc/SharedSurfacesMemoryReport.h diff --git a/gfx/layers/SourceSurfaceSharedData.h b/gfx/layers/SourceSurfaceSharedData.h index a1083837bb12..7053b8a0bc5a 100644 --- a/gfx/layers/SourceSurfaceSharedData.h +++ b/gfx/layers/SourceSurfaceSharedData.h @@ -43,6 +43,7 @@ public: , mConsumers(0) , mFormat(SurfaceFormat::UNKNOWN) , mCreatorPid(0) + , mCreatorRef(true) { } bool Init(const IntSize& aSize, @@ -79,12 +80,30 @@ public: return ++mConsumers == 1; } - bool RemoveConsumer() + bool RemoveConsumer(bool aForCreator) { MOZ_ASSERT(mConsumers > 0); + if (aForCreator) { + if (!mCreatorRef) { + MOZ_ASSERT_UNREACHABLE("Already released creator reference!"); + return false; + } + mCreatorRef = false; + } return --mConsumers == 0; } + uint32_t GetConsumers() const + { + MOZ_ASSERT(mConsumers > 0); + return mConsumers; + } + + bool HasCreatorRef() const + { + return mCreatorRef; + } + private: size_t GetDataLength() const { @@ -102,6 +121,7 @@ private: RefPtr mBuf; SurfaceFormat mFormat; base::ProcessId mCreatorPid; + bool mCreatorRef; }; /** diff --git a/gfx/layers/ipc/CompositorManagerParent.cpp b/gfx/layers/ipc/CompositorManagerParent.cpp index c7834cbceeb4..bc93e6b47479 100644 --- a/gfx/layers/ipc/CompositorManagerParent.cpp +++ b/gfx/layers/ipc/CompositorManagerParent.cpp @@ -289,6 +289,15 @@ CompositorManagerParent::RecvRemoveSharedSurface(const wr::ExternalImageId& aId) return IPC_OK(); } +mozilla::ipc::IPCResult +CompositorManagerParent::RecvReportSharedSurfacesMemory(ReportSharedSurfacesMemoryResolver&& aResolver) +{ + SharedSurfacesMemoryReport report; + SharedSurfacesParent::AccumulateMemoryReport(OtherPid(), report); + aResolver(std::move(report)); + return IPC_OK(); +} + mozilla::ipc::IPCResult CompositorManagerParent::RecvNotifyMemoryPressure() { diff --git a/gfx/layers/ipc/CompositorManagerParent.h b/gfx/layers/ipc/CompositorManagerParent.h index 2b7c7345d017..930440aee85b 100644 --- a/gfx/layers/ipc/CompositorManagerParent.h +++ b/gfx/layers/ipc/CompositorManagerParent.h @@ -43,6 +43,7 @@ public: mozilla::ipc::IPCResult RecvAddSharedSurface(const wr::ExternalImageId& aId, const SurfaceDescriptorShared& aDesc) override; mozilla::ipc::IPCResult RecvRemoveSharedSurface(const wr::ExternalImageId& aId) override; + mozilla::ipc::IPCResult RecvReportSharedSurfacesMemory(ReportSharedSurfacesMemoryResolver&&) override; virtual mozilla::ipc::IPCResult RecvNotifyMemoryPressure() override; diff --git a/gfx/layers/ipc/PCompositorManager.ipdl b/gfx/layers/ipc/PCompositorManager.ipdl index 16e56e2f5f7d..490906c839c0 100644 --- a/gfx/layers/ipc/PCompositorManager.ipdl +++ b/gfx/layers/ipc/PCompositorManager.ipdl @@ -18,6 +18,7 @@ using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasi using mozilla::layers::CompositorOptions from "mozilla/layers/CompositorOptions.h"; using mozilla::wr::ExternalImageId from "mozilla/webrender/WebRenderTypes.h"; using mozilla::wr::MemoryReport from "mozilla/webrender/WebRenderTypes.h"; +using mozilla::layers::SharedSurfacesMemoryReport from "mozilla/layers/SharedSurfacesMemoryReport.h"; namespace mozilla { namespace layers { @@ -76,6 +77,7 @@ parent: async AddSharedSurface(ExternalImageId aId, SurfaceDescriptorShared aDesc); async RemoveSharedSurface(ExternalImageId aId); + async ReportSharedSurfacesMemory() returns (SharedSurfacesMemoryReport aReport); async NotifyMemoryPressure(); diff --git a/gfx/layers/ipc/SharedSurfacesChild.cpp b/gfx/layers/ipc/SharedSurfacesChild.cpp index 78ab4aa2638c..26f4548711e8 100644 --- a/gfx/layers/ipc/SharedSurfacesChild.cpp +++ b/gfx/layers/ipc/SharedSurfacesChild.cpp @@ -19,6 +19,8 @@ namespace layers { using namespace mozilla::gfx; +/* static */ UserDataKey SharedSurfacesChild::sSharedKey; + class SharedSurfacesChild::ImageKeyData final { public: @@ -224,7 +226,6 @@ SharedSurfacesChild::ShareInternal(SourceSurfaceSharedData* aSurface, return NS_ERROR_NOT_INITIALIZED; } - static UserDataKey sSharedKey; SharedUserData* data = static_cast(aSurface->GetUserData(&sSharedKey)); if (!data) { @@ -455,5 +456,20 @@ SharedSurfacesChild::Unshare(const wr::ExternalImageId& aId, } } +/* static */ Maybe +SharedSurfacesChild::GetExternalId(const SourceSurfaceSharedData* aSurface) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aSurface); + + SharedUserData* data = + static_cast(aSurface->GetUserData(&sSharedKey)); + if (!data || !data->IsShared()) { + return Nothing(); + } + + return Some(data->Id()); +} + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/ipc/SharedSurfacesChild.h b/gfx/layers/ipc/SharedSurfacesChild.h index 1706505080e8..df0892b008cf 100644 --- a/gfx/layers/ipc/SharedSurfacesChild.h +++ b/gfx/layers/ipc/SharedSurfacesChild.h @@ -10,8 +10,10 @@ #include // for size_t #include // for uint32_t, uint64_t #include "mozilla/Attributes.h" // for override +#include "mozilla/Maybe.h" // for Maybe #include "mozilla/RefPtr.h" // for already_AddRefed #include "mozilla/StaticPtr.h" // for StaticRefPtr +#include "mozilla/gfx/UserData.h" // for UserDataKey #include "mozilla/webrender/WebRenderTypes.h" // for wr::ImageKey namespace mozilla { @@ -71,6 +73,13 @@ public: wr::IpcResourceUpdateQueue& aResources, wr::ImageKey& aKey); + /** + * Get the external ID, if any, bound to the shared surface. Used for memory + * reporting purposes. + */ + static Maybe + GetExternalId(const gfx::SourceSurfaceSharedData* aSurface); + private: SharedSurfacesChild() = delete; ~SharedSurfacesChild() = delete; @@ -83,6 +92,8 @@ private: static void Unshare(const wr::ExternalImageId& aId, nsTArray& aKeys); static void DestroySharedUserData(void* aClosure); + + static gfx::UserDataKey sSharedKey; }; } // namespace layers diff --git a/gfx/layers/ipc/SharedSurfacesMemoryReport.h b/gfx/layers/ipc/SharedSurfacesMemoryReport.h new file mode 100644 index 000000000000..b105a162e20f --- /dev/null +++ b/gfx/layers/ipc/SharedSurfacesMemoryReport.h @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +#ifndef MOZILLA_GFX_SHAREDSURFACESMEMORYREPORT_H +#define MOZILLA_GFX_SHAREDSURFACESMEMORYREPORT_H + +#include // for uint32_t +#include +#include "ipc/IPCMessageUtils.h" +#include "mozilla/gfx/Point.h" // for IntSize + +namespace mozilla { +namespace layers { + +class SharedSurfacesMemoryReport final +{ +public: + class SurfaceEntry final { + public: + base::ProcessId mCreatorPid; + gfx::IntSize mSize; + int32_t mStride; + uint32_t mConsumers; + bool mCreatorRef; + }; + + std::unordered_map mSurfaces; +}; + +} // namespace layers +} // namespace mozilla + +namespace IPC { + +template<> +struct ParamTraits +{ + typedef mozilla::layers::SharedSurfacesMemoryReport paramType; + + static void Write(Message* aMsg, const paramType& aParam) { + WriteParam(aMsg, aParam.mSurfaces); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + return ReadParam(aMsg, aIter, &aResult->mSurfaces); + } +}; + +template<> +struct ParamTraits + : public PlainOldDataSerializer +{ +}; + +template +struct ParamTraits> +{ + typedef std::unordered_map paramType; + + static void Write(Message* aMsg, const paramType& aParam) { + WriteParam(aMsg, aParam.size()); + for (auto i = aParam.begin(); i != aParam.end(); ++i) { + WriteParam(aMsg, i->first); + WriteParam(aMsg, i->second); + } + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + size_t count; + if (!ReadParam(aMsg, aIter, &count)) { + return false; + } + for (; count > 0; --count) { + KeyType k; + DataType v; + if (!ReadParam(aMsg, aIter, &k) || + !ReadParam(aMsg, aIter, &v)) { + return false; + } + aResult->insert(std::make_pair(std::move(k), std::move(v))); + } + return true; + } +}; + +} // namespace IPC + +#endif diff --git a/gfx/layers/ipc/SharedSurfacesParent.cpp b/gfx/layers/ipc/SharedSurfacesParent.cpp index 3c9c017165f7..ed5f9e76c761 100644 --- a/gfx/layers/ipc/SharedSurfacesParent.cpp +++ b/gfx/layers/ipc/SharedSurfacesParent.cpp @@ -6,6 +6,8 @@ #include "SharedSurfacesParent.h" #include "mozilla/DebugOnly.h" +#include "mozilla/gfx/GPUProcessManager.h" +#include "mozilla/layers/SharedSurfacesMemoryReport.h" #include "mozilla/layers/SourceSurfaceSharedData.h" #include "mozilla/layers/CompositorThread.h" #include "mozilla/webrender/RenderSharedSurfaceTextureHost.h" @@ -85,7 +87,7 @@ SharedSurfacesParent::Acquire(const wr::ExternalImageId& aId) } /* static */ bool -SharedSurfacesParent::Release(const wr::ExternalImageId& aId) +SharedSurfacesParent::Release(const wr::ExternalImageId& aId, bool aForCreator) { StaticMutexAutoLock lock(sMutex); if (!sInstance) { @@ -99,7 +101,7 @@ SharedSurfacesParent::Release(const wr::ExternalImageId& aId) return false; } - if (surface->RemoveConsumer()) { + if (surface->RemoveConsumer(aForCreator)) { wr::RenderThread::Get()->UnregisterExternalImage(id); sInstance->mSurfaces.Remove(id); } @@ -143,7 +145,7 @@ SharedSurfacesParent::RemoveSameProcess(const wr::ExternalImageId& aId) { MOZ_ASSERT(XRE_IsParentProcess()); MOZ_ASSERT(NS_IsMainThread()); - Release(aId); + Release(aId, /* aForCreator */ true); } /* static */ void @@ -158,7 +160,9 @@ SharedSurfacesParent::DestroyProcess(base::ProcessId aPid) // lot of surfaces still bound that require unmapping. for (auto i = sInstance->mSurfaces.Iter(); !i.Done(); i.Next()) { SourceSurfaceSharedDataWrapper* surface = i.Data(); - if (surface->GetCreatorPid() == aPid && surface->RemoveConsumer()) { + if (surface->GetCreatorPid() == aPid && + surface->HasCreatorRef() && + surface->RemoveConsumer(/* aForCreator */ true)) { wr::RenderThread::Get()->UnregisterExternalImage(i.Key()); i.Remove(); } @@ -200,9 +204,57 @@ SharedSurfacesParent::Add(const wr::ExternalImageId& aId, /* static */ void SharedSurfacesParent::Remove(const wr::ExternalImageId& aId) { - DebugOnly rv = Release(aId); + DebugOnly rv = Release(aId, /* aForCreator */ true); MOZ_ASSERT(rv); } +/* static */ void +SharedSurfacesParent::AccumulateMemoryReport(base::ProcessId aPid, + SharedSurfacesMemoryReport& aReport) +{ + StaticMutexAutoLock lock(sMutex); + if (!sInstance) { + return; + } + + for (auto i = sInstance->mSurfaces.ConstIter(); !i.Done(); i.Next()) { + SourceSurfaceSharedDataWrapper* surface = i.Data(); + if (surface->GetCreatorPid() == aPid) { + aReport.mSurfaces.insert(std::make_pair(i.Key(), + SharedSurfacesMemoryReport::SurfaceEntry { + aPid, surface->GetSize(), surface->Stride(), + surface->GetConsumers(), surface->HasCreatorRef() })); + } + } +} + +/* static */ bool +SharedSurfacesParent::AccumulateMemoryReport(SharedSurfacesMemoryReport& aReport) +{ + if (XRE_IsParentProcess()) { + GPUProcessManager* gpm = GPUProcessManager::Get(); + if (!gpm || gpm->GPUProcessPid() != -1) { + return false; + } + } else if (!XRE_IsGPUProcess()) { + return false; + } + + StaticMutexAutoLock lock(sMutex); + if (!sInstance) { + return true; + } + + for (auto i = sInstance->mSurfaces.ConstIter(); !i.Done(); i.Next()) { + SourceSurfaceSharedDataWrapper* surface = i.Data(); + aReport.mSurfaces.insert(std::make_pair(i.Key(), + SharedSurfacesMemoryReport::SurfaceEntry { + surface->GetCreatorPid(), surface->GetSize(), surface->Stride(), + surface->GetConsumers(), surface->HasCreatorRef() })); + } + + return true; +} + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/ipc/SharedSurfacesParent.h b/gfx/layers/ipc/SharedSurfacesParent.h index e03954307dfa..d377f0f073a8 100644 --- a/gfx/layers/ipc/SharedSurfacesParent.h +++ b/gfx/layers/ipc/SharedSurfacesParent.h @@ -29,6 +29,7 @@ class SourceSurfaceSharedDataWrapper; namespace layers { class SharedSurfacesChild; +class SharedSurfacesMemoryReport; class SharedSurfacesParent final { @@ -44,7 +45,8 @@ public: static already_AddRefed Acquire(const wr::ExternalImageId& aId); - static bool Release(const wr::ExternalImageId& aId); + static bool Release(const wr::ExternalImageId& aId, + bool aForCreator = false); static void Add(const wr::ExternalImageId& aId, const SurfaceDescriptorShared& aDesc, @@ -54,6 +56,11 @@ public: static void DestroyProcess(base::ProcessId aPid); + static void AccumulateMemoryReport(base::ProcessId aPid, + SharedSurfacesMemoryReport& aReport); + + static bool AccumulateMemoryReport(SharedSurfacesMemoryReport& aReport); + ~SharedSurfacesParent(); private: diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index 2f07ce12e601..678e94a47a75 100755 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -196,6 +196,7 @@ EXPORTS.mozilla.layers += [ 'ipc/SharedPlanarYCbCrImage.h', 'ipc/SharedRGBImage.h', 'ipc/SharedSurfacesChild.h', + 'ipc/SharedSurfacesMemoryReport.h', 'ipc/SharedSurfacesParent.h', 'ipc/SynchronousTask.h', 'ipc/TextureForwarder.h',