Source code

Revision control

Other Tools

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/. */
6
7
#include "CheckerboardEvent.h"
8
9
#include <algorithm> // for std::sort
10
11
static mozilla::LazyLogModule sApzCheckLog("apz.checkerboard");
12
13
namespace mozilla {
14
namespace layers {
15
16
// Relatively arbitrary limit to prevent a perma-checkerboard event from
17
// eating up gobs of memory. Ideally we shouldn't have perma-checkerboarding
18
// but better to guard against it.
19
#define LOG_LENGTH_LIMIT (50 * 1024)
20
21
const char* CheckerboardEvent::sDescriptions[] = {
22
"page",
23
"painted critical displayport",
24
"painted displayport",
25
"requested displayport",
26
"viewport",
27
};
28
29
const char* CheckerboardEvent::sColors[] = {
30
"brown", "darkgreen", "lightgreen", "yellow", "red",
31
};
32
33
CheckerboardEvent::CheckerboardEvent(bool aRecordTrace)
34
: mRecordTrace(aRecordTrace),
35
mOriginTime(TimeStamp::Now()),
36
mCheckerboardingActive(false),
37
mLastSampleTime(mOriginTime),
38
mFrameCount(0),
39
mTotalPixelMs(0),
40
mPeakPixels(0),
41
mRendertraceLock("Rendertrace") {}
42
43
uint32_t CheckerboardEvent::GetSeverity() {
44
// Scale the total into a 32-bit value
45
return (uint32_t)sqrt((double)mTotalPixelMs);
46
}
47
48
uint32_t CheckerboardEvent::GetPeak() { return mPeakPixels; }
49
50
TimeDuration CheckerboardEvent::GetDuration() { return mEndTime - mStartTime; }
51
52
std::string CheckerboardEvent::GetLog() {
53
MonitorAutoLock lock(mRendertraceLock);
54
return mRendertraceInfo.str();
55
}
56
57
bool CheckerboardEvent::IsRecordingTrace() { return mRecordTrace; }
58
59
void CheckerboardEvent::UpdateRendertraceProperty(
60
RendertraceProperty aProperty, const CSSRect& aRect,
61
const std::string& aExtraInfo) {
62
if (!mRecordTrace) {
63
return;
64
}
65
MonitorAutoLock lock(mRendertraceLock);
66
if (!mCheckerboardingActive) {
67
mBufferedProperties[aProperty].Update(aProperty, aRect, aExtraInfo, lock);
68
} else {
69
LogInfo(aProperty, TimeStamp::Now(), aRect, aExtraInfo, lock);
70
}
71
}
72
73
void CheckerboardEvent::LogInfo(RendertraceProperty aProperty,
74
const TimeStamp& aTimestamp,
75
const CSSRect& aRect,
76
const std::string& aExtraInfo,
77
const MonitorAutoLock& aProofOfLock) {
78
MOZ_ASSERT(mRecordTrace);
79
if (mRendertraceInfo.tellp() >= LOG_LENGTH_LIMIT) {
80
// The log is already long enough, don't put more things into it. We'll
81
// append a truncation message when this event ends.
82
return;
83
}
84
// The log is consumed by the page at
86
// about:checkerboard in bug 1238042. The format is not formally specced, but
87
// an informal description can be found at
89
mRendertraceInfo << "RENDERTRACE "
90
<< (aTimestamp - mOriginTime).ToMilliseconds() << " rect "
91
<< sColors[aProperty] << " " << aRect.X() << " " << aRect.Y()
92
<< " " << aRect.Width() << " " << aRect.Height() << " "
93
<< "// " << sDescriptions[aProperty] << aExtraInfo
94
<< std::endl;
95
}
96
97
bool CheckerboardEvent::RecordFrameInfo(uint32_t aCssPixelsCheckerboarded) {
98
TimeStamp sampleTime = TimeStamp::Now();
99
bool eventEnding = false;
100
if (aCssPixelsCheckerboarded > 0) {
101
if (!mCheckerboardingActive) {
102
StartEvent();
103
}
104
MOZ_ASSERT(mCheckerboardingActive);
105
MOZ_ASSERT(sampleTime >= mLastSampleTime);
106
mTotalPixelMs +=
107
(uint64_t)((sampleTime - mLastSampleTime).ToMilliseconds() *
108
aCssPixelsCheckerboarded);
109
if (aCssPixelsCheckerboarded > mPeakPixels) {
110
mPeakPixels = aCssPixelsCheckerboarded;
111
}
112
mFrameCount++;
113
} else {
114
if (mCheckerboardingActive) {
115
StopEvent();
116
eventEnding = true;
117
}
118
MOZ_ASSERT(!mCheckerboardingActive);
119
}
120
mLastSampleTime = sampleTime;
121
return eventEnding;
122
}
123
124
void CheckerboardEvent::StartEvent() {
125
MOZ_LOG(sApzCheckLog, LogLevel::Debug, ("Starting checkerboard event"));
126
MOZ_ASSERT(!mCheckerboardingActive);
127
mCheckerboardingActive = true;
128
mStartTime = TimeStamp::Now();
129
130
if (!mRecordTrace) {
131
return;
132
}
133
MonitorAutoLock lock(mRendertraceLock);
134
std::vector<PropertyValue> history;
135
for (PropertyBuffer& bufferedProperty : mBufferedProperties) {
136
bufferedProperty.Flush(history, lock);
137
}
138
std::sort(history.begin(), history.end());
139
for (const PropertyValue& p : history) {
140
LogInfo(p.mProperty, p.mTimeStamp, p.mRect, p.mExtraInfo, lock);
141
}
142
mRendertraceInfo << " -- checkerboarding starts below --" << std::endl;
143
}
144
145
void CheckerboardEvent::StopEvent() {
146
MOZ_LOG(sApzCheckLog, LogLevel::Debug, ("Stopping checkerboard event"));
147
mCheckerboardingActive = false;
148
mEndTime = TimeStamp::Now();
149
150
if (!mRecordTrace) {
151
return;
152
}
153
MonitorAutoLock lock(mRendertraceLock);
154
if (mRendertraceInfo.tellp() >= LOG_LENGTH_LIMIT) {
155
mRendertraceInfo << "[logging aborted due to length limitations]\n";
156
}
157
mRendertraceInfo << "Checkerboarded for " << mFrameCount << " frames ("
158
<< (mEndTime - mStartTime).ToMilliseconds() << " ms), "
159
<< mPeakPixels << " peak, " << GetSeverity() << " severity."
160
<< std::endl;
161
}
162
163
bool CheckerboardEvent::PropertyValue::operator<(
164
const PropertyValue& aOther) const {
165
if (mTimeStamp < aOther.mTimeStamp) {
166
return true;
167
} else if (mTimeStamp > aOther.mTimeStamp) {
168
return false;
169
}
170
return mProperty < aOther.mProperty;
171
}
172
173
CheckerboardEvent::PropertyBuffer::PropertyBuffer() : mIndex(0) {}
174
175
void CheckerboardEvent::PropertyBuffer::Update(
176
RendertraceProperty aProperty, const CSSRect& aRect,
177
const std::string& aExtraInfo, const MonitorAutoLock& aProofOfLock) {
178
mValues[mIndex] = {aProperty, TimeStamp::Now(), aRect, aExtraInfo};
179
mIndex = (mIndex + 1) % BUFFER_SIZE;
180
}
181
182
void CheckerboardEvent::PropertyBuffer::Flush(
183
std::vector<PropertyValue>& aOut, const MonitorAutoLock& aProofOfLock) {
184
for (uint32_t i = 0; i < BUFFER_SIZE; i++) {
185
uint32_t ix = (mIndex + i) % BUFFER_SIZE;
186
if (!mValues[ix].mTimeStamp.IsNull()) {
187
aOut.push_back(mValues[ix]);
188
mValues[ix].mTimeStamp = TimeStamp();
189
}
190
}
191
}
192
193
} // namespace layers
194
} // namespace mozilla