summaryrefslogtreecommitdiffstats
path: root/xpcom/base/MemoryTelemetry.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/base/MemoryTelemetry.cpp')
-rw-r--r--xpcom/base/MemoryTelemetry.cpp114
1 files changed, 80 insertions, 34 deletions
diff --git a/xpcom/base/MemoryTelemetry.cpp b/xpcom/base/MemoryTelemetry.cpp
index d89c528049..e5013b9c73 100644
--- a/xpcom/base/MemoryTelemetry.cpp
+++ b/xpcom/base/MemoryTelemetry.cpp
@@ -42,10 +42,13 @@ using mozilla::dom::AutoJSAPI;
using mozilla::dom::ContentParent;
// Do not gather data more than once a minute (ms)
-static constexpr uint32_t kTelemetryInterval = 60 * 1000;
+static constexpr uint32_t kTelemetryIntervalMS = 60 * 1000;
-static constexpr const char* kTopicCycleCollectorBegin =
- "cycle-collector-begin";
+// Do not create a timer for telemetry this many seconds after the previous one
+// fires. This exists so that we don't respond to our own timer.
+static constexpr uint32_t kTelemetryCooldownS = 10;
+
+static constexpr const char* kTopicShutdown = "content-child-shutdown";
namespace {
@@ -101,7 +104,7 @@ void MemoryTelemetry::Init() {
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
MOZ_RELEASE_ASSERT(obs);
- obs->AddObserver(this, "content-child-shutdown", true);
+ obs->AddObserver(this, kTopicShutdown, true);
}
}
@@ -118,24 +121,66 @@ void MemoryTelemetry::Init() {
return *sInstance;
}
-nsresult MemoryTelemetry::DelayedInit() {
- if (Telemetry::CanRecordExtended()) {
- nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
- MOZ_RELEASE_ASSERT(obs);
+void MemoryTelemetry::DelayedInit() {
+ mCanRun = true;
+ Poke();
+}
- obs->AddObserver(this, kTopicCycleCollectorBegin, true);
+void MemoryTelemetry::Poke() {
+ // Don't do anything that might delay process startup
+ if (!mCanRun) {
+ return;
}
- GatherReports();
+ if (XRE_IsContentProcess() && !Telemetry::CanRecordReleaseData()) {
+ // All memory telemetry produced by content processes is release data, so if
+ // we're not recording release data then don't setup the timers on content
+ // processes.
+ return;
+ }
- return NS_OK;
+ TimeStamp now = TimeStamp::Now();
+
+ if (mLastRun && mLastRun + TimeDuration::FromSeconds(10) < now) {
+ // If we last gathered telemetry less than ten seconds ago then Poke() does
+ // nothing. This is to prevent our own timer waking us up.
+ return;
+ }
+
+ mLastPoke = now;
+ if (!mTimer) {
+ uint32_t delay = kTelemetryIntervalMS;
+ if (mLastRun) {
+ delay = uint32_t(
+ std::min(
+ TimeDuration::FromMilliseconds(kTelemetryIntervalMS),
+ std::max(TimeDuration::FromSeconds(kTelemetryCooldownS),
+ TimeDuration::FromMilliseconds(kTelemetryIntervalMS) -
+ (now - mLastRun)))
+ .ToMilliseconds());
+ }
+ RefPtr<MemoryTelemetry> self(this);
+ auto res = NS_NewTimerWithCallback(
+ [self](nsITimer* aTimer) { self->GatherReports(); }, delay,
+ nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY, "MemoryTelemetry::GatherReports");
+
+ if (res.isOk()) {
+ // Errors are ignored, if there was an error then we just don't get
+ // telemetry.
+ mTimer = res.unwrap();
+ }
+ }
}
nsresult MemoryTelemetry::Shutdown() {
+ if (mTimer) {
+ mTimer->Cancel();
+ }
+
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
MOZ_RELEASE_ASSERT(obs);
- obs->RemoveObserver(this, kTopicCycleCollectorBegin);
+ obs->RemoveObserver(this, kTopicShutdown);
return NS_OK;
}
@@ -199,6 +244,9 @@ nsresult MemoryTelemetry::GatherReports(
}
});
+ mLastRun = TimeStamp::Now();
+ mTimer = nullptr;
+
RefPtr<nsMemoryReporterManager> mgr = nsMemoryReporterManager::GetOrCreate();
MOZ_DIAGNOSTIC_ASSERT(mgr);
NS_ENSURE_TRUE(mgr, NS_ERROR_FAILURE);
@@ -385,17 +433,22 @@ void MemoryTelemetry::GatherTotalMemory() {
// Use our handle for the remote process to collect resident unique set
// size information for that process.
+ bool success = true;
for (const auto& info : infos) {
#ifdef XP_MACOSX
int64_t memory =
nsMemoryReporterManager::PhysicalFootprint(info.mHandle);
#else
- int64_t memory =
- nsMemoryReporterManager::ResidentUnique(info.mHandle);
+ int64_t memory =
+ nsMemoryReporterManager::ResidentUnique(info.mHandle);
#endif
if (memory > 0) {
childSizes.AppendElement(memory);
totalMemory += memory;
+ } else {
+ // We don't break out of the loop otherwise the cleanup code
+ // wouldn't run.
+ success = false;
}
#if defined(XP_WIN)
@@ -405,17 +458,22 @@ void MemoryTelemetry::GatherTotalMemory() {
#endif
}
+ Maybe<int64_t> mbTotal;
+ if (success) {
+ mbTotal = Some(totalMemory);
+ }
+
NS_DispatchToMainThread(NS_NewRunnableFunction(
"MemoryTelemetry::FinishGatheringTotalMemory",
- [totalMemory, childSizes = std::move(childSizes)] {
- MemoryTelemetry::Get().FinishGatheringTotalMemory(totalMemory,
+ [mbTotal, childSizes = std::move(childSizes)] {
+ MemoryTelemetry::Get().FinishGatheringTotalMemory(mbTotal,
childSizes);
}));
}));
}
nsresult MemoryTelemetry::FinishGatheringTotalMemory(
- int64_t aTotalMemory, const nsTArray<int64_t>& aChildSizes) {
+ Maybe<int64_t> aTotalMemory, const nsTArray<int64_t>& aChildSizes) {
mGatheringTotalMemory = false;
// Total memory usage can be difficult to measure both accurately and fast
@@ -424,8 +482,10 @@ nsresult MemoryTelemetry::FinishGatheringTotalMemory(
// especially on MacOS where it double-counts shared memory. For a more
// detailed explaination see:
// https://groups.google.com/a/mozilla.org/g/dev-platform/c/WGNOtjHdsdA
- HandleMemoryReport(Telemetry::MEMORY_TOTAL, nsIMemoryReporter::UNITS_BYTES,
- aTotalMemory);
+ if (aTotalMemory) {
+ HandleMemoryReport(Telemetry::MEMORY_TOTAL, nsIMemoryReporter::UNITS_BYTES,
+ aTotalMemory.value());
+ }
if (aChildSizes.Length() > 1) {
int32_t tabsCount;
@@ -502,21 +562,7 @@ nsresult MemoryTelemetry::FinishGatheringTotalMemory(
nsresult MemoryTelemetry::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) {
- if (strcmp(aTopic, kTopicCycleCollectorBegin) == 0) {
- auto now = TimeStamp::Now();
- if (!mLastPoll.IsNull() &&
- (now - mLastPoll).ToMilliseconds() < kTelemetryInterval) {
- return NS_OK;
- }
-
- mLastPoll = now;
-
- NS_DispatchToCurrentThreadQueue(
- NewRunnableMethod<std::function<void()>>(
- "MemoryTelemetry::GatherReports", this,
- &MemoryTelemetry::GatherReports, nullptr),
- EventQueuePriority::Idle);
- } else if (strcmp(aTopic, "content-child-shutdown") == 0) {
+ if (strcmp(aTopic, kTopicShutdown) == 0) {
if (nsCOMPtr<nsITelemetry> telemetry =
do_GetService("@mozilla.org/base/telemetry;1")) {
telemetry->FlushBatchedChildTelemetry();