MemoryReportRequest.cpp (5799B)
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 "MemoryReportRequest.h" 8 9 #include "mozilla/ipc/FileDescriptor.h" 10 #include "mozilla/ipc/FileDescriptorUtils.h" 11 #include "nsMemoryReporterManager.h" 12 13 using namespace mozilla::ipc; 14 15 namespace mozilla::dom { 16 17 MemoryReportRequestHost::MemoryReportRequestHost(uint32_t aGeneration) 18 : mGeneration(aGeneration), mSuccess(false) { 19 MOZ_COUNT_CTOR(MemoryReportRequestHost); 20 mReporterManager = nsMemoryReporterManager::GetOrCreate(); 21 NS_WARNING_ASSERTION(mReporterManager, "GetOrCreate failed"); 22 } 23 24 void MemoryReportRequestHost::RecvReport(const MemoryReport& aReport) { 25 // Skip reports from older generations. We need to do this here since we 26 // could receive older reports from a subprocesses before it acknowledges 27 // a new request, and we only track one active request per process. 28 if (aReport.generation() != mGeneration) { 29 return; 30 } 31 32 if (mReporterManager) { 33 mReporterManager->HandleChildReport(mGeneration, aReport); 34 } 35 } 36 37 void MemoryReportRequestHost::Finish(uint32_t aGeneration) { 38 // Skip reports from older generations. See the comment in RecvReport. 39 if (mGeneration != aGeneration) { 40 return; 41 } 42 mSuccess = true; 43 } 44 45 MemoryReportRequestHost::~MemoryReportRequestHost() { 46 MOZ_COUNT_DTOR(MemoryReportRequestHost); 47 48 if (mReporterManager) { 49 mReporterManager->EndProcessReport(mGeneration, mSuccess); 50 mReporterManager = nullptr; 51 } 52 } 53 54 NS_IMPL_ISUPPORTS(MemoryReportRequestClient, nsIRunnable) 55 56 /* static */ void MemoryReportRequestClient::Start( 57 uint32_t aGeneration, bool aAnonymize, bool aMinimizeMemoryUsage, 58 const Maybe<FileDescriptor>& aDMDFile, const nsACString& aProcessString, 59 const ReportCallback& aReportCallback, 60 const FinishCallback& aFinishCallback) { 61 RefPtr<MemoryReportRequestClient> request = new MemoryReportRequestClient( 62 aGeneration, aAnonymize, aDMDFile, aProcessString, aReportCallback, 63 aFinishCallback); 64 65 DebugOnly<nsresult> rv; 66 if (aMinimizeMemoryUsage) { 67 nsCOMPtr<nsIMemoryReporterManager> mgr = 68 do_GetService("@mozilla.org/memory-reporter-manager;1"); 69 rv = mgr->MinimizeMemoryUsage(request); 70 // mgr will eventually call actor->Run() 71 } else { 72 rv = request->Run(); 73 } 74 75 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "actor operation failed"); 76 } 77 78 MemoryReportRequestClient::MemoryReportRequestClient( 79 uint32_t aGeneration, bool aAnonymize, 80 const Maybe<FileDescriptor>& aDMDFile, const nsACString& aProcessString, 81 const ReportCallback& aReportCallback, 82 const FinishCallback& aFinishCallback) 83 : mGeneration(aGeneration), 84 mAnonymize(aAnonymize), 85 mProcessString(aProcessString), 86 mReportCallback(aReportCallback), 87 mFinishCallback(aFinishCallback) { 88 if (aDMDFile.isSome()) { 89 mDMDFile = aDMDFile.value(); 90 } 91 } 92 93 MemoryReportRequestClient::~MemoryReportRequestClient() = default; 94 95 class HandleReportCallback final : public nsIHandleReportCallback { 96 public: 97 using ReportCallback = typename MemoryReportRequestClient::ReportCallback; 98 99 NS_DECL_ISUPPORTS 100 101 explicit HandleReportCallback(uint32_t aGeneration, 102 const nsACString& aProcess, 103 const ReportCallback& aReportCallback) 104 : mGeneration(aGeneration), 105 mProcess(aProcess), 106 mReportCallback(aReportCallback) {} 107 108 NS_IMETHOD Callback(const nsACString& aProcess, const nsACString& aPath, 109 int32_t aKind, int32_t aUnits, int64_t aAmount, 110 const nsACString& aDescription, 111 nsISupports* aUnused) override { 112 MemoryReport memreport(mProcess, nsCString(aPath), aKind, aUnits, aAmount, 113 mGeneration, nsCString(aDescription)); 114 mReportCallback(memreport); 115 return NS_OK; 116 } 117 118 private: 119 ~HandleReportCallback() = default; 120 121 uint32_t mGeneration; 122 const nsCString mProcess; 123 ReportCallback mReportCallback; 124 }; 125 126 NS_IMPL_ISUPPORTS(HandleReportCallback, nsIHandleReportCallback) 127 128 class FinishReportingCallback final : public nsIFinishReportingCallback { 129 public: 130 using FinishCallback = typename MemoryReportRequestClient::FinishCallback; 131 132 NS_DECL_ISUPPORTS 133 134 explicit FinishReportingCallback(uint32_t aGeneration, 135 const FinishCallback& aFinishCallback) 136 : mGeneration(aGeneration), mFinishCallback(aFinishCallback) {} 137 138 NS_IMETHOD Callback(nsISupports* aUnused) override { 139 mFinishCallback(mGeneration); 140 return NS_OK; 141 } 142 143 private: 144 ~FinishReportingCallback() = default; 145 146 uint32_t mGeneration; 147 FinishCallback mFinishCallback; 148 }; 149 150 NS_IMPL_ISUPPORTS(FinishReportingCallback, nsIFinishReportingCallback) 151 152 NS_IMETHODIMP MemoryReportRequestClient::Run() { 153 nsCOMPtr<nsIMemoryReporterManager> mgr = 154 do_GetService("@mozilla.org/memory-reporter-manager;1"); 155 156 // Run the reporters. The callback will turn each measurement into a 157 // MemoryReport. 158 RefPtr<HandleReportCallback> handleReport = 159 new HandleReportCallback(mGeneration, mProcessString, mReportCallback); 160 RefPtr<FinishReportingCallback> finishReporting = 161 new FinishReportingCallback(mGeneration, mFinishCallback); 162 163 nsresult rv = mgr->GetReportsForThisProcessExtended( 164 handleReport, nullptr, mAnonymize, FileDescriptorToFILE(mDMDFile, "wb"), 165 finishReporting, nullptr); 166 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), 167 "GetReportsForThisProcessExtended failed"); 168 return rv; 169 } 170 171 } // namespace mozilla::dom