Bug 1919083 - [ci] Enable os-integration variant for more suites, r=jmaher
[gecko.git] / xpcom / base / CycleCollectorStats.cpp
blobda3e8ab068272694bdd40d2e82008c1a31924852
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/. */
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
11 #include "nsCycleCollector.h"
12 #include "nsDebug.h"
13 #include "CycleCollectorStats.h"
14 #include "MainThreadUtils.h"
15 #include "mozilla/BaseProfilerMarkersPrerequisites.h"
16 #include "mozilla/ProfilerMarkers.h"
17 #include "mozilla/Telemetry.h"
18 #include "mozilla/TimeStamp.h"
20 using namespace mozilla;
22 mozilla::CycleCollectorStats::CycleCollectorStats() {
23 char* env = getenv("MOZ_CCTIMER");
24 if (!env) {
25 return;
27 if (strcmp(env, "none") == 0) {
28 mFile = nullptr;
29 } else if (strcmp(env, "stdout") == 0) {
30 mFile = stdout;
31 } else if (strcmp(env, "stderr") == 0) {
32 mFile = stderr;
33 } else {
34 mFile = fopen(env, "a");
35 if (!mFile) {
36 NS_WARNING("Failed to open MOZ_CCTIMER log file.");
41 void mozilla::CycleCollectorStats::Clear() {
42 if (mFile && mFile != stdout && mFile != stderr) {
43 fclose(mFile);
45 *this = CycleCollectorStats();
48 MOZ_ALWAYS_INLINE
49 static TimeDuration TimeBetween(TimeStamp aStart, TimeStamp aEnd) {
50 MOZ_ASSERT(aEnd >= aStart);
51 return aEnd - aStart;
54 static TimeDuration TimeUntilNow(TimeStamp start) {
55 if (start.IsNull()) {
56 return TimeDuration();
58 return TimeBetween(start, TimeStamp::Now());
61 namespace geckoprofiler::markers {
62 class CCSliceMarker : public BaseMarkerType<CCSliceMarker> {
63 public:
64 static constexpr const char* Name = "CCSlice";
65 static constexpr const char* Description =
66 "Information for an individual CC slice.";
68 using MS = MarkerSchema;
69 static constexpr MS::PayloadField PayloadFields[] = {
70 {"idle", MS::InputType::Boolean, "Idle", MS::Format::Integer}};
72 static constexpr MS::Location Locations[] = {MS::Location::MarkerChart,
73 MS::Location::MarkerTable,
74 MS::Location::TimelineMemory};
75 static constexpr const char* AllLabels =
76 "{marker.name} (idle={marker.data.idle})";
78 static constexpr MS::ETWMarkerGroup Group = MS::ETWMarkerGroup::Memory;
80 static void StreamJSONMarkerData(
81 mozilla::baseprofiler::SpliceableJSONWriter& aWriter,
82 bool aIsDuringIdle) {
83 StreamJSONMarkerDataImpl(aWriter, aIsDuringIdle);
86 } // namespace geckoprofiler::markers
88 void mozilla::CycleCollectorStats::AfterCycleCollectionSlice() {
89 // The meaning of the telemetry is specific to the main thread. No worker
90 // should be calling this method. (And workers currently do not have
91 // incremental CC, so the profiler marker is not needed either.)
92 MOZ_ASSERT(NS_IsMainThread());
94 if (mBeginSliceTime.IsNull()) {
95 // We already called this method from EndCycleCollectionCallback for this
96 // slice.
97 return;
100 mEndSliceTime = TimeStamp::Now();
101 TimeDuration duration = mEndSliceTime - mBeginSliceTime;
103 PROFILER_MARKER(
104 "CCSlice", GCCC, MarkerTiming::Interval(mBeginSliceTime, mEndSliceTime),
105 CCSliceMarker, !mIdleDeadline.IsNull() && mIdleDeadline >= mEndSliceTime);
107 if (duration.ToSeconds()) {
108 TimeDuration idleDuration;
109 if (!mIdleDeadline.IsNull()) {
110 if (mIdleDeadline < mEndSliceTime) {
111 // This slice overflowed the idle period.
112 if (mIdleDeadline > mBeginSliceTime) {
113 idleDuration = mIdleDeadline - mBeginSliceTime;
115 } else {
116 idleDuration = duration;
120 uint32_t percent =
121 uint32_t(idleDuration.ToSeconds() / duration.ToSeconds() * 100);
122 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_SLICE_DURING_IDLE,
123 percent);
126 TimeDuration sliceTime = TimeBetween(mBeginSliceTime, mEndSliceTime);
127 mMaxSliceTime = std::max(mMaxSliceTime, sliceTime);
128 mMaxSliceTimeSinceClear = std::max(mMaxSliceTimeSinceClear, sliceTime);
129 mTotalSliceTime += sliceTime;
130 mBeginSliceTime = TimeStamp();
133 void mozilla::CycleCollectorStats::PrepareForCycleCollection(TimeStamp aNow) {
134 mBeginTime = aNow;
135 mSuspected = nsCycleCollector_suspectedCount();
138 void mozilla::CycleCollectorStats::AfterPrepareForCycleCollectionSlice(
139 TimeStamp aDeadline, TimeStamp aBeginTime, TimeStamp aMaybeAfterGCTime) {
140 mBeginSliceTime = aBeginTime;
141 mIdleDeadline = aDeadline;
143 if (!aMaybeAfterGCTime.IsNull()) {
144 mAnyLockedOut = true;
145 mMaxGCDuration = std::max(mMaxGCDuration, aMaybeAfterGCTime - aBeginTime);
149 void mozilla::CycleCollectorStats::AfterSyncForgetSkippable(
150 TimeStamp beginTime) {
151 mMaxSkippableDuration =
152 std::max(mMaxSkippableDuration, TimeUntilNow(beginTime));
153 mRanSyncForgetSkippable = true;
156 void mozilla::CycleCollectorStats::AfterForgetSkippable(
157 mozilla::TimeStamp aStartTime, mozilla::TimeStamp aEndTime,
158 uint32_t aRemovedPurples, bool aInIdle) {
159 mozilla::TimeDuration duration = aEndTime - aStartTime;
160 if (!mMinForgetSkippableTime || mMinForgetSkippableTime > duration) {
161 mMinForgetSkippableTime = duration;
163 if (!mMaxForgetSkippableTime || mMaxForgetSkippableTime < duration) {
164 mMaxForgetSkippableTime = duration;
166 mTotalForgetSkippableTime += duration;
167 ++mForgetSkippableBeforeCC;
169 mRemovedPurples += aRemovedPurples;
171 PROFILER_MARKER("ForgetSkippable", GCCC,
172 MarkerTiming::IntervalUntilNowFrom(aStartTime), CCSliceMarker,
173 aInIdle);
176 void mozilla::CycleCollectorStats::SendTelemetry(TimeDuration aCCNowDuration,
177 TimeStamp aPrevCCEnd) const {
178 // Many of the telemetry measures would not make sense off the main thread (on
179 // workers), and even for those that do, we don't want to mix mainthread and
180 // other threads' measures.
181 MOZ_ASSERT(NS_IsMainThread());
183 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FINISH_IGC, mAnyLockedOut);
184 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_SYNC_SKIPPABLE,
185 mRanSyncForgetSkippable);
186 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FULL,
187 aCCNowDuration.ToMilliseconds());
188 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_MAX_PAUSE,
189 mMaxSliceTime.ToMilliseconds());
191 if (!aPrevCCEnd.IsNull()) {
192 TimeDuration timeBetween = TimeBetween(aPrevCCEnd, mBeginTime);
193 Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_TIME_BETWEEN,
194 timeBetween.ToSeconds());
197 Telemetry::Accumulate(Telemetry::FORGET_SKIPPABLE_MAX,
198 mMaxForgetSkippableTime.ToMilliseconds());