diff options
Diffstat (limited to '')
-rw-r--r-- | image/ImageMemoryReporter.cpp | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/image/ImageMemoryReporter.cpp b/image/ImageMemoryReporter.cpp new file mode 100644 index 0000000000..0afb890d00 --- /dev/null +++ b/image/ImageMemoryReporter.cpp @@ -0,0 +1,185 @@ +/* -*- 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/. */ + +#include "ImageMemoryReporter.h" +#include "Image.h" +#include "base/process_util.h" +#include "mozilla/layers/SharedSurfacesParent.h" +#include "mozilla/StaticPrefs_image.h" +#include "nsIMemoryReporter.h" +#include "nsISupportsImpl.h" + +namespace mozilla { +namespace image { + +ImageMemoryReporter::WebRenderReporter* ImageMemoryReporter::sWrReporter; + +class ImageMemoryReporter::WebRenderReporter final : public nsIMemoryReporter { + public: + NS_DECL_ISUPPORTS + + WebRenderReporter() {} + + NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, bool aAnonymize) override { + layers::SharedSurfacesMemoryReport report; + layers::SharedSurfacesParent::AccumulateMemoryReport(report); + ReportSharedSurfaces(aHandleReport, aData, /* aIsForCompositor */ true, + report); + return NS_OK; + } + + private: + virtual ~WebRenderReporter() {} +}; + +NS_IMPL_ISUPPORTS(ImageMemoryReporter::WebRenderReporter, nsIMemoryReporter) + +/* static */ +void ImageMemoryReporter::InitForWebRender() { + MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsGPUProcess()); + if (!sWrReporter) { + sWrReporter = new WebRenderReporter(); + RegisterStrongMemoryReporter(sWrReporter); + } +} + +/* static */ +void ImageMemoryReporter::ShutdownForWebRender() { + MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsGPUProcess()); + if (sWrReporter) { + UnregisterStrongMemoryReporter(sWrReporter); + sWrReporter = nullptr; + } +} + +/* static */ +void ImageMemoryReporter::ReportSharedSurfaces( + nsIHandleReportCallback* aHandleReport, nsISupports* aData, + const layers::SharedSurfacesMemoryReport& aSharedSurfaces) { + ReportSharedSurfaces(aHandleReport, aData, + /* aIsForCompositor */ false, aSharedSurfaces); +} + +/* static */ +void ImageMemoryReporter::ReportSharedSurfaces( + nsIHandleReportCallback* aHandleReport, nsISupports* aData, + bool aIsForCompositor, + const layers::SharedSurfacesMemoryReport& aSharedSurfaces) { + MOZ_ASSERT_IF(aIsForCompositor, XRE_IsParentProcess() || XRE_IsGPUProcess()); + MOZ_ASSERT_IF(!aIsForCompositor, + XRE_IsParentProcess() || XRE_IsContentProcess()); + + for (auto i = aSharedSurfaces.mSurfaces.begin(); + i != aSharedSurfaces.mSurfaces.end(); ++i) { + ReportSharedSurface(aHandleReport, aData, aIsForCompositor, i->first, + i->second); + } +} + +/* static */ +void ImageMemoryReporter::ReportSharedSurface( + nsIHandleReportCallback* aHandleReport, nsISupports* aData, + bool aIsForCompositor, uint64_t aExternalId, + const layers::SharedSurfacesMemoryReport::SurfaceEntry& aEntry) { + nsAutoCString path; + if (aIsForCompositor) { + path.AppendLiteral("gfx/webrender/images/mapped_from_owner/"); + } else { + path.AppendLiteral("gfx/webrender/images/owner_cache_missing/"); + } + + if (aIsForCompositor) { + path.AppendLiteral("pid="); + path.AppendInt(uint32_t(aEntry.mCreatorPid)); + path.AppendLiteral("/"); + } + + if (StaticPrefs::image_mem_debug_reporting()) { + path.AppendInt(aExternalId, 16); + path.AppendLiteral("/"); + } + + path.AppendLiteral("image("); + path.AppendInt(aEntry.mSize.width); + path.AppendLiteral("x"); + path.AppendInt(aEntry.mSize.height); + path.AppendLiteral(", compositor_ref:"); + path.AppendInt(aEntry.mConsumers); + path.AppendLiteral(", creator_ref:"); + path.AppendInt(aEntry.mCreatorRef); + path.AppendLiteral(")/decoded-"); + + size_t surfaceSize = mozilla::ipc::SharedMemory::PageAlignedSize( + aEntry.mSize.height * aEntry.mStride); + + // If this memory has already been reported elsewhere (e.g. as part of our + // explicit section in the surface cache), we don't want report it again as + // KIND_NONHEAP and have it counted again. The paths must be different if the + // kinds are different to avoid problems when diffing memory reports. + bool sameProcess = aEntry.mCreatorPid == base::GetCurrentProcId(); + int32_t kind; + if (aIsForCompositor && !sameProcess) { + path.AppendLiteral("nonheap"); + kind = nsIMemoryReporter::KIND_NONHEAP; + } else { + path.AppendLiteral("other"); + kind = nsIMemoryReporter::KIND_OTHER; + } + + constexpr auto desc = "Decoded image data stored in shared memory."_ns; + aHandleReport->Callback(""_ns, path, kind, nsIMemoryReporter::UNITS_BYTES, + surfaceSize, desc, aData); +} + +/* static */ +void ImageMemoryReporter::AppendSharedSurfacePrefix( + nsACString& aPathPrefix, const SurfaceMemoryCounter& aCounter, + layers::SharedSurfacesMemoryReport& aSharedSurfaces) { + uint64_t extId = aCounter.Values().ExternalId(); + if (extId) { + auto gpuEntry = aSharedSurfaces.mSurfaces.find(extId); + + if (StaticPrefs::image_mem_debug_reporting()) { + aPathPrefix.AppendLiteral(", external_id:"); + aPathPrefix.AppendInt(extId, 16); + if (gpuEntry != aSharedSurfaces.mSurfaces.end()) { + aPathPrefix.AppendLiteral(", compositor_ref:"); + aPathPrefix.AppendInt(gpuEntry->second.mConsumers); + } else { + aPathPrefix.AppendLiteral(", compositor_ref:missing"); + } + } + + if (gpuEntry != aSharedSurfaces.mSurfaces.end()) { + MOZ_ASSERT(gpuEntry->second.mCreatorRef); + aSharedSurfaces.mSurfaces.erase(gpuEntry); + } + } +} + +/* static */ +void ImageMemoryReporter::TrimSharedSurfaces( + const ImageMemoryCounter& aCounter, + layers::SharedSurfacesMemoryReport& aSharedSurfaces) { + if (aSharedSurfaces.mSurfaces.empty()) { + return; + } + + for (const SurfaceMemoryCounter& counter : aCounter.Surfaces()) { + uint64_t extId = counter.Values().ExternalId(); + if (extId) { + auto gpuEntry = aSharedSurfaces.mSurfaces.find(extId); + if (gpuEntry != aSharedSurfaces.mSurfaces.end()) { + MOZ_ASSERT(gpuEntry->second.mCreatorRef); + aSharedSurfaces.mSurfaces.erase(gpuEntry); + } + } + } +} + +} // namespace image +} // namespace mozilla |