tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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