CheckerboardEvent.cpp (6536B)
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 #include "mozilla/Logging.h" 9 10 #include <algorithm> // for std::sort 11 12 static mozilla::LazyLogModule sApzCheckLog("apz.checkerboard"); 13 14 namespace mozilla { 15 namespace layers { 16 17 // Relatively arbitrary limit to prevent a perma-checkerboard event from 18 // eating up gobs of memory. Ideally we shouldn't have perma-checkerboarding 19 // but better to guard against it. 20 #define LOG_LENGTH_LIMIT (50 * 1024) 21 22 const char* CheckerboardEvent::sDescriptions[] = { 23 "page", 24 "painted displayport", 25 "requested displayport", 26 "viewport", 27 }; 28 29 const char* CheckerboardEvent::sColors[] = { 30 "brown", 31 "lightgreen", 32 "yellow", 33 "red", 34 }; 35 36 CheckerboardEvent::CheckerboardEvent(bool aRecordTrace) 37 : mRecordTrace(aRecordTrace), 38 mOriginTime(TimeStamp::Now()), 39 mCheckerboardingActive(false), 40 mLastSampleTime(mOriginTime), 41 mFrameCount(0), 42 mTotalPixelMs(0), 43 mPeakPixels(0), 44 mRendertraceLock("Rendertrace") {} 45 46 uint32_t CheckerboardEvent::GetSeverity() { 47 // Scale the total into a 32-bit value 48 return (uint32_t)sqrt((double)mTotalPixelMs); 49 } 50 51 uint32_t CheckerboardEvent::GetPeak() { return mPeakPixels; } 52 53 TimeDuration CheckerboardEvent::GetDuration() { return mEndTime - mStartTime; } 54 55 std::string CheckerboardEvent::GetLog() { 56 MonitorAutoLock lock(mRendertraceLock); 57 return mRendertraceInfo.str(); 58 } 59 60 bool CheckerboardEvent::IsRecordingTrace() { return mRecordTrace; } 61 62 void CheckerboardEvent::UpdateRendertraceProperty( 63 RendertraceProperty aProperty, const CSSRect& aRect, 64 const std::string& aExtraInfo) { 65 if (!mRecordTrace) { 66 return; 67 } 68 MonitorAutoLock lock(mRendertraceLock); 69 if (!mCheckerboardingActive) { 70 mBufferedProperties[aProperty].Update(aProperty, aRect, aExtraInfo, lock); 71 } else { 72 LogInfo(aProperty, TimeStamp::Now(), aRect, aExtraInfo, lock); 73 } 74 } 75 76 void CheckerboardEvent::LogInfo(RendertraceProperty aProperty, 77 const TimeStamp& aTimestamp, 78 const CSSRect& aRect, 79 const std::string& aExtraInfo, 80 const MonitorAutoLock& aProofOfLock) { 81 MOZ_ASSERT(mRecordTrace); 82 if (mRendertraceInfo.tellp() >= LOG_LENGTH_LIMIT) { 83 // The log is already long enough, don't put more things into it. We'll 84 // append a truncation message when this event ends. 85 return; 86 } 87 // The log is consumed by the page at about:checkerboard. The format is not 88 // formally specced, but an informal description can be found at 89 // https://searchfox.org/mozilla-central/rev/d866b96d74ec2a63f09ee418f048d23f4fd379a2/toolkit/components/aboutcheckerboard/content/aboutCheckerboard.js#86 90 mRendertraceInfo << "RENDERTRACE " 91 << (aTimestamp - mOriginTime).ToMilliseconds() << " rect " 92 << sColors[aProperty] << " " << aRect.X() << " " << aRect.Y() 93 << " " << aRect.Width() << " " << aRect.Height() << " " 94 << "// " << sDescriptions[aProperty] << aExtraInfo << '\n'; 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 --\n"; 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 << '\n'; 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