ImageMemoryReporter.cpp (6259B)
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/. */ 6 7 #include "ImageMemoryReporter.h" 8 #include "Image.h" 9 #include "base/process_util.h" 10 #include "mozilla/ipc/SharedMemoryMapping.h" 11 #include "mozilla/layers/SharedSurfacesParent.h" 12 #include "mozilla/StaticPrefs_image.h" 13 #include "nsIMemoryReporter.h" 14 #include "nsISupportsImpl.h" 15 16 namespace mozilla { 17 namespace image { 18 19 ImageMemoryReporter::WebRenderReporter* ImageMemoryReporter::sWrReporter; 20 21 class ImageMemoryReporter::WebRenderReporter final : public nsIMemoryReporter { 22 public: 23 NS_DECL_ISUPPORTS 24 25 WebRenderReporter() {} 26 27 NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, 28 nsISupports* aData, bool aAnonymize) override { 29 layers::SharedSurfacesMemoryReport report; 30 layers::SharedSurfacesParent::AccumulateMemoryReport(report); 31 ReportSharedSurfaces(aHandleReport, aData, /* aIsForCompositor */ true, 32 report); 33 return NS_OK; 34 } 35 36 private: 37 virtual ~WebRenderReporter() {} 38 }; 39 40 NS_IMPL_ISUPPORTS(ImageMemoryReporter::WebRenderReporter, nsIMemoryReporter) 41 42 /* static */ 43 void ImageMemoryReporter::InitForWebRender() { 44 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsGPUProcess()); 45 if (!sWrReporter) { 46 sWrReporter = new WebRenderReporter(); 47 RegisterStrongMemoryReporter(sWrReporter); 48 } 49 } 50 51 /* static */ 52 void ImageMemoryReporter::ShutdownForWebRender() { 53 MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsGPUProcess()); 54 if (sWrReporter) { 55 UnregisterStrongMemoryReporter(sWrReporter); 56 sWrReporter = nullptr; 57 } 58 } 59 60 /* static */ 61 void ImageMemoryReporter::ReportSharedSurfaces( 62 nsIHandleReportCallback* aHandleReport, nsISupports* aData, 63 const layers::SharedSurfacesMemoryReport& aSharedSurfaces) { 64 ReportSharedSurfaces(aHandleReport, aData, 65 /* aIsForCompositor */ false, aSharedSurfaces); 66 } 67 68 /* static */ 69 void ImageMemoryReporter::ReportSharedSurfaces( 70 nsIHandleReportCallback* aHandleReport, nsISupports* aData, 71 bool aIsForCompositor, 72 const layers::SharedSurfacesMemoryReport& aSharedSurfaces) { 73 MOZ_ASSERT_IF(aIsForCompositor, XRE_IsParentProcess() || XRE_IsGPUProcess()); 74 MOZ_ASSERT_IF(!aIsForCompositor, 75 XRE_IsParentProcess() || XRE_IsContentProcess()); 76 77 for (auto i = aSharedSurfaces.mSurfaces.begin(); 78 i != aSharedSurfaces.mSurfaces.end(); ++i) { 79 ReportSharedSurface(aHandleReport, aData, aIsForCompositor, i->first, 80 i->second); 81 } 82 } 83 84 /* static */ 85 void ImageMemoryReporter::ReportSharedSurface( 86 nsIHandleReportCallback* aHandleReport, nsISupports* aData, 87 bool aIsForCompositor, uint64_t aExternalId, 88 const layers::SharedSurfacesMemoryReport::SurfaceEntry& aEntry) { 89 nsAutoCString path; 90 if (aIsForCompositor) { 91 path.AppendLiteral("gfx/webrender/images/mapped_from_owner/"); 92 } else { 93 path.AppendLiteral("gfx/webrender/images/owner_cache_missing/"); 94 } 95 96 if (aIsForCompositor) { 97 path.AppendLiteral("pid="); 98 path.AppendInt(uint32_t(aEntry.mCreatorPid)); 99 path.AppendLiteral("/"); 100 } 101 102 if (StaticPrefs::image_mem_debug_reporting()) { 103 path.AppendInt(aExternalId, 16); 104 path.AppendLiteral("/"); 105 } 106 107 path.AppendLiteral("image("); 108 path.AppendInt(aEntry.mSize.width); 109 path.AppendLiteral("x"); 110 path.AppendInt(aEntry.mSize.height); 111 path.AppendLiteral(", compositor_ref:"); 112 path.AppendInt(aEntry.mConsumers); 113 path.AppendLiteral(", creator_ref:"); 114 path.AppendInt(aEntry.mCreatorRef); 115 path.AppendLiteral(")/decoded-"); 116 117 size_t surfaceSize = mozilla::ipc::shared_memory::PageAlignedSize( 118 aEntry.mSize.height * aEntry.mStride); 119 120 // If this memory has already been reported elsewhere (e.g. as part of our 121 // explicit section in the surface cache), we don't want report it again as 122 // KIND_NONHEAP and have it counted again. The paths must be different if the 123 // kinds are different to avoid problems when diffing memory reports. 124 bool sameProcess = aEntry.mCreatorPid == base::GetCurrentProcId(); 125 int32_t kind; 126 if (aIsForCompositor && !sameProcess) { 127 path.AppendLiteral("nonheap"); 128 kind = nsIMemoryReporter::KIND_NONHEAP; 129 } else { 130 path.AppendLiteral("other"); 131 kind = nsIMemoryReporter::KIND_OTHER; 132 } 133 134 constexpr auto desc = "Decoded image data stored in shared memory."_ns; 135 aHandleReport->Callback(""_ns, path, kind, nsIMemoryReporter::UNITS_BYTES, 136 surfaceSize, desc, aData); 137 } 138 139 /* static */ 140 void ImageMemoryReporter::AppendSharedSurfacePrefix( 141 nsACString& aPathPrefix, const SurfaceMemoryCounter& aCounter, 142 layers::SharedSurfacesMemoryReport& aSharedSurfaces) { 143 uint64_t extId = aCounter.Values().ExternalId(); 144 if (extId) { 145 auto gpuEntry = aSharedSurfaces.mSurfaces.find(extId); 146 147 if (StaticPrefs::image_mem_debug_reporting()) { 148 aPathPrefix.AppendLiteral(", external_id:"); 149 aPathPrefix.AppendInt(extId, 16); 150 if (gpuEntry != aSharedSurfaces.mSurfaces.end()) { 151 aPathPrefix.AppendLiteral(", compositor_ref:"); 152 aPathPrefix.AppendInt(gpuEntry->second.mConsumers); 153 } else { 154 aPathPrefix.AppendLiteral(", compositor_ref:missing"); 155 } 156 } 157 158 if (gpuEntry != aSharedSurfaces.mSurfaces.end()) { 159 MOZ_ASSERT(gpuEntry->second.mCreatorRef); 160 aSharedSurfaces.mSurfaces.erase(gpuEntry); 161 } 162 } 163 } 164 165 /* static */ 166 void ImageMemoryReporter::TrimSharedSurfaces( 167 const ImageMemoryCounter& aCounter, 168 layers::SharedSurfacesMemoryReport& aSharedSurfaces) { 169 if (aSharedSurfaces.mSurfaces.empty()) { 170 return; 171 } 172 173 for (const SurfaceMemoryCounter& counter : aCounter.Surfaces()) { 174 uint64_t extId = counter.Values().ExternalId(); 175 if (extId) { 176 auto gpuEntry = aSharedSurfaces.mSurfaces.find(extId); 177 if (gpuEntry != aSharedSurfaces.mSurfaces.end()) { 178 MOZ_ASSERT(gpuEntry->second.mCreatorRef); 179 aSharedSurfaces.mSurfaces.erase(gpuEntry); 180 } 181 } 182 } 183 } 184 185 } // namespace image 186 } // namespace mozilla