LCOV - code coverage report
Current view: top level - gfx/layers/apz/util - CheckerboardReportService.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 102 1.0 %
Date: 2017-07-14 16:53:18 Functions: 0 21 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; 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 "CheckerboardReportService.h"
       7             : 
       8             : #include "gfxPrefs.h" // for gfxPrefs
       9             : #include "jsapi.h" // for JS_Now
      10             : #include "MainThreadUtils.h" // for NS_IsMainThread
      11             : #include "mozilla/Assertions.h" // for MOZ_ASSERT
      12             : #include "mozilla/ClearOnShutdown.h" // for ClearOnShutdown
      13             : #include "mozilla/Unused.h"
      14             : #include "mozilla/dom/CheckerboardReportServiceBinding.h" // for dom::CheckerboardReports
      15             : #include "mozilla/gfx/GPUParent.h"
      16             : #include "mozilla/gfx/GPUProcessManager.h"
      17             : #include "nsContentUtils.h" // for nsContentUtils
      18             : #include "nsXULAppAPI.h"
      19             : 
      20             : namespace mozilla {
      21             : namespace layers {
      22             : 
      23           3 : /*static*/ StaticRefPtr<CheckerboardEventStorage> CheckerboardEventStorage::sInstance;
      24             : 
      25             : /*static*/ already_AddRefed<CheckerboardEventStorage>
      26           0 : CheckerboardEventStorage::GetInstance()
      27             : {
      28             :   // The instance in the parent process does all the work, so if this is getting
      29             :   // called in the child process something is likely wrong.
      30           0 :   MOZ_ASSERT(XRE_IsParentProcess());
      31             : 
      32           0 :   MOZ_ASSERT(NS_IsMainThread());
      33           0 :   if (!sInstance) {
      34           0 :     sInstance = new CheckerboardEventStorage();
      35           0 :     ClearOnShutdown(&sInstance);
      36             :   }
      37           0 :   RefPtr<CheckerboardEventStorage> instance = sInstance.get();
      38           0 :   return instance.forget();
      39             : }
      40             : 
      41             : void
      42           0 : CheckerboardEventStorage::Report(uint32_t aSeverity, const std::string& aLog)
      43             : {
      44           0 :   if (!NS_IsMainThread()) {
      45           0 :     RefPtr<Runnable> task = NS_NewRunnableFunction(
      46           0 :       "layers::CheckerboardEventStorage::Report", [aSeverity, aLog]() -> void {
      47           0 :         CheckerboardEventStorage::Report(aSeverity, aLog);
      48           0 :       });
      49           0 :     NS_DispatchToMainThread(task.forget());
      50           0 :     return;
      51             :   }
      52             : 
      53           0 :   if (XRE_IsGPUProcess()) {
      54           0 :     if (gfx::GPUParent* gpu = gfx::GPUParent::GetSingleton()) {
      55           0 :       nsCString log(aLog.c_str());
      56           0 :       Unused << gpu->SendReportCheckerboard(aSeverity, log);
      57             :     }
      58           0 :     return;
      59             :   }
      60             : 
      61           0 :   RefPtr<CheckerboardEventStorage> storage = GetInstance();
      62           0 :   storage->ReportCheckerboard(aSeverity, aLog);
      63             : }
      64             : 
      65             : void
      66           0 : CheckerboardEventStorage::ReportCheckerboard(uint32_t aSeverity, const std::string& aLog)
      67             : {
      68           0 :   MOZ_ASSERT(NS_IsMainThread());
      69             : 
      70           0 :   if (aSeverity == 0) {
      71             :     // This code assumes all checkerboard reports have a nonzero severity.
      72           0 :     return;
      73             :   }
      74             : 
      75           0 :   CheckerboardReport severe(aSeverity, JS_Now(), aLog);
      76           0 :   CheckerboardReport recent;
      77             : 
      78             :   // First look in the "severe" reports to see if the new one belongs in that
      79             :   // list.
      80           0 :   for (int i = 0; i < SEVERITY_MAX_INDEX; i++) {
      81           0 :     if (mCheckerboardReports[i].mSeverity >= severe.mSeverity) {
      82           0 :       continue;
      83             :     }
      84             :     // The new one deserves to be in the "severe" list. Take the one getting
      85             :     // bumped off the list, and put it in |recent| for possible insertion into
      86             :     // the recents list.
      87           0 :     recent = mCheckerboardReports[SEVERITY_MAX_INDEX - 1];
      88             : 
      89             :     // Shuffle the severe list down, insert the new one.
      90           0 :     for (int j = SEVERITY_MAX_INDEX - 1; j > i; j--) {
      91           0 :       mCheckerboardReports[j] = mCheckerboardReports[j - 1];
      92             :     }
      93           0 :     mCheckerboardReports[i] = severe;
      94           0 :     severe.mSeverity = 0; // mark |severe| as inserted
      95           0 :     break;
      96             :   }
      97             : 
      98             :   // If |severe.mSeverity| is nonzero, the incoming report didn't get inserted
      99             :   // into the severe list; put it into |recent| for insertion into the recent
     100             :   // list.
     101           0 :   if (severe.mSeverity) {
     102           0 :     MOZ_ASSERT(recent.mSeverity == 0, "recent should be empty here");
     103           0 :     recent = severe;
     104             :   } // else |recent| may hold a report that got knocked out of the severe list.
     105             : 
     106           0 :   if (recent.mSeverity == 0) {
     107             :     // Nothing to be inserted into the recent list.
     108           0 :     return;
     109             :   }
     110             : 
     111             :   // If it wasn't in the "severe" list, add it to the "recent" list.
     112           0 :   for (int i = SEVERITY_MAX_INDEX; i < RECENT_MAX_INDEX; i++) {
     113           0 :     if (mCheckerboardReports[i].mTimestamp >= recent.mTimestamp) {
     114           0 :       continue;
     115             :     }
     116             :     // |recent| needs to be inserted at |i|. Shuffle the remaining ones down
     117             :     // and insert it.
     118           0 :     for (int j = RECENT_MAX_INDEX - 1; j > i; j--) {
     119           0 :       mCheckerboardReports[j] = mCheckerboardReports[j - 1];
     120             :     }
     121           0 :     mCheckerboardReports[i] = recent;
     122           0 :     break;
     123             :   }
     124             : }
     125             : 
     126             : void
     127           0 : CheckerboardEventStorage::GetReports(nsTArray<dom::CheckerboardReport>& aOutReports)
     128             : {
     129           0 :   MOZ_ASSERT(NS_IsMainThread());
     130             : 
     131           0 :   for (int i = 0; i < RECENT_MAX_INDEX; i++) {
     132           0 :     CheckerboardReport& r = mCheckerboardReports[i];
     133           0 :     if (r.mSeverity == 0) {
     134           0 :       continue;
     135             :     }
     136           0 :     dom::CheckerboardReport report;
     137           0 :     report.mSeverity.Construct() = r.mSeverity;
     138           0 :     report.mTimestamp.Construct() = r.mTimestamp / 1000; // micros to millis
     139           0 :     report.mLog.Construct() = NS_ConvertUTF8toUTF16(r.mLog.c_str(), r.mLog.size());
     140           0 :     report.mReason.Construct() = (i < SEVERITY_MAX_INDEX)
     141           0 :         ? dom::CheckerboardReason::Severe
     142             :         : dom::CheckerboardReason::Recent;
     143           0 :     aOutReports.AppendElement(report);
     144             :   }
     145           0 : }
     146             : 
     147             : } // namespace layers
     148             : 
     149             : namespace dom {
     150             : 
     151           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CheckerboardReportService, mParent)
     152           0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CheckerboardReportService, AddRef)
     153           0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CheckerboardReportService, Release)
     154             : 
     155             : /*static*/ bool
     156           0 : CheckerboardReportService::IsEnabled(JSContext* aCtx, JSObject* aGlobal)
     157             : {
     158             :   // Only allow this in the parent process
     159           0 :   if (!XRE_IsParentProcess()) {
     160           0 :     return false;
     161             :   }
     162             :   // Allow privileged code or about:checkerboard (unprivileged) to access this.
     163           0 :   return nsContentUtils::IsSystemCaller(aCtx)
     164           0 :       || nsContentUtils::IsSpecificAboutPage(aGlobal, "about:checkerboard");
     165             : }
     166             : 
     167             : /*static*/ already_AddRefed<CheckerboardReportService>
     168           0 : CheckerboardReportService::Constructor(const dom::GlobalObject& aGlobal, ErrorResult& aRv)
     169             : {
     170           0 :   RefPtr<CheckerboardReportService> ces = new CheckerboardReportService(aGlobal.GetAsSupports());
     171           0 :   return ces.forget();
     172             : }
     173             : 
     174           0 : CheckerboardReportService::CheckerboardReportService(nsISupports* aParent)
     175           0 :   : mParent(aParent)
     176             : {
     177           0 : }
     178             : 
     179             : JSObject*
     180           0 : CheckerboardReportService::WrapObject(JSContext* aCtx, JS::Handle<JSObject*> aGivenProto)
     181             : {
     182           0 :   return CheckerboardReportServiceBinding::Wrap(aCtx, this, aGivenProto);
     183             : }
     184             : 
     185             : nsISupports*
     186           0 : CheckerboardReportService::GetParentObject()
     187             : {
     188           0 :   return mParent;
     189             : }
     190             : 
     191             : void
     192           0 : CheckerboardReportService::GetReports(nsTArray<dom::CheckerboardReport>& aOutReports)
     193             : {
     194             :   RefPtr<mozilla::layers::CheckerboardEventStorage> instance =
     195           0 :       mozilla::layers::CheckerboardEventStorage::GetInstance();
     196           0 :   MOZ_ASSERT(instance);
     197           0 :   instance->GetReports(aOutReports);
     198           0 : }
     199             : 
     200             : bool
     201           0 : CheckerboardReportService::IsRecordingEnabled() const
     202             : {
     203           0 :   return gfxPrefs::APZRecordCheckerboarding();
     204             : }
     205             : 
     206             : void
     207           0 : CheckerboardReportService::SetRecordingEnabled(bool aEnabled)
     208             : {
     209           0 :   gfxPrefs::SetAPZRecordCheckerboarding(aEnabled);
     210           0 : }
     211             : 
     212             : void
     213           0 : CheckerboardReportService::FlushActiveReports()
     214             : {
     215           0 :   MOZ_ASSERT(XRE_IsParentProcess());
     216           0 :   gfx::GPUProcessManager* gpu = gfx::GPUProcessManager::Get();
     217           0 :   if (gpu && gpu->NotifyGpuObservers("APZ:FlushActiveCheckerboard")) {
     218           0 :     return;
     219             :   }
     220             : 
     221           0 :   nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
     222           0 :   MOZ_ASSERT(obsSvc);
     223           0 :   if (obsSvc) {
     224           0 :     obsSvc->NotifyObservers(nullptr, "APZ:FlushActiveCheckerboard", nullptr);
     225             :   }
     226             : }
     227             : 
     228             : } // namespace dom
     229             : } // namespace mozilla

Generated by: LCOV version 1.13