Bug 1776056 - Switch to the tab an animation is running and make sure the animation...
[gecko.git] / layout / base / LayoutTelemetryTools.cpp
blobb59b73f81096197899b1c3298f8ea4c099d4cb34
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 "mozilla/layout/LayoutTelemetryTools.h"
9 #include "MainThreadUtils.h"
10 #include "mozilla/Atomics.h"
11 #include "mozilla/PodOperations.h"
12 #include "mozilla/Telemetry.h"
14 using namespace mozilla;
15 using namespace mozilla::layout_telemetry;
17 // Returns the key name expected by telemetry. Keep to date with
18 // toolkits/components/telemetry/Histograms.json.
19 static nsLiteralCString SubsystemTelemetryKey(LayoutSubsystem aSubsystem) {
20 switch (aSubsystem) {
21 default:
22 MOZ_CRASH("Unexpected LayoutSubsystem value");
23 case LayoutSubsystem::Restyle:
24 return "Restyle"_ns;
25 case LayoutSubsystem::Reflow:
26 return "ReflowOther"_ns;
27 case LayoutSubsystem::ReflowFlex:
28 return "ReflowFlex"_ns;
29 case LayoutSubsystem::ReflowGrid:
30 return "ReflowGrid"_ns;
31 case LayoutSubsystem::ReflowTable:
32 return "ReflowTable"_ns;
33 case LayoutSubsystem::ReflowText:
34 return "ReflowText"_ns;
38 static AutoRecord* sCurrentRecord;
40 static FlushKind ToKind(FlushType aFlushType) {
41 switch (aFlushType) {
42 default:
43 MOZ_CRASH("Expected FlushType::Style or FlushType::Layout");
44 case FlushType::Style:
45 return FlushKind::Style;
46 case FlushType::Layout:
47 return FlushKind::Layout;
51 namespace mozilla {
52 namespace layout_telemetry {
54 Data::Data() {
55 PodZero(&mReqsPerFlush);
56 PodZero(&mFlushesPerTick);
57 PodZero(&mLayoutSubsystemDurationMs);
60 void Data::IncReqsPerFlush(FlushType aFlushType) {
61 mReqsPerFlush[ToKind(aFlushType)]++;
64 void Data::IncFlushesPerTick(FlushType aFlushType) {
65 mFlushesPerTick[ToKind(aFlushType)]++;
68 void Data::PingReqsPerFlushTelemetry(FlushType aFlushType) {
69 auto flushKind = ToKind(aFlushType);
70 if (flushKind == FlushKind::Layout) {
71 auto styleFlushReqs = mReqsPerFlush[FlushKind::Style].value();
72 auto layoutFlushReqs = mReqsPerFlush[FlushKind::Layout].value();
73 Telemetry::Accumulate(Telemetry::PRESSHELL_REQS_PER_LAYOUT_FLUSH,
74 "Style"_ns, styleFlushReqs);
75 Telemetry::Accumulate(Telemetry::PRESSHELL_REQS_PER_LAYOUT_FLUSH,
76 "Layout"_ns, layoutFlushReqs);
77 mReqsPerFlush[FlushKind::Style] = SaturateUint8(0);
78 mReqsPerFlush[FlushKind::Layout] = SaturateUint8(0);
79 } else {
80 auto styleFlushReqs = mReqsPerFlush[FlushKind::Style].value();
81 Telemetry::Accumulate(Telemetry::PRESSHELL_REQS_PER_STYLE_FLUSH,
82 styleFlushReqs);
83 mReqsPerFlush[FlushKind::Style] = SaturateUint8(0);
87 void Data::PingFlushPerTickTelemetry(FlushType aFlushType) {
88 auto flushKind = ToKind(aFlushType);
89 auto styleFlushes = mFlushesPerTick[FlushKind::Style].value();
90 if (styleFlushes > 0) {
91 Telemetry::Accumulate(Telemetry::PRESSHELL_FLUSHES_PER_TICK, "Style"_ns,
92 styleFlushes);
93 mFlushesPerTick[FlushKind::Style] = SaturateUint8(0);
96 auto layoutFlushes = mFlushesPerTick[FlushKind::Layout].value();
97 if (flushKind == FlushKind::Layout && layoutFlushes > 0) {
98 Telemetry::Accumulate(Telemetry::PRESSHELL_FLUSHES_PER_TICK, "Layout"_ns,
99 layoutFlushes);
100 mFlushesPerTick[FlushKind::Layout] = SaturateUint8(0);
104 void Data::PingTotalMsPerTickTelemetry(FlushType aFlushType) {
105 auto flushKind = ToKind(aFlushType);
106 auto range = (flushKind == FlushKind::Style)
107 ? MakeEnumeratedRange(LayoutSubsystem::Restyle,
108 LayoutSubsystem::Reflow)
109 : MakeEnumeratedRange(LayoutSubsystem::Reflow,
110 LayoutSubsystem::Count);
112 for (auto subsystem : range) {
113 auto key = SubsystemTelemetryKey(subsystem);
114 double& duration = mLayoutSubsystemDurationMs[subsystem];
115 if (duration > 0.0) {
116 Telemetry::Accumulate(Telemetry::PRESSHELL_LAYOUT_TOTAL_MS_PER_TICK, key,
117 static_cast<uint32_t>(duration));
118 duration = 0.0;
123 void Data::PingPerTickTelemetry(FlushType aFlushType) {
124 PingFlushPerTickTelemetry(aFlushType);
125 PingTotalMsPerTickTelemetry(aFlushType);
128 AutoRecord::AutoRecord(LayoutSubsystem aSubsystem)
129 : AutoRecord(nullptr, aSubsystem) {}
131 AutoRecord::AutoRecord(Data* aLayoutTelemetry, LayoutSubsystem aSubsystem)
132 : mParentRecord(sCurrentRecord),
133 mLayoutTelemetry(aLayoutTelemetry),
134 mSubsystem(aSubsystem),
135 mStartTime(TimeStamp::Now()),
136 mDurationMs(0.0) {
137 MOZ_ASSERT(NS_IsMainThread());
139 // If we're re-entering the same subsystem, don't update the current record.
140 if (mParentRecord) {
141 if (mParentRecord->mSubsystem == mSubsystem) {
142 return;
145 mLayoutTelemetry = mParentRecord->mLayoutTelemetry;
146 MOZ_ASSERT(mLayoutTelemetry);
148 // If we're entering a new subsystem, record the amount of time spent in the
149 // parent record before setting the new current record.
150 mParentRecord->mDurationMs +=
151 (mStartTime - mParentRecord->mStartTime).ToMilliseconds();
154 sCurrentRecord = this;
157 AutoRecord::~AutoRecord() {
158 if (sCurrentRecord != this) {
159 // If this record is not head of the list, do nothing.
160 return;
163 TimeStamp now = TimeStamp::Now();
164 mDurationMs += (now - mStartTime).ToMilliseconds();
165 mLayoutTelemetry->mLayoutSubsystemDurationMs[mSubsystem] += mDurationMs;
167 if (mParentRecord) {
168 // Restart the parent recording from this point
169 mParentRecord->mStartTime = now;
172 // Unlink this record from the current record list
173 sCurrentRecord = mParentRecord;
176 } // namespace layout_telemetry
177 } // namespace mozilla