Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set sw=2 ts=8 et 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 : namespace mozilla {
12 : namespace layers {
13 :
14 : // Relatively arbitrary limit to prevent a perma-checkerboard event from
15 : // eating up gobs of memory. Ideally we shouldn't have perma-checkerboarding
16 : // but better to guard against it.
17 : #define LOG_LENGTH_LIMIT (50 * 1024)
18 :
19 : const char* CheckerboardEvent::sDescriptions[] = {
20 : "page",
21 : "painted critical displayport",
22 : "painted displayport",
23 : "requested displayport",
24 : "viewport",
25 : };
26 :
27 : const char* CheckerboardEvent::sColors[] = {
28 : "brown",
29 : "darkgreen",
30 : "lightgreen",
31 : "yellow",
32 : "red",
33 : };
34 :
35 2 : CheckerboardEvent::CheckerboardEvent(bool aRecordTrace)
36 : : mRecordTrace(aRecordTrace)
37 : , mOriginTime(TimeStamp::Now())
38 : , mCheckerboardingActive(false)
39 : , mLastSampleTime(mOriginTime)
40 : , mFrameCount(0)
41 : , mTotalPixelMs(0)
42 : , mPeakPixels(0)
43 2 : , mRendertraceLock("Rendertrace")
44 : {
45 2 : }
46 :
47 : uint32_t
48 0 : CheckerboardEvent::GetSeverity()
49 : {
50 : // Scale the total into a 32-bit value
51 0 : return (uint32_t)sqrt((double)mTotalPixelMs);
52 : }
53 :
54 : uint32_t
55 0 : CheckerboardEvent::GetPeak()
56 : {
57 0 : return mPeakPixels;
58 : }
59 :
60 : TimeDuration
61 0 : CheckerboardEvent::GetDuration()
62 : {
63 0 : return mEndTime - mStartTime;
64 : }
65 :
66 : std::string
67 0 : CheckerboardEvent::GetLog()
68 : {
69 0 : MonitorAutoLock lock(mRendertraceLock);
70 0 : return mRendertraceInfo.str();
71 : }
72 :
73 : bool
74 7 : CheckerboardEvent::IsRecordingTrace()
75 : {
76 7 : return mRecordTrace;
77 : }
78 :
79 : void
80 52 : CheckerboardEvent::UpdateRendertraceProperty(RendertraceProperty aProperty,
81 : const CSSRect& aRect,
82 : const std::string& aExtraInfo)
83 : {
84 52 : if (!mRecordTrace) {
85 0 : return;
86 : }
87 104 : MonitorAutoLock lock(mRendertraceLock);
88 52 : if (!mCheckerboardingActive) {
89 52 : mBufferedProperties[aProperty].Update(aProperty, aRect, aExtraInfo, lock);
90 : } else {
91 0 : LogInfo(aProperty, TimeStamp::Now(), aRect, aExtraInfo, lock);
92 : }
93 : }
94 :
95 : void
96 0 : CheckerboardEvent::LogInfo(RendertraceProperty aProperty,
97 : const TimeStamp& aTimestamp,
98 : const CSSRect& aRect,
99 : const std::string& aExtraInfo,
100 : const MonitorAutoLock& aProofOfLock)
101 : {
102 0 : MOZ_ASSERT(mRecordTrace);
103 0 : if (mRendertraceInfo.tellp() >= LOG_LENGTH_LIMIT) {
104 : // The log is already long enough, don't put more things into it. We'll
105 : // append a truncation message when this event ends.
106 0 : return;
107 : }
108 : // The log is consumed by the page at http://people.mozilla.org/~kgupta/rendertrace.html
109 : // and will move to about:checkerboard in bug 1238042. The format is not
110 : // formally specced, but an informal description can be found at
111 : // https://github.com/staktrace/rendertrace/blob/master/index.html#L30
112 0 : mRendertraceInfo << "RENDERTRACE "
113 0 : << (aTimestamp - mOriginTime).ToMilliseconds() << " rect "
114 0 : << sColors[aProperty] << " "
115 0 : << aRect.x << " "
116 0 : << aRect.y << " "
117 0 : << aRect.width << " "
118 0 : << aRect.height << " "
119 : << "// " << sDescriptions[aProperty]
120 0 : << aExtraInfo << std::endl;
121 : }
122 :
123 : bool
124 35 : CheckerboardEvent::RecordFrameInfo(uint32_t aCssPixelsCheckerboarded)
125 : {
126 35 : TimeStamp sampleTime = TimeStamp::Now();
127 35 : bool eventEnding = false;
128 35 : if (aCssPixelsCheckerboarded > 0) {
129 0 : if (!mCheckerboardingActive) {
130 0 : StartEvent();
131 : }
132 0 : MOZ_ASSERT(mCheckerboardingActive);
133 0 : MOZ_ASSERT(sampleTime >= mLastSampleTime);
134 0 : mTotalPixelMs += (uint64_t)((sampleTime - mLastSampleTime).ToMilliseconds() * aCssPixelsCheckerboarded);
135 0 : if (aCssPixelsCheckerboarded > mPeakPixels) {
136 0 : mPeakPixels = aCssPixelsCheckerboarded;
137 : }
138 0 : mFrameCount++;
139 : } else {
140 35 : if (mCheckerboardingActive) {
141 0 : StopEvent();
142 0 : eventEnding = true;
143 : }
144 35 : MOZ_ASSERT(!mCheckerboardingActive);
145 : }
146 35 : mLastSampleTime = sampleTime;
147 35 : return eventEnding;
148 : }
149 :
150 : void
151 0 : CheckerboardEvent::StartEvent()
152 : {
153 0 : MOZ_ASSERT(!mCheckerboardingActive);
154 0 : mCheckerboardingActive = true;
155 0 : mStartTime = TimeStamp::Now();
156 :
157 0 : if (!mRecordTrace) {
158 0 : return;
159 : }
160 0 : MonitorAutoLock lock(mRendertraceLock);
161 0 : std::vector<PropertyValue> history;
162 0 : for (size_t i = 0; i < sRendertracePropertyCount; i++) {
163 0 : mBufferedProperties[i].Flush(history, lock);
164 : }
165 0 : std::sort(history.begin(), history.end());
166 0 : for (const PropertyValue& p : history) {
167 0 : LogInfo(p.mProperty, p.mTimeStamp, p.mRect, p.mExtraInfo, lock);
168 : }
169 0 : mRendertraceInfo << " -- checkerboarding starts below --" << std::endl;
170 : }
171 :
172 : void
173 0 : CheckerboardEvent::StopEvent()
174 : {
175 0 : mCheckerboardingActive = false;
176 0 : mEndTime = TimeStamp::Now();
177 :
178 0 : if (!mRecordTrace) {
179 0 : return;
180 : }
181 0 : MonitorAutoLock lock(mRendertraceLock);
182 0 : if (mRendertraceInfo.tellp() >= LOG_LENGTH_LIMIT) {
183 0 : mRendertraceInfo << "[logging aborted due to length limitations]\n";
184 : }
185 0 : mRendertraceInfo << "Checkerboarded for " << mFrameCount << " frames ("
186 0 : << (mEndTime - mStartTime).ToMilliseconds() << " ms), "
187 0 : << mPeakPixels << " peak, " << GetSeverity() << " severity." << std::endl;
188 : }
189 :
190 : bool
191 0 : CheckerboardEvent::PropertyValue::operator<(const PropertyValue& aOther) const
192 : {
193 0 : if (mTimeStamp < aOther.mTimeStamp) {
194 0 : return true;
195 0 : } else if (mTimeStamp > aOther.mTimeStamp) {
196 0 : return false;
197 : }
198 0 : return mProperty < aOther.mProperty;
199 : }
200 :
201 10 : CheckerboardEvent::PropertyBuffer::PropertyBuffer()
202 10 : : mIndex(0)
203 : {
204 10 : }
205 :
206 : void
207 52 : CheckerboardEvent::PropertyBuffer::Update(RendertraceProperty aProperty,
208 : const CSSRect& aRect,
209 : const std::string& aExtraInfo,
210 : const MonitorAutoLock& aProofOfLock)
211 : {
212 52 : mValues[mIndex] = { aProperty, TimeStamp::Now(), aRect, aExtraInfo };
213 52 : mIndex = (mIndex + 1) % BUFFER_SIZE;
214 52 : }
215 :
216 : void
217 0 : CheckerboardEvent::PropertyBuffer::Flush(std::vector<PropertyValue>& aOut,
218 : const MonitorAutoLock& aProofOfLock)
219 : {
220 0 : for (uint32_t i = 0; i < BUFFER_SIZE; i++) {
221 0 : uint32_t ix = (mIndex + i) % BUFFER_SIZE;
222 0 : if (!mValues[ix].mTimeStamp.IsNull()) {
223 0 : aOut.push_back(mValues[ix]);
224 0 : mValues[ix].mTimeStamp = TimeStamp();
225 : }
226 : }
227 0 : }
228 :
229 : } // namespace layers
230 : } // namespace mozilla
|