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