LCOV - code coverage report
Current view: top level - gfx/layers/composite - FPSCounter.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 9 170 5.3 %
Date: 2017-07-14 16:53:18 Functions: 2 20 10.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include <stddef.h>                     // for size_t
       7             : #include "Units.h"                      // for ScreenIntRect
       8             : #include "gfxRect.h"                    // for gfxRect
       9             : #include "gfxPrefs.h"                   // for gfxPrefs
      10             : #include "mozilla/gfx/Point.h"          // for IntSize, Point
      11             : #include "mozilla/gfx/Rect.h"           // for Rect
      12             : #include "mozilla/gfx/Types.h"          // for Color, SurfaceFormat
      13             : #include "mozilla/layers/Compositor.h"  // for Compositor
      14             : #include "mozilla/layers/CompositorTypes.h"
      15             : #include "mozilla/layers/Effects.h"     // for Effect, EffectChain, etc
      16             : #include "mozilla/TimeStamp.h"          // for TimeStamp, TimeDuration
      17             : #include "nsPoint.h"                    // for nsIntPoint
      18             : #include "nsRect.h"                     // for mozilla::gfx::IntRect
      19             : #include "nsIFile.h"                    // for nsIFile
      20             : #include "nsDirectoryServiceDefs.h"     // for NS_OS_TMP_DIR
      21             : #include "mozilla/Sprintf.h"
      22             : #include "FPSCounter.h"
      23             : 
      24             : namespace mozilla {
      25             : namespace layers {
      26             : 
      27             : using namespace mozilla::gfx;
      28             : 
      29           2 : FPSCounter::FPSCounter(const char* aName)
      30             :   : mWriteIndex(0)
      31             :   , mIteratorIndex(-1)
      32           2 :   , mFPSName(aName)
      33             : {
      34           2 :   Init();
      35           2 : }
      36             : 
      37           0 : FPSCounter::~FPSCounter() { }
      38             : 
      39             : void
      40           2 : FPSCounter::Init()
      41             : {
      42        4802 :   for (int i = 0; i < kMaxFrames; i++) {
      43        4800 :     mFrameTimestamps.AppendElement(TimeStamp());
      44             :   }
      45           2 :   mLastInterval = TimeStamp::Now();
      46           2 : }
      47             : 
      48             : // Returns true if we captured a full interval of data
      49             : bool
      50           0 : FPSCounter::CapturedFullInterval(TimeStamp aTimestamp) {
      51           0 :   TimeDuration duration = aTimestamp - mLastInterval;
      52           0 :   return duration.ToSeconds() >= kFpsDumpInterval;
      53             : }
      54             : 
      55             : void
      56           0 : FPSCounter::AddFrame(TimeStamp aTimestamp) {
      57           0 :   NS_ASSERTION(mWriteIndex < kMaxFrames, "We probably have a bug with the circular buffer");
      58           0 :   NS_ASSERTION(mWriteIndex >= 0, "Circular Buffer index should never be negative");
      59             : 
      60           0 :   int index = mWriteIndex++;
      61           0 :   if (mWriteIndex == kMaxFrames) {
      62           0 :     mWriteIndex = 0;
      63             :   }
      64             : 
      65           0 :   mFrameTimestamps[index] = aTimestamp;
      66             : 
      67           0 :   if (CapturedFullInterval(aTimestamp)) {
      68           0 :     PrintFPS();
      69           0 :     WriteFrameTimeStamps();
      70           0 :     mLastInterval = aTimestamp;
      71             :   }
      72           0 : }
      73             : 
      74             : double
      75           0 : FPSCounter::AddFrameAndGetFps(TimeStamp aTimestamp) {
      76           0 :   AddFrame(aTimestamp);
      77           0 :   return GetFPS(aTimestamp);
      78             : }
      79             : 
      80             : int
      81           0 : FPSCounter::GetLatestReadIndex()
      82             : {
      83           0 :   if (mWriteIndex == 0) {
      84           0 :     return kMaxFrames - 1;
      85             :   }
      86             : 
      87           0 :   return mWriteIndex - 1;
      88             : }
      89             : 
      90             : TimeStamp
      91           0 : FPSCounter::GetLatestTimeStamp()
      92             : {
      93           0 :   TimeStamp timestamp = mFrameTimestamps[GetLatestReadIndex()];
      94           0 :   MOZ_ASSERT(!timestamp.IsNull(), "Cannot use null timestamps");
      95           0 :   return timestamp;
      96             : }
      97             : 
      98             : // Returns true if we iterated over a full interval of data
      99             : bool
     100           0 : FPSCounter::IteratedFullInterval(TimeStamp aTimestamp, double aDuration) {
     101           0 :   MOZ_ASSERT(mIteratorIndex >= 0, "Cannot be negative");
     102           0 :   MOZ_ASSERT(mIteratorIndex < kMaxFrames, "Iterator index cannot be greater than kMaxFrames");
     103             : 
     104           0 :   TimeStamp currentStamp = mFrameTimestamps[mIteratorIndex];
     105           0 :   TimeDuration duration = aTimestamp - currentStamp;
     106           0 :   return duration.ToSeconds() >= aDuration;
     107             : }
     108             : 
     109             : void
     110           0 : FPSCounter::ResetReverseIterator()
     111             : {
     112           0 :   mIteratorIndex = GetLatestReadIndex();
     113           0 : }
     114             : 
     115             : /***
     116             :  * Returns true if we have another timestamp that is valid and
     117             :  * is within the given duration that we're interested in.
     118             :  * Duration is in seconds
     119             :  */
     120           0 : bool FPSCounter::HasNext(TimeStamp aTimestamp, double aDuration)
     121             : {
     122             :   // Order of evaluation here has to stay the same
     123             :   // otherwise IteratedFullInterval reads from mFrameTimestamps which cannot
     124             :   // be null
     125           0 :   return (mIteratorIndex != mWriteIndex) // Didn't loop around the buffer
     126           0 :           && !mFrameTimestamps[mIteratorIndex].IsNull() // valid data
     127           0 :           && !IteratedFullInterval(aTimestamp, aDuration);
     128             : }
     129             : 
     130             : TimeStamp
     131           0 : FPSCounter::GetNextTimeStamp()
     132             : {
     133           0 :   TimeStamp timestamp = mFrameTimestamps[mIteratorIndex--];
     134           0 :   MOZ_ASSERT(!timestamp.IsNull(), "Reading Invalid Timestamp Data");
     135             : 
     136           0 :   if (mIteratorIndex == -1) {
     137           0 :     mIteratorIndex = kMaxFrames - 1;
     138             :   }
     139           0 :   return timestamp;
     140             : }
     141             : 
     142             : /**
     143             :  * GetFPS calculates how many frames we've already composited from the current
     144             :  * frame timestamp and we iterate from the latest timestamp we recorded,
     145             :  * going back in time. When we hit a frame that is longer than the 1 second
     146             :  * from the current composited frame, we return how many frames we've counted.
     147             :  * Just a visualization:
     148             :  *
     149             :  *                                 aTimestamp
     150             :  * Frames: 1 2 3 4 5 6 7 8 9 10 11 12
     151             :  * Time   -------------------------->
     152             :  *
     153             :  * GetFPS iterates from aTimestamp, which is the current frame.
     154             :  * Then starting at frame 12, going back to frame 11, 10, etc, we calculate
     155             :  * the duration of the recorded frame timestamp from aTimestamp.
     156             :  * Once duration is greater than 1 second, we return how many frames
     157             :  * we composited.
     158             :  */
     159             : double
     160           0 : FPSCounter::GetFPS(TimeStamp aTimestamp)
     161             : {
     162           0 :   int frameCount = 0;
     163           0 :   int duration = 1.0; // Only care about the last 1s of data
     164             : 
     165           0 :   ResetReverseIterator();
     166           0 :   while (HasNext(aTimestamp, duration)) {
     167           0 :     GetNextTimeStamp();
     168           0 :     frameCount++;
     169             :   }
     170             : 
     171           0 :   return frameCount;
     172             : }
     173             : 
     174             : // Iterate the same way we do in GetFPS()
     175             : int
     176           0 : FPSCounter::BuildHistogram(std::map<int, int>& aFpsData)
     177             : {
     178           0 :   TimeStamp currentIntervalStart = GetLatestTimeStamp();
     179           0 :   TimeStamp currentTimeStamp = GetLatestTimeStamp();
     180           0 :   TimeStamp startTimeStamp = GetLatestTimeStamp();
     181             : 
     182           0 :   int frameCount = 0;
     183           0 :   int totalFrameCount = 0;
     184             : 
     185           0 :   ResetReverseIterator();
     186           0 :   while (HasNext(startTimeStamp)) {
     187           0 :     currentTimeStamp = GetNextTimeStamp();
     188           0 :     TimeDuration interval = currentIntervalStart - currentTimeStamp;
     189             : 
     190           0 :     if (interval.ToSeconds() >= 1.0 ) {
     191           0 :       currentIntervalStart = currentTimeStamp;
     192           0 :       aFpsData[frameCount]++;
     193           0 :       frameCount = 0;
     194             :     }
     195             : 
     196           0 :     frameCount++;
     197           0 :     totalFrameCount++;
     198             :   }
     199             : 
     200           0 :   TimeDuration totalTime = currentIntervalStart - currentTimeStamp;
     201           0 :   printf_stderr("Discarded %d frames over %f ms in histogram for %s\n",
     202           0 :     frameCount, totalTime.ToMilliseconds(), mFPSName);
     203           0 :   return totalFrameCount;
     204             : }
     205             : 
     206             : // Iterate the same way we do in GetFPS()
     207             : void
     208           0 : FPSCounter::WriteFrameTimeStamps(PRFileDesc* fd)
     209             : {
     210           0 :   const int bufferSize = 256;
     211             :   char buffer[bufferSize];
     212           0 :   int writtenCount = SprintfLiteral(buffer, "FPS Data for: %s\n", mFPSName);
     213           0 :   MOZ_ASSERT(writtenCount >= 0);
     214           0 :   PR_Write(fd, buffer, writtenCount);
     215             : 
     216           0 :   ResetReverseIterator();
     217           0 :   TimeStamp startTimeStamp = GetLatestTimeStamp();
     218             : 
     219           0 :   MOZ_ASSERT(HasNext(startTimeStamp));
     220           0 :   TimeStamp previousSample = GetNextTimeStamp();
     221             : 
     222           0 :   MOZ_ASSERT(HasNext(startTimeStamp));
     223           0 :   TimeStamp nextTimeStamp = GetNextTimeStamp();
     224             : 
     225           0 :   while (HasNext(startTimeStamp)) {
     226           0 :     TimeDuration duration = previousSample - nextTimeStamp;
     227           0 :     writtenCount = SprintfLiteral(buffer, "%f,\n", duration.ToMilliseconds());
     228             : 
     229           0 :     MOZ_ASSERT(writtenCount >= 0);
     230           0 :     PR_Write(fd, buffer, writtenCount);
     231             : 
     232           0 :     previousSample = nextTimeStamp;
     233           0 :     nextTimeStamp = GetNextTimeStamp();
     234             :   }
     235           0 : }
     236             : 
     237             : double
     238           0 : FPSCounter::GetMean(std::map<int, int> aHistogram)
     239             : {
     240           0 :   double average = 0.0;
     241           0 :   double samples = 0.0;
     242             : 
     243           0 :   for (std::map<int, int>::iterator iter = aHistogram.begin();
     244           0 :     iter != aHistogram.end(); ++iter)
     245             :   {
     246           0 :     int fps = iter->first;
     247           0 :     int count = iter->second;
     248             : 
     249           0 :     average += fps * count;
     250           0 :     samples += count;
     251             :   }
     252             : 
     253           0 :   return average / samples;
     254             : }
     255             : 
     256             : double
     257           0 : FPSCounter::GetStdDev(std::map<int, int> aHistogram)
     258             : {
     259           0 :   double sumOfDifferences = 0;
     260           0 :   double average = GetMean(aHistogram);
     261           0 :   double samples = 0.0;
     262             : 
     263           0 :   for (std::map<int, int>::iterator iter = aHistogram.begin();
     264           0 :     iter != aHistogram.end(); ++iter)
     265             :   {
     266           0 :     int fps = iter->first;
     267           0 :     int count = iter->second;
     268             : 
     269           0 :     double diff = ((double) fps) - average;
     270           0 :     diff *= diff;
     271             : 
     272           0 :     for (int i = 0; i < count; i++) {
     273           0 :       sumOfDifferences += diff;
     274             :     }
     275           0 :     samples += count;
     276             :   }
     277             : 
     278           0 :   double stdDev = sumOfDifferences / samples;
     279           0 :   return sqrt(stdDev);
     280             : }
     281             : 
     282             : void
     283           0 : FPSCounter::PrintFPS()
     284             : {
     285           0 :   if (!gfxPrefs::FPSPrintHistogram()) {
     286           0 :     return;
     287             :   }
     288             : 
     289           0 :   std::map<int, int> histogram;
     290           0 :   int totalFrames = BuildHistogram(histogram);
     291             : 
     292           0 :   TimeDuration measurementInterval = mFrameTimestamps[GetLatestReadIndex()] - mLastInterval;
     293           0 :   printf_stderr("FPS for %s. Total Frames: %d Time Interval: %f seconds\n",
     294           0 :                 mFPSName, totalFrames, measurementInterval.ToSecondsSigDigits());
     295             : 
     296           0 :   PrintHistogram(histogram);
     297             : }
     298             : 
     299             : void
     300           0 : FPSCounter::PrintHistogram(std::map<int, int>& aHistogram)
     301             : {
     302           0 :   int length = 0;
     303           0 :   const int kBufferLength = 512;
     304             :   char buffer[kBufferLength];
     305             : 
     306           0 :   for (std::map<int, int>::iterator iter = aHistogram.begin();
     307           0 :     iter != aHistogram.end(); iter++)
     308             :   {
     309           0 :     int fps = iter->first;
     310           0 :     int count = iter->second;
     311             : 
     312           0 :     length += snprintf(buffer + length, kBufferLength - length,
     313             :                        "FPS: %d = %d. ", fps, count);
     314           0 :     NS_ASSERTION(length >= kBufferLength, "Buffer overrun while printing FPS histogram.");
     315             :   }
     316             : 
     317           0 :   printf_stderr("%s\n", buffer);
     318           0 :   printf_stderr("Mean: %f , std dev %f\n", GetMean(aHistogram), GetStdDev(aHistogram));
     319           0 : }
     320             : 
     321             : // Write FPS timestamp data to a file only if
     322             : // draw-fps.write-to-file is true
     323             : nsresult
     324           0 : FPSCounter::WriteFrameTimeStamps()
     325             : {
     326           0 :   if (!gfxPrefs::WriteFPSToFile()) {
     327           0 :     return NS_OK;
     328             :   }
     329             : 
     330           0 :   MOZ_ASSERT(mWriteIndex == 0);
     331             : 
     332           0 :   nsCOMPtr<nsIFile> resultFile;
     333           0 :   nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(resultFile));
     334           0 :   NS_ENSURE_SUCCESS(rv, rv);
     335             : 
     336           0 :   if (!strncmp(mFPSName, "Compositor", strlen(mFPSName))) {
     337           0 :     resultFile->Append(NS_LITERAL_STRING("fps.txt"));
     338             :   } else {
     339           0 :     resultFile->Append(NS_LITERAL_STRING("txn.txt"));
     340             :   }
     341             : 
     342           0 :   PRFileDesc* fd = nullptr;
     343           0 :   int mode = 644;
     344           0 :   int openFlags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
     345           0 :   rv = resultFile->OpenNSPRFileDesc(openFlags, mode, &fd);
     346           0 :   NS_ENSURE_SUCCESS(rv, rv);
     347             : 
     348           0 :   WriteFrameTimeStamps(fd);
     349           0 :   PR_Close(fd);
     350             : 
     351           0 :   nsAutoCString path;
     352           0 :   rv = resultFile->GetNativePath(path);
     353           0 :   NS_ENSURE_SUCCESS(rv, rv);
     354             : 
     355           0 :   printf_stderr("Wrote FPS data to file: %s\n", path.get());
     356           0 :   return NS_OK;
     357             : }
     358             : 
     359             : } // end namespace layers
     360             : } // end namespace mozilla

Generated by: LCOV version 1.13