LCOV - code coverage report
Current view: top level - docshell/base/timeline - ObservedDocShell.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 79 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 5 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "ObservedDocShell.h"
       8             : 
       9             : #include "AbstractTimelineMarker.h"
      10             : #include "LayerTimelineMarker.h"
      11             : #include "MainThreadUtils.h"
      12             : #include "mozilla/Move.h"
      13             : #include "mozilla/AutoRestore.h"
      14             : 
      15             : namespace mozilla {
      16             : 
      17           0 : ObservedDocShell::ObservedDocShell(nsIDocShell* aDocShell)
      18             :   : MarkersStorage("ObservedDocShellMutex")
      19             :   , mDocShell(aDocShell)
      20           0 :   , mPopping(false)
      21             : {
      22           0 :   MOZ_ASSERT(NS_IsMainThread());
      23           0 : }
      24             : 
      25             : void
      26           0 : ObservedDocShell::AddMarker(UniquePtr<AbstractTimelineMarker>&& aMarker)
      27             : {
      28             :   // Only allow main thread markers to go into this list. No need to lock
      29             :   // here since `mTimelineMarkers` will only be accessed or modified on the
      30             :   // main thread only.
      31           0 :   MOZ_ASSERT(NS_IsMainThread());
      32             :   // Don't accept any markers generated by the process of popping
      33             :   // markers.
      34           0 :   if (!mPopping) {
      35           0 :     mTimelineMarkers.AppendElement(Move(aMarker));
      36             :   }
      37           0 : }
      38             : 
      39             : void
      40           0 : ObservedDocShell::AddOTMTMarker(UniquePtr<AbstractTimelineMarker>&& aMarker)
      41             : {
      42             :   // Only allow off the main thread markers to go into this list. Since most
      43             :   // of our markers come from the main thread, be a little more efficient and
      44             :   // avoid dealing with multithreading scenarios until all the markers are
      45             :   // actually cleared or popped in `ClearMarkers` or `PopMarkers`.
      46           0 :   MOZ_ASSERT(!NS_IsMainThread());
      47           0 :   MutexAutoLock lock(GetLock()); // for `mOffTheMainThreadTimelineMarkers`.
      48           0 :   mOffTheMainThreadTimelineMarkers.AppendElement(Move(aMarker));
      49           0 : }
      50             : 
      51             : void
      52           0 : ObservedDocShell::ClearMarkers()
      53             : {
      54           0 :   MOZ_ASSERT(NS_IsMainThread());
      55           0 :   MutexAutoLock lock(GetLock()); // for `mOffTheMainThreadTimelineMarkers`.
      56           0 :   mTimelineMarkers.Clear();
      57           0 :   mOffTheMainThreadTimelineMarkers.Clear();
      58           0 : }
      59             : 
      60             : void
      61           0 : ObservedDocShell::PopMarkers(JSContext* aCx,
      62             :                              nsTArray<dom::ProfileTimelineMarker>& aStore)
      63             : {
      64           0 :   MOZ_ASSERT(NS_IsMainThread());
      65           0 :   MutexAutoLock lock(GetLock()); // for `mOffTheMainThreadTimelineMarkers`.
      66             : 
      67           0 :   MOZ_RELEASE_ASSERT(!mPopping);
      68           0 :   AutoRestore<bool> resetPopping(mPopping);
      69           0 :   mPopping = true;
      70             : 
      71             :   // First, move all of our markers into a single array. We'll chose
      72             :   // the `mTimelineMarkers` store because that's where we expect most of
      73             :   // our markers to be.
      74           0 :   mTimelineMarkers.AppendElements(Move(mOffTheMainThreadTimelineMarkers));
      75             : 
      76             :   // If we see an unpaired START, we keep it around for the next call
      77             :   // to ObservedDocShell::PopMarkers. We store the kept START objects here.
      78           0 :   nsTArray<UniquePtr<AbstractTimelineMarker>> keptStartMarkers;
      79             : 
      80           0 :   for (uint32_t i = 0; i < mTimelineMarkers.Length(); ++i) {
      81           0 :     UniquePtr<AbstractTimelineMarker>& startPayload = mTimelineMarkers.ElementAt(i);
      82             : 
      83             :     // If this is a TIMESTAMP marker, there's no corresponding END,
      84             :     // as it's a single unit of time, not a duration.
      85           0 :     if (startPayload->GetTracingType() == MarkerTracingType::TIMESTAMP) {
      86           0 :       dom::ProfileTimelineMarker* marker = aStore.AppendElement();
      87           0 :       marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName());
      88           0 :       marker->mStart = startPayload->GetTime();
      89           0 :       marker->mEnd = startPayload->GetTime();
      90           0 :       marker->mStack = startPayload->GetStack();
      91           0 :       startPayload->AddDetails(aCx, *marker);
      92           0 :       continue;
      93             :     }
      94             : 
      95             :     // Whenever a START marker is found, look for the corresponding END
      96             :     // and build a {name,start,end} JS object.
      97           0 :     if (startPayload->GetTracingType() == MarkerTracingType::START) {
      98           0 :       bool hasSeenEnd = false;
      99             : 
     100             :       // "Paint" markers are different because painting is handled at root
     101             :       // docshell level. The information that a paint was done is stored at
     102             :       // sub-docshell level, but we can only be sure that a paint did actually
     103             :       // happen in if a "Layer" marker was recorded too.
     104           0 :       bool startIsPaintType = strcmp(startPayload->GetName(), "Paint") == 0;
     105           0 :       bool hasSeenLayerType = false;
     106             : 
     107             :       // If we are processing a "Paint" marker, we append information from
     108             :       // all the embedded "Layer" markers to this array.
     109           0 :       dom::Sequence<dom::ProfileTimelineLayerRect> layerRectangles;
     110             : 
     111             :       // DOM events can be nested, so we must take care when searching
     112             :       // for the matching end. It doesn't hurt to apply this logic to
     113             :       // all event types.
     114           0 :       uint32_t markerDepth = 0;
     115             : 
     116             :       // The assumption is that the devtools timeline flushes markers frequently
     117             :       // enough for the amount of markers to always be small enough that the
     118             :       // nested for loop isn't going to be a performance problem.
     119           0 :       for (uint32_t j = i + 1; j < mTimelineMarkers.Length(); ++j) {
     120           0 :         UniquePtr<AbstractTimelineMarker>& endPayload = mTimelineMarkers.ElementAt(j);
     121           0 :         bool endIsLayerType = strcmp(endPayload->GetName(), "Layer") == 0;
     122             : 
     123             :         // Look for "Layer" markers to stream out "Paint" markers.
     124           0 :         if (startIsPaintType && endIsLayerType) {
     125           0 :           AbstractTimelineMarker* raw = endPayload.get();
     126           0 :           LayerTimelineMarker* layerPayload = static_cast<LayerTimelineMarker*>(raw);
     127           0 :           layerPayload->AddLayerRectangles(layerRectangles);
     128           0 :           hasSeenLayerType = true;
     129             :         }
     130           0 :         if (!startPayload->Equals(*endPayload)) {
     131           0 :           continue;
     132             :         }
     133           0 :         if (endPayload->GetTracingType() == MarkerTracingType::START) {
     134           0 :           ++markerDepth;
     135           0 :           continue;
     136             :         }
     137           0 :         if (endPayload->GetTracingType() == MarkerTracingType::END) {
     138           0 :           if (markerDepth > 0) {
     139           0 :             --markerDepth;
     140           0 :             continue;
     141             :           }
     142           0 :           if (!startIsPaintType || (startIsPaintType && hasSeenLayerType)) {
     143           0 :             dom::ProfileTimelineMarker* marker = aStore.AppendElement();
     144           0 :             marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName());
     145           0 :             marker->mStart = startPayload->GetTime();
     146           0 :             marker->mEnd = endPayload->GetTime();
     147           0 :             marker->mStack = startPayload->GetStack();
     148           0 :             if (hasSeenLayerType) {
     149           0 :               marker->mRectangles.Construct(layerRectangles);
     150             :             }
     151           0 :             startPayload->AddDetails(aCx, *marker);
     152           0 :             endPayload->AddDetails(aCx, *marker);
     153             :           }
     154           0 :           hasSeenEnd = true;
     155           0 :           break;
     156             :         }
     157             :       }
     158             : 
     159             :       // If we did not see the corresponding END, keep the START.
     160           0 :       if (!hasSeenEnd) {
     161           0 :         keptStartMarkers.AppendElement(Move(mTimelineMarkers.ElementAt(i)));
     162           0 :         mTimelineMarkers.RemoveElementAt(i);
     163           0 :         --i;
     164             :       }
     165             :     }
     166             :   }
     167             : 
     168           0 :   mTimelineMarkers.SwapElements(keptStartMarkers);
     169           0 : }
     170             : 
     171             : } // namespace mozilla

Generated by: LCOV version 1.13