зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1766044 - Move CycleCollectorStats from nsJSEnvironment.cpp to its own file r=mccr8
Differential Revision: https://phabricator.services.mozilla.com/D212048
This commit is contained in:
Родитель
f3b37b8e52
Коммит
6c65226d5d
|
@ -54,6 +54,7 @@
|
|||
#include "nsGlobalWindowOuter.h"
|
||||
#include "mozilla/AutoRestore.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/CycleCollectorStats.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/SchedulerGroup.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
|
@ -109,75 +110,17 @@ static bool sShuttingDown;
|
|||
static CCGCScheduler* sScheduler = nullptr;
|
||||
static std::aligned_storage_t<sizeof(*sScheduler)> sSchedulerStorage;
|
||||
|
||||
struct CycleCollectorStats {
|
||||
constexpr CycleCollectorStats() = default;
|
||||
void Init();
|
||||
void Clear();
|
||||
void PrepareForCycleCollection(TimeStamp aNow);
|
||||
void AfterPrepareForCycleCollectionSlice(TimeStamp aDeadline,
|
||||
TimeStamp aBeginTime,
|
||||
TimeStamp aMaybeAfterGCTime);
|
||||
void AfterCycleCollectionSlice();
|
||||
void AfterSyncForgetSkippable(TimeStamp beginTime);
|
||||
void AfterForgetSkippable(TimeDuration duration, uint32_t aRemovedPurples);
|
||||
void AfterCycleCollection();
|
||||
struct MainThreadCycleCollectorStats : CycleCollectorStats {
|
||||
constexpr MainThreadCycleCollectorStats() = default;
|
||||
|
||||
void SendTelemetry(TimeDuration aCCNowDuration, TimeStamp aPrevCCEnd) const;
|
||||
void MaybeLogStats(const CycleCollectorResults& aResults,
|
||||
uint32_t aCleanups) const;
|
||||
void MaybeNotifyStats(const CycleCollectorResults& aResults,
|
||||
TimeDuration aCCNowDuration, uint32_t aCleanups) const;
|
||||
|
||||
// Time the current slice began, including any GC finishing.
|
||||
TimeStamp mBeginSliceTime;
|
||||
|
||||
// Time the previous slice of the current CC ended.
|
||||
TimeStamp mEndSliceTime;
|
||||
|
||||
// Time the current cycle collection began.
|
||||
TimeStamp mBeginTime;
|
||||
|
||||
// The longest GC finishing duration for any slice of the current CC.
|
||||
TimeDuration mMaxGCDuration;
|
||||
|
||||
// True if we ran sync forget skippable in any slice of the current CC.
|
||||
bool mRanSyncForgetSkippable = false;
|
||||
|
||||
// Number of suspected objects at the start of the current CC.
|
||||
uint32_t mSuspected = 0;
|
||||
|
||||
// The longest duration spent on sync forget skippable in any slice of the
|
||||
// current CC.
|
||||
TimeDuration mMaxSkippableDuration;
|
||||
|
||||
// The longest pause of any slice in the current CC.
|
||||
TimeDuration mMaxSliceTime;
|
||||
|
||||
// The longest slice time since ClearMaxCCSliceTime() was called.
|
||||
TimeDuration mMaxSliceTimeSinceClear;
|
||||
|
||||
// The total amount of time spent actually running the current CC.
|
||||
TimeDuration mTotalSliceTime;
|
||||
|
||||
// True if we were locked out by the GC in any slice of the current CC.
|
||||
bool mAnyLockedOut = false;
|
||||
|
||||
// A file to dump CC activity to; set by MOZ_CCTIMER environment variable.
|
||||
FILE* mFile = nullptr;
|
||||
|
||||
// In case CC slice was triggered during idle time, set to the end of the idle
|
||||
// period.
|
||||
TimeStamp mIdleDeadline;
|
||||
|
||||
TimeDuration mMinForgetSkippableTime;
|
||||
TimeDuration mMaxForgetSkippableTime;
|
||||
TimeDuration mTotalForgetSkippableTime;
|
||||
uint32_t mForgetSkippableBeforeCC = 0;
|
||||
|
||||
uint32_t mRemovedPurples = 0;
|
||||
mozilla::TimeDuration aCCNowDuration,
|
||||
uint32_t aCleanups) const;
|
||||
};
|
||||
|
||||
static CycleCollectorStats sCCStats;
|
||||
static MainThreadCycleCollectorStats sCCStats;
|
||||
|
||||
static const char* ProcessNameForCollectorLog() {
|
||||
return XRE_GetProcessType() == GeckoProcessType_Default ? "default"
|
||||
|
@ -1109,33 +1052,6 @@ static void FinishAnyIncrementalGC() {
|
|||
}
|
||||
}
|
||||
|
||||
namespace geckoprofiler::markers {
|
||||
class CCSliceMarker : public BaseMarkerType<CCSliceMarker> {
|
||||
public:
|
||||
static constexpr const char* Name = "CCSlice";
|
||||
static constexpr const char* Description =
|
||||
"Information for an individual CC slice.";
|
||||
|
||||
using MS = MarkerSchema;
|
||||
static constexpr MS::PayloadField PayloadFields[] = {
|
||||
{"idle", MS::InputType::Boolean, "Idle", MS::Format::Integer}};
|
||||
|
||||
static constexpr MS::Location Locations[] = {MS::Location::MarkerChart,
|
||||
MS::Location::MarkerTable,
|
||||
MS::Location::TimelineMemory};
|
||||
static constexpr const char* AllLabels =
|
||||
"{marker.name} (idle={marker.data.idle})";
|
||||
|
||||
static constexpr MS::ETWMarkerGroup Group = MS::ETWMarkerGroup::Memory;
|
||||
|
||||
static void StreamJSONMarkerData(
|
||||
mozilla::baseprofiler::SpliceableJSONWriter& aWriter,
|
||||
bool aIsDuringIdle) {
|
||||
StreamJSONMarkerDataImpl(aWriter, aIsDuringIdle);
|
||||
}
|
||||
};
|
||||
} // namespace geckoprofiler::markers
|
||||
|
||||
static void FireForgetSkippable(bool aRemoveChildless, TimeStamp aDeadline) {
|
||||
TimeStamp startTimeStamp = TimeStamp::Now();
|
||||
FinishAnyIncrementalGC();
|
||||
|
@ -1150,10 +1066,10 @@ static void FireForgetSkippable(bool aRemoveChildless, TimeStamp aDeadline) {
|
|||
uint32_t removedPurples = sScheduler->NoteForgetSkippableComplete(
|
||||
now, suspectedBefore, nsCycleCollector_suspectedCount());
|
||||
|
||||
bool inIdle = !aDeadline.IsNull();
|
||||
sCCStats.AfterForgetSkippable(startTimeStamp, now, removedPurples, inIdle);
|
||||
|
||||
TimeDuration duration = now - startTimeStamp;
|
||||
|
||||
sCCStats.AfterForgetSkippable(duration, removedPurples);
|
||||
|
||||
if (duration.ToSeconds()) {
|
||||
TimeDuration idleDuration;
|
||||
if (!aDeadline.IsNull()) {
|
||||
|
@ -1171,151 +1087,10 @@ static void FireForgetSkippable(bool aRemoveChildless, TimeStamp aDeadline) {
|
|||
uint32_t(idleDuration.ToSeconds() / duration.ToSeconds() * 100);
|
||||
Telemetry::Accumulate(Telemetry::FORGET_SKIPPABLE_DURING_IDLE, percent);
|
||||
}
|
||||
|
||||
PROFILER_MARKER("ForgetSkippable", GCCC,
|
||||
MarkerTiming::IntervalUntilNowFrom(startTimeStamp),
|
||||
CCSliceMarker, !aDeadline.IsNull());
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE
|
||||
static TimeDuration TimeBetween(TimeStamp aStart, TimeStamp aEnd) {
|
||||
MOZ_ASSERT(aEnd >= aStart);
|
||||
return aEnd - aStart;
|
||||
}
|
||||
|
||||
static TimeDuration TimeUntilNow(TimeStamp start) {
|
||||
if (start.IsNull()) {
|
||||
return TimeDuration();
|
||||
}
|
||||
return TimeBetween(start, TimeStamp::Now());
|
||||
}
|
||||
|
||||
void CycleCollectorStats::Init() {
|
||||
Clear();
|
||||
|
||||
char* env = getenv("MOZ_CCTIMER");
|
||||
if (!env) {
|
||||
return;
|
||||
}
|
||||
if (strcmp(env, "none") == 0) {
|
||||
mFile = nullptr;
|
||||
} else if (strcmp(env, "stdout") == 0) {
|
||||
mFile = stdout;
|
||||
} else if (strcmp(env, "stderr") == 0) {
|
||||
mFile = stderr;
|
||||
} else {
|
||||
mFile = fopen(env, "a");
|
||||
if (!mFile) {
|
||||
MOZ_CRASH("Failed to open MOZ_CCTIMER log file.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CycleCollectorStats::Clear() {
|
||||
if (mFile && mFile != stdout && mFile != stderr) {
|
||||
fclose(mFile);
|
||||
}
|
||||
*this = CycleCollectorStats();
|
||||
}
|
||||
|
||||
void CycleCollectorStats::AfterCycleCollectionSlice() {
|
||||
if (mBeginSliceTime.IsNull()) {
|
||||
// We already called this method from EndCycleCollectionCallback for this
|
||||
// slice.
|
||||
return;
|
||||
}
|
||||
|
||||
mEndSliceTime = TimeStamp::Now();
|
||||
TimeDuration duration = mEndSliceTime - mBeginSliceTime;
|
||||
|
||||
PROFILER_MARKER(
|
||||
"CCSlice", GCCC, MarkerTiming::Interval(mBeginSliceTime, mEndSliceTime),
|
||||
CCSliceMarker, !mIdleDeadline.IsNull() && mIdleDeadline >= mEndSliceTime);
|
||||
|
||||
if (duration.ToSeconds()) {
|
||||
TimeDuration idleDuration;
|
||||
if (!mIdleDeadline.IsNull()) {
|
||||
if (mIdleDeadline < mEndSliceTime) {
|
||||
// This slice overflowed the idle period.
|
||||
if (mIdleDeadline > mBeginSliceTime) {
|
||||
idleDuration = mIdleDeadline - mBeginSliceTime;
|
||||
}
|
||||
} else {
|
||||
idleDuration = duration;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t percent =
|
||||
uint32_t(idleDuration.ToSeconds() / duration.ToSeconds() * 100);
|
||||
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_SLICE_DURING_IDLE,
|
||||
percent);
|
||||
}
|
||||
|
||||
TimeDuration sliceTime = TimeBetween(mBeginSliceTime, mEndSliceTime);
|
||||
mMaxSliceTime = std::max(mMaxSliceTime, sliceTime);
|
||||
mMaxSliceTimeSinceClear = std::max(mMaxSliceTimeSinceClear, sliceTime);
|
||||
mTotalSliceTime += sliceTime;
|
||||
mBeginSliceTime = TimeStamp();
|
||||
}
|
||||
|
||||
void CycleCollectorStats::PrepareForCycleCollection(TimeStamp aNow) {
|
||||
mBeginTime = aNow;
|
||||
mSuspected = nsCycleCollector_suspectedCount();
|
||||
}
|
||||
|
||||
void CycleCollectorStats::AfterPrepareForCycleCollectionSlice(
|
||||
TimeStamp aDeadline, TimeStamp aBeginTime, TimeStamp aMaybeAfterGCTime) {
|
||||
mBeginSliceTime = aBeginTime;
|
||||
mIdleDeadline = aDeadline;
|
||||
|
||||
if (!aMaybeAfterGCTime.IsNull()) {
|
||||
mAnyLockedOut = true;
|
||||
mMaxGCDuration = std::max(mMaxGCDuration, aMaybeAfterGCTime - aBeginTime);
|
||||
}
|
||||
}
|
||||
|
||||
void CycleCollectorStats::AfterSyncForgetSkippable(TimeStamp beginTime) {
|
||||
mMaxSkippableDuration =
|
||||
std::max(mMaxSkippableDuration, TimeUntilNow(beginTime));
|
||||
mRanSyncForgetSkippable = true;
|
||||
}
|
||||
|
||||
void CycleCollectorStats::AfterForgetSkippable(TimeDuration duration,
|
||||
uint32_t aRemovedPurples) {
|
||||
if (!mMinForgetSkippableTime || mMinForgetSkippableTime > duration) {
|
||||
mMinForgetSkippableTime = duration;
|
||||
}
|
||||
if (!mMaxForgetSkippableTime || mMaxForgetSkippableTime < duration) {
|
||||
mMaxForgetSkippableTime = duration;
|
||||
}
|
||||
mTotalForgetSkippableTime += duration;
|
||||
++mForgetSkippableBeforeCC;
|
||||
|
||||
mRemovedPurples += aRemovedPurples;
|
||||
}
|
||||
|
||||
void CycleCollectorStats::SendTelemetry(TimeDuration aCCNowDuration,
|
||||
TimeStamp aPrevCCEnd) const {
|
||||
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FINISH_IGC, mAnyLockedOut);
|
||||
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_SYNC_SKIPPABLE,
|
||||
mRanSyncForgetSkippable);
|
||||
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FULL,
|
||||
aCCNowDuration.ToMilliseconds());
|
||||
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_MAX_PAUSE,
|
||||
mMaxSliceTime.ToMilliseconds());
|
||||
|
||||
if (!aPrevCCEnd.IsNull()) {
|
||||
TimeDuration timeBetween = TimeBetween(aPrevCCEnd, mBeginTime);
|
||||
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_TIME_BETWEEN,
|
||||
timeBetween.ToSeconds());
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::FORGET_SKIPPABLE_MAX,
|
||||
mMaxForgetSkippableTime.ToMilliseconds());
|
||||
}
|
||||
|
||||
void CycleCollectorStats::MaybeLogStats(const CycleCollectorResults& aResults,
|
||||
uint32_t aCleanups) const {
|
||||
void MainThreadCycleCollectorStats::MaybeLogStats(
|
||||
const CycleCollectorResults& aResults, uint32_t aCleanups) const {
|
||||
if (!StaticPrefs::javascript_options_mem_log() && !sCCStats.mFile) {
|
||||
return;
|
||||
}
|
||||
|
@ -1365,7 +1140,7 @@ void CycleCollectorStats::MaybeLogStats(const CycleCollectorResults& aResults,
|
|||
}
|
||||
}
|
||||
|
||||
void CycleCollectorStats::MaybeNotifyStats(
|
||||
void MainThreadCycleCollectorStats::MaybeNotifyStats(
|
||||
const CycleCollectorResults& aResults, TimeDuration aCCNowDuration,
|
||||
uint32_t aCleanups) const {
|
||||
if (!StaticPrefs::javascript_options_mem_notify()) {
|
||||
|
@ -1544,7 +1319,8 @@ void nsJSContext::EndCycleCollectionCallback(
|
|||
sCCStats.AfterCycleCollectionSlice();
|
||||
|
||||
TimeStamp endCCTimeStamp = TimeStamp::Now();
|
||||
TimeDuration ccNowDuration = TimeBetween(sCCStats.mBeginTime, endCCTimeStamp);
|
||||
MOZ_ASSERT(endCCTimeStamp >= sCCStats.mBeginTime);
|
||||
TimeDuration ccNowDuration = endCCTimeStamp - sCCStats.mBeginTime;
|
||||
TimeStamp prevCCEnd = sScheduler->GetLastCCEndTime();
|
||||
|
||||
sScheduler->NoteCCEnd(aResults, endCCTimeStamp, sCCStats.mMaxSliceTime);
|
||||
|
@ -1861,8 +1637,10 @@ static void DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress,
|
|||
nsCycleCollector_dispatchDeferredDeletion();
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::GC_IN_PROGRESS_MS,
|
||||
TimeUntilNow(sCurrentGCStartTime).ToMilliseconds());
|
||||
MOZ_ASSERT(sCurrentGCStartTime);
|
||||
Telemetry::Accumulate(
|
||||
Telemetry::GC_IN_PROGRESS_MS,
|
||||
(TimeStamp::Now() - sCurrentGCStartTime).ToMilliseconds());
|
||||
|
||||
#if defined(MOZ_MEMORY)
|
||||
if (freeDirty &&
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
/* -*- 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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nsCycleCollector.h"
|
||||
#include "nsDebug.h"
|
||||
#include "CycleCollectorStats.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozilla/BaseProfilerMarkersPrerequisites.h"
|
||||
#include "mozilla/ProfilerMarkers.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
void mozilla::CycleCollectorStats::Init() {
|
||||
char* env = getenv("MOZ_CCTIMER");
|
||||
if (!env) {
|
||||
return;
|
||||
}
|
||||
if (strcmp(env, "none") == 0) {
|
||||
mFile = nullptr;
|
||||
} else if (strcmp(env, "stdout") == 0) {
|
||||
mFile = stdout;
|
||||
} else if (strcmp(env, "stderr") == 0) {
|
||||
mFile = stderr;
|
||||
} else {
|
||||
mFile = fopen(env, "a");
|
||||
if (!mFile) {
|
||||
NS_WARNING("Failed to open MOZ_CCTIMER log file.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mozilla::CycleCollectorStats::Clear() {
|
||||
if (mFile && mFile != stdout && mFile != stderr) {
|
||||
fclose(mFile);
|
||||
}
|
||||
*this = CycleCollectorStats();
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE
|
||||
static TimeDuration TimeBetween(TimeStamp aStart, TimeStamp aEnd) {
|
||||
MOZ_ASSERT(aEnd >= aStart);
|
||||
return aEnd - aStart;
|
||||
}
|
||||
|
||||
static TimeDuration TimeUntilNow(TimeStamp start) {
|
||||
if (start.IsNull()) {
|
||||
return TimeDuration();
|
||||
}
|
||||
return TimeBetween(start, TimeStamp::Now());
|
||||
}
|
||||
|
||||
namespace geckoprofiler::markers {
|
||||
class CCSliceMarker : public BaseMarkerType<CCSliceMarker> {
|
||||
public:
|
||||
static constexpr const char* Name = "CCSlice";
|
||||
static constexpr const char* Description =
|
||||
"Information for an individual CC slice.";
|
||||
|
||||
using MS = MarkerSchema;
|
||||
static constexpr MS::PayloadField PayloadFields[] = {
|
||||
{"idle", MS::InputType::Boolean, "Idle", MS::Format::Integer}};
|
||||
|
||||
static constexpr MS::Location Locations[] = {MS::Location::MarkerChart,
|
||||
MS::Location::MarkerTable,
|
||||
MS::Location::TimelineMemory};
|
||||
static constexpr const char* AllLabels =
|
||||
"{marker.name} (idle={marker.data.idle})";
|
||||
|
||||
static constexpr MS::ETWMarkerGroup Group = MS::ETWMarkerGroup::Memory;
|
||||
|
||||
static void StreamJSONMarkerData(
|
||||
mozilla::baseprofiler::SpliceableJSONWriter& aWriter,
|
||||
bool aIsDuringIdle) {
|
||||
StreamJSONMarkerDataImpl(aWriter, aIsDuringIdle);
|
||||
}
|
||||
};
|
||||
} // namespace geckoprofiler::markers
|
||||
|
||||
void mozilla::CycleCollectorStats::AfterCycleCollectionSlice() {
|
||||
// The meaning of the telemetry is specific to the main thread. No worker
|
||||
// should be calling this method. (And workers currently do not have
|
||||
// incremental CC, so the profiler marker is not needed either.)
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mBeginSliceTime.IsNull()) {
|
||||
// We already called this method from EndCycleCollectionCallback for this
|
||||
// slice.
|
||||
return;
|
||||
}
|
||||
|
||||
mEndSliceTime = TimeStamp::Now();
|
||||
TimeDuration duration = mEndSliceTime - mBeginSliceTime;
|
||||
|
||||
PROFILER_MARKER(
|
||||
"CCSlice", GCCC, MarkerTiming::Interval(mBeginSliceTime, mEndSliceTime),
|
||||
CCSliceMarker, !mIdleDeadline.IsNull() && mIdleDeadline >= mEndSliceTime);
|
||||
|
||||
if (duration.ToSeconds()) {
|
||||
TimeDuration idleDuration;
|
||||
if (!mIdleDeadline.IsNull()) {
|
||||
if (mIdleDeadline < mEndSliceTime) {
|
||||
// This slice overflowed the idle period.
|
||||
if (mIdleDeadline > mBeginSliceTime) {
|
||||
idleDuration = mIdleDeadline - mBeginSliceTime;
|
||||
}
|
||||
} else {
|
||||
idleDuration = duration;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t percent =
|
||||
uint32_t(idleDuration.ToSeconds() / duration.ToSeconds() * 100);
|
||||
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_SLICE_DURING_IDLE,
|
||||
percent);
|
||||
}
|
||||
|
||||
TimeDuration sliceTime = TimeBetween(mBeginSliceTime, mEndSliceTime);
|
||||
mMaxSliceTime = std::max(mMaxSliceTime, sliceTime);
|
||||
mMaxSliceTimeSinceClear = std::max(mMaxSliceTimeSinceClear, sliceTime);
|
||||
mTotalSliceTime += sliceTime;
|
||||
mBeginSliceTime = TimeStamp();
|
||||
}
|
||||
|
||||
void mozilla::CycleCollectorStats::PrepareForCycleCollection(TimeStamp aNow) {
|
||||
mBeginTime = aNow;
|
||||
mSuspected = nsCycleCollector_suspectedCount();
|
||||
}
|
||||
|
||||
void mozilla::CycleCollectorStats::AfterPrepareForCycleCollectionSlice(
|
||||
TimeStamp aDeadline, TimeStamp aBeginTime, TimeStamp aMaybeAfterGCTime) {
|
||||
mBeginSliceTime = aBeginTime;
|
||||
mIdleDeadline = aDeadline;
|
||||
|
||||
if (!aMaybeAfterGCTime.IsNull()) {
|
||||
mAnyLockedOut = true;
|
||||
mMaxGCDuration = std::max(mMaxGCDuration, aMaybeAfterGCTime - aBeginTime);
|
||||
}
|
||||
}
|
||||
|
||||
void mozilla::CycleCollectorStats::AfterSyncForgetSkippable(
|
||||
TimeStamp beginTime) {
|
||||
mMaxSkippableDuration =
|
||||
std::max(mMaxSkippableDuration, TimeUntilNow(beginTime));
|
||||
mRanSyncForgetSkippable = true;
|
||||
}
|
||||
|
||||
void mozilla::CycleCollectorStats::AfterForgetSkippable(
|
||||
mozilla::TimeStamp aStartTime, mozilla::TimeStamp aEndTime,
|
||||
uint32_t aRemovedPurples, bool aInIdle) {
|
||||
mozilla::TimeDuration duration = aEndTime - aStartTime;
|
||||
if (!mMinForgetSkippableTime || mMinForgetSkippableTime > duration) {
|
||||
mMinForgetSkippableTime = duration;
|
||||
}
|
||||
if (!mMaxForgetSkippableTime || mMaxForgetSkippableTime < duration) {
|
||||
mMaxForgetSkippableTime = duration;
|
||||
}
|
||||
mTotalForgetSkippableTime += duration;
|
||||
++mForgetSkippableBeforeCC;
|
||||
|
||||
mRemovedPurples += aRemovedPurples;
|
||||
|
||||
PROFILER_MARKER("ForgetSkippable", GCCC,
|
||||
MarkerTiming::IntervalUntilNowFrom(aStartTime), CCSliceMarker,
|
||||
aInIdle);
|
||||
}
|
||||
|
||||
void mozilla::CycleCollectorStats::SendTelemetry(TimeDuration aCCNowDuration,
|
||||
TimeStamp aPrevCCEnd) const {
|
||||
// Many of the telemetry measures would not make sense off the main thread (on
|
||||
// workers), and even for those that do, we don't want to mix mainthread and
|
||||
// other threads' measures.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FINISH_IGC, mAnyLockedOut);
|
||||
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_SYNC_SKIPPABLE,
|
||||
mRanSyncForgetSkippable);
|
||||
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FULL,
|
||||
aCCNowDuration.ToMilliseconds());
|
||||
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_MAX_PAUSE,
|
||||
mMaxSliceTime.ToMilliseconds());
|
||||
|
||||
if (!aPrevCCEnd.IsNull()) {
|
||||
TimeDuration timeBetween = TimeBetween(aPrevCCEnd, mBeginTime);
|
||||
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_TIME_BETWEEN,
|
||||
timeBetween.ToSeconds());
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::FORGET_SKIPPABLE_MAX,
|
||||
mMaxForgetSkippableTime.ToMilliseconds());
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef XPCOM_BASE_CYCLECOLLECTORSTATS_H_
|
||||
#define XPCOM_BASE_CYCLECOLLECTORSTATS_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
struct CycleCollectorStats {
|
||||
CycleCollectorStats() = default;
|
||||
void Init();
|
||||
void Clear();
|
||||
void PrepareForCycleCollection(TimeStamp aNow);
|
||||
void AfterPrepareForCycleCollectionSlice(TimeStamp aDeadline,
|
||||
TimeStamp aBeginTime,
|
||||
TimeStamp aMaybeAfterGCTime);
|
||||
void AfterCycleCollectionSlice();
|
||||
void AfterSyncForgetSkippable(TimeStamp beginTime);
|
||||
void AfterForgetSkippable(TimeStamp aStartTime, TimeStamp aEndTime,
|
||||
uint32_t aRemovedPurples, bool aInIdle);
|
||||
void AfterCycleCollection();
|
||||
|
||||
void SendTelemetry(TimeDuration aCCNowDuration, TimeStamp aPrevCCEnd) const;
|
||||
|
||||
// Time the current slice began, including any GC finishing.
|
||||
TimeStamp mBeginSliceTime;
|
||||
|
||||
// Time the previous slice of the current CC ended.
|
||||
TimeStamp mEndSliceTime;
|
||||
|
||||
// Time the current cycle collection began.
|
||||
TimeStamp mBeginTime;
|
||||
|
||||
// The longest GC finishing duration for any slice of the current CC.
|
||||
TimeDuration mMaxGCDuration;
|
||||
|
||||
// True if we ran sync forget skippable in any slice of the current CC.
|
||||
bool mRanSyncForgetSkippable = false;
|
||||
|
||||
// Number of suspected objects at the start of the current CC.
|
||||
uint32_t mSuspected = 0;
|
||||
|
||||
// The longest duration spent on sync forget skippable in any slice of the
|
||||
// current CC.
|
||||
TimeDuration mMaxSkippableDuration;
|
||||
|
||||
// The longest pause of any slice in the current CC.
|
||||
TimeDuration mMaxSliceTime;
|
||||
|
||||
// The longest slice time since ClearMaxCCSliceTime() was called.
|
||||
TimeDuration mMaxSliceTimeSinceClear;
|
||||
|
||||
// The total amount of time spent actually running the current CC.
|
||||
TimeDuration mTotalSliceTime;
|
||||
|
||||
// True if we were locked out by the GC in any slice of the current CC.
|
||||
bool mAnyLockedOut = false;
|
||||
|
||||
// A file to dump CC activity to; set by MOZ_CCTIMER environment variable.
|
||||
FILE* mFile = nullptr;
|
||||
|
||||
// In case CC slice was triggered during idle time, set to the end of the idle
|
||||
// period.
|
||||
TimeStamp mIdleDeadline;
|
||||
|
||||
TimeDuration mMinForgetSkippableTime;
|
||||
TimeDuration mMaxForgetSkippableTime;
|
||||
TimeDuration mTotalForgetSkippableTime;
|
||||
uint32_t mForgetSkippableBeforeCC = 0;
|
||||
|
||||
uint32_t mRemovedPurples = 0;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // XPCOM_BASE_CYCLECOLLECTORSTATS_H_
|
|
@ -113,6 +113,7 @@ EXPORTS.mozilla += [
|
|||
"CountingAllocatorBase.h",
|
||||
"CycleCollectedJSContext.h",
|
||||
"CycleCollectedJSRuntime.h",
|
||||
"CycleCollectorStats.h",
|
||||
"Debug.h",
|
||||
"DebuggerOnGCRunnable.h",
|
||||
"DeferredFinalize.h",
|
||||
|
@ -159,6 +160,7 @@ UNIFIED_SOURCES += [
|
|||
"ClearOnShutdown.cpp",
|
||||
"CycleCollectedJSContext.cpp",
|
||||
"CycleCollectedJSRuntime.cpp",
|
||||
"CycleCollectorStats.cpp",
|
||||
"Debug.cpp",
|
||||
"DebuggerOnGCRunnable.cpp",
|
||||
"DeferredFinalize.cpp",
|
||||
|
|
|
@ -15,6 +15,8 @@ struct already_AddRefed;
|
|||
|
||||
#include <cstdint>
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
namespace JS {
|
||||
class SliceBudget;
|
||||
|
|
Загрузка…
Ссылка в новой задаче