1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ImageMemoryReporter.h"
9 #include "base/process_util.h"
10 #include "mozilla/layers/SharedSurfacesParent.h"
11 #include "mozilla/StaticPrefs_image.h"
12 #include "nsIMemoryReporter.h"
13 #include "nsISupportsImpl.h"
18 ImageMemoryReporter::WebRenderReporter
* ImageMemoryReporter::sWrReporter
;
20 class ImageMemoryReporter::WebRenderReporter final
: public nsIMemoryReporter
{
24 WebRenderReporter() {}
26 NS_IMETHOD
CollectReports(nsIHandleReportCallback
* aHandleReport
,
27 nsISupports
* aData
, bool aAnonymize
) override
{
28 layers::SharedSurfacesMemoryReport report
;
29 layers::SharedSurfacesParent::AccumulateMemoryReport(report
);
30 ReportSharedSurfaces(aHandleReport
, aData
, /* aIsForCompositor */ true,
36 virtual ~WebRenderReporter() {}
39 NS_IMPL_ISUPPORTS(ImageMemoryReporter::WebRenderReporter
, nsIMemoryReporter
)
42 void ImageMemoryReporter::InitForWebRender() {
43 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsGPUProcess());
45 sWrReporter
= new WebRenderReporter();
46 RegisterStrongMemoryReporter(sWrReporter
);
51 void ImageMemoryReporter::ShutdownForWebRender() {
52 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsGPUProcess());
54 UnregisterStrongMemoryReporter(sWrReporter
);
55 sWrReporter
= nullptr;
60 void ImageMemoryReporter::ReportSharedSurfaces(
61 nsIHandleReportCallback
* aHandleReport
, nsISupports
* aData
,
62 const layers::SharedSurfacesMemoryReport
& aSharedSurfaces
) {
63 ReportSharedSurfaces(aHandleReport
, aData
,
64 /* aIsForCompositor */ false, aSharedSurfaces
);
68 void ImageMemoryReporter::ReportSharedSurfaces(
69 nsIHandleReportCallback
* aHandleReport
, nsISupports
* aData
,
70 bool aIsForCompositor
,
71 const layers::SharedSurfacesMemoryReport
& aSharedSurfaces
) {
72 MOZ_ASSERT_IF(aIsForCompositor
, XRE_IsParentProcess() || XRE_IsGPUProcess());
73 MOZ_ASSERT_IF(!aIsForCompositor
,
74 XRE_IsParentProcess() || XRE_IsContentProcess());
76 for (auto i
= aSharedSurfaces
.mSurfaces
.begin();
77 i
!= aSharedSurfaces
.mSurfaces
.end(); ++i
) {
78 ReportSharedSurface(aHandleReport
, aData
, aIsForCompositor
, i
->first
,
84 void ImageMemoryReporter::ReportSharedSurface(
85 nsIHandleReportCallback
* aHandleReport
, nsISupports
* aData
,
86 bool aIsForCompositor
, uint64_t aExternalId
,
87 const layers::SharedSurfacesMemoryReport::SurfaceEntry
& aEntry
) {
89 if (aIsForCompositor
) {
90 path
.AppendLiteral("gfx/webrender/images/mapped_from_owner/");
92 path
.AppendLiteral("gfx/webrender/images/owner_cache_missing/");
95 if (aIsForCompositor
) {
96 path
.AppendLiteral("pid=");
97 path
.AppendInt(uint32_t(aEntry
.mCreatorPid
));
98 path
.AppendLiteral("/");
101 if (StaticPrefs::image_mem_debug_reporting()) {
102 path
.AppendInt(aExternalId
, 16);
103 path
.AppendLiteral("/");
106 path
.AppendLiteral("image(");
107 path
.AppendInt(aEntry
.mSize
.width
);
108 path
.AppendLiteral("x");
109 path
.AppendInt(aEntry
.mSize
.height
);
110 path
.AppendLiteral(", compositor_ref:");
111 path
.AppendInt(aEntry
.mConsumers
);
112 path
.AppendLiteral(", creator_ref:");
113 path
.AppendInt(aEntry
.mCreatorRef
);
114 path
.AppendLiteral(")/decoded-");
116 size_t surfaceSize
= mozilla::ipc::SharedMemory::PageAlignedSize(
117 aEntry
.mSize
.height
* aEntry
.mStride
);
119 // If this memory has already been reported elsewhere (e.g. as part of our
120 // explicit section in the surface cache), we don't want report it again as
121 // KIND_NONHEAP and have it counted again. The paths must be different if the
122 // kinds are different to avoid problems when diffing memory reports.
123 bool sameProcess
= aEntry
.mCreatorPid
== base::GetCurrentProcId();
125 if (aIsForCompositor
&& !sameProcess
) {
126 path
.AppendLiteral("nonheap");
127 kind
= nsIMemoryReporter::KIND_NONHEAP
;
129 path
.AppendLiteral("other");
130 kind
= nsIMemoryReporter::KIND_OTHER
;
133 constexpr auto desc
= "Decoded image data stored in shared memory."_ns
;
134 aHandleReport
->Callback(""_ns
, path
, kind
, nsIMemoryReporter::UNITS_BYTES
,
135 surfaceSize
, desc
, aData
);
139 void ImageMemoryReporter::AppendSharedSurfacePrefix(
140 nsACString
& aPathPrefix
, const SurfaceMemoryCounter
& aCounter
,
141 layers::SharedSurfacesMemoryReport
& aSharedSurfaces
) {
142 uint64_t extId
= aCounter
.Values().ExternalId();
144 auto gpuEntry
= aSharedSurfaces
.mSurfaces
.find(extId
);
146 if (StaticPrefs::image_mem_debug_reporting()) {
147 aPathPrefix
.AppendLiteral(", external_id:");
148 aPathPrefix
.AppendInt(extId
, 16);
149 if (gpuEntry
!= aSharedSurfaces
.mSurfaces
.end()) {
150 aPathPrefix
.AppendLiteral(", compositor_ref:");
151 aPathPrefix
.AppendInt(gpuEntry
->second
.mConsumers
);
153 aPathPrefix
.AppendLiteral(", compositor_ref:missing");
157 if (gpuEntry
!= aSharedSurfaces
.mSurfaces
.end()) {
158 MOZ_ASSERT(gpuEntry
->second
.mCreatorRef
);
159 aSharedSurfaces
.mSurfaces
.erase(gpuEntry
);
165 void ImageMemoryReporter::TrimSharedSurfaces(
166 const ImageMemoryCounter
& aCounter
,
167 layers::SharedSurfacesMemoryReport
& aSharedSurfaces
) {
168 if (aSharedSurfaces
.mSurfaces
.empty()) {
172 for (const SurfaceMemoryCounter
& counter
: aCounter
.Surfaces()) {
173 uint64_t extId
= counter
.Values().ExternalId();
175 auto gpuEntry
= aSharedSurfaces
.mSurfaces
.find(extId
);
176 if (gpuEntry
!= aSharedSurfaces
.mSurfaces
.end()) {
177 MOZ_ASSERT(gpuEntry
->second
.mCreatorRef
);
178 aSharedSurfaces
.mSurfaces
.erase(gpuEntry
);
185 } // namespace mozilla