Bug 1200119 - Add a way to create usable markers from different threads, r=tromey

This commit is contained in:
Victor Porof 2015-09-11 17:03:06 +02:00
parent bffbe7a3aa
commit d5ee0e4580
10 changed files with 239 additions and 28 deletions

View File

@ -282,7 +282,9 @@ private:
friend void mozilla::TimelineConsumers::AddMarkerForDocShell(
nsDocShell*, const char*, const TimeStamp&, MarkerTracingType);
friend void mozilla::TimelineConsumers::AddMarkerForDocShell(
nsDocShell*, UniquePtr<TimelineMarker>&&);
nsDocShell*, UniquePtr<AbstractTimelineMarker>&&);
friend void mozilla::TimelineConsumers::AddOTMTMarkerForDocShell(
nsDocShell*, UniquePtr<AbstractTimelineMarker>&);
public:
// Tell the favicon service that aNewURI has the same favicon as aOldURI.

View File

@ -28,6 +28,13 @@ AbstractTimelineMarker::AbstractTimelineMarker(const char* aName,
SetCustomTime(aTime);
}
UniquePtr<AbstractTimelineMarker>
AbstractTimelineMarker::Clone()
{
MOZ_ASSERT(false, "Clone method not yet implemented on this marker type.");
return nullptr;
}
AbstractTimelineMarker::~AbstractTimelineMarker()
{
MOZ_COUNT_DTOR(AbstractTimelineMarker);

View File

@ -9,6 +9,7 @@
#include "TimelineMarkerEnums.h" // for MarkerTracingType
#include "nsDOMNavigationTiming.h" // for DOMHighResTimeStamp
#include "mozilla/UniquePtr.h"
struct JSContext;
@ -36,8 +37,11 @@ public:
virtual ~AbstractTimelineMarker();
virtual UniquePtr<AbstractTimelineMarker> Clone();
virtual bool Equals(const AbstractTimelineMarker& aOther) = 0;
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) = 0;
virtual JSObject* GetStack() = 0;
const char* GetName() const { return mName; }
DOMHighResTimeStamp GetTime() const { return mTime; }

View File

@ -0,0 +1,40 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_OTMTMarkerObserver_h_
#define mozilla_OTMTMarkerObserver_h_
#include "mozilla/Mutex.h"
namespace mozilla {
class AbstractTimelineMarker;
class OTMTMarkerReceiver
{
private:
OTMTMarkerReceiver() = delete;
OTMTMarkerReceiver(const OTMTMarkerReceiver& aOther) = delete;
void operator=(const OTMTMarkerReceiver& aOther) = delete;
public:
explicit OTMTMarkerReceiver(const char* aMutexName)
: mLock(aMutexName)
{
}
virtual ~OTMTMarkerReceiver() {}
virtual void AddOTMTMarkerClone(UniquePtr<AbstractTimelineMarker>& aMarker) = 0;
protected:
Mutex& GetLock() { return mLock; };
private:
Mutex mLock;
};
} // namespace mozilla
#endif /* mozilla_OTMTMarkerObserver_h_ */

View File

@ -6,25 +6,40 @@
#include "ObservedDocShell.h"
#include "TimelineMarker.h"
#include "AbstractTimelineMarker.h"
#include "LayerTimelineMarker.h"
#include "MainThreadUtils.h"
#include "mozilla/Move.h"
namespace mozilla {
ObservedDocShell::ObservedDocShell(nsDocShell* aDocShell)
: mDocShell(aDocShell)
{}
: OTMTMarkerReceiver("ObservedDocShellMutex")
, mDocShell(aDocShell)
{
MOZ_ASSERT(NS_IsMainThread());
}
void
ObservedDocShell::AddMarker(UniquePtr<TimelineMarker>&& aMarker)
ObservedDocShell::AddMarker(UniquePtr<AbstractTimelineMarker>&& aMarker)
{
MOZ_ASSERT(NS_IsMainThread());
mTimelineMarkers.AppendElement(Move(aMarker));
}
void
ObservedDocShell::AddOTMTMarkerClone(UniquePtr<AbstractTimelineMarker>& aMarker)
{
MOZ_ASSERT(!NS_IsMainThread());
MutexAutoLock lock(GetLock());
UniquePtr<AbstractTimelineMarker> cloned = aMarker->Clone();
mTimelineMarkers.AppendElement(Move(cloned));
}
void
ObservedDocShell::ClearMarkers()
{
MOZ_ASSERT(NS_IsMainThread());
mTimelineMarkers.Clear();
}
@ -32,12 +47,14 @@ void
ObservedDocShell::PopMarkers(JSContext* aCx,
nsTArray<dom::ProfileTimelineMarker>& aStore)
{
MOZ_ASSERT(NS_IsMainThread());
// If we see an unpaired START, we keep it around for the next call
// to ObservedDocShell::PopMarkers. We store the kept START objects here.
nsTArray<UniquePtr<TimelineMarker>> keptStartMarkers;
nsTArray<UniquePtr<AbstractTimelineMarker>> keptStartMarkers;
for (uint32_t i = 0; i < mTimelineMarkers.Length(); ++i) {
UniquePtr<TimelineMarker>& startPayload = mTimelineMarkers[i];
UniquePtr<AbstractTimelineMarker>& startPayload = mTimelineMarkers[i];
// If this is a TIMESTAMP marker, there's no corresponding END,
// as it's a single unit of time, not a duration.
@ -76,7 +93,7 @@ ObservedDocShell::PopMarkers(JSContext* aCx,
// enough for the amount of markers to always be small enough that the
// nested for loop isn't going to be a performance problem.
for (uint32_t j = i + 1; j < mTimelineMarkers.Length(); ++j) {
UniquePtr<TimelineMarker>& endPayload = mTimelineMarkers[j];
UniquePtr<AbstractTimelineMarker>& endPayload = mTimelineMarkers[j];
bool endIsLayerType = strcmp(endPayload->GetName(), "Layer") == 0;
// Look for "Layer" markers to stream out "Paint" markers.

View File

@ -7,13 +7,14 @@
#ifndef mozilla_ObservedDocShell_h_
#define mozilla_ObservedDocShell_h_
#include "OTMTMarkerReceiver.h"
#include "nsTArray.h"
#include "mozilla/nsRefPtr.h"
class nsDocShell;
namespace mozilla {
class TimelineMarker;
class AbstractTimelineMarker;
namespace dom {
struct ProfileTimelineMarker;
@ -23,17 +24,20 @@ struct ProfileTimelineMarker;
//
// A wrapper around a docshell for which docshell-specific markers are
// allowed to exist. See TimelineConsumers for register/unregister logic.
class ObservedDocShell : public LinkedListElement<ObservedDocShell>
class ObservedDocShell : public LinkedListElement<ObservedDocShell>,
public OTMTMarkerReceiver
{
private:
nsRefPtr<nsDocShell> mDocShell;
nsTArray<UniquePtr<TimelineMarker>> mTimelineMarkers;
nsTArray<UniquePtr<AbstractTimelineMarker>> mTimelineMarkers;
public:
explicit ObservedDocShell(nsDocShell* aDocShell);
nsDocShell* operator*() const { return mDocShell.get(); }
void AddMarker(UniquePtr<TimelineMarker>&& aMarker);
void AddMarker(UniquePtr<AbstractTimelineMarker>&& aMarker);
void AddOTMTMarkerClone(UniquePtr<AbstractTimelineMarker>& aMarker) override;
void ClearMarkers();
void PopMarkers(JSContext* aCx, nsTArray<dom::ProfileTimelineMarker>& aStore);
};

View File

@ -10,6 +10,7 @@ namespace mozilla {
unsigned long TimelineConsumers::sActiveConsumers = 0;
LinkedList<ObservedDocShell>* TimelineConsumers::sObservedDocShells = nullptr;
Mutex* TimelineConsumers::sLock = nullptr;
LinkedList<ObservedDocShell>&
TimelineConsumers::GetOrCreateObservedDocShellsList()
@ -20,9 +21,19 @@ TimelineConsumers::GetOrCreateObservedDocShellsList()
return *sObservedDocShells;
}
Mutex&
TimelineConsumers::GetLock()
{
if (!sLock) {
sLock = new Mutex("TimelineConsumersMutex");
}
return *sLock;
}
void
TimelineConsumers::AddConsumer(nsDocShell* aDocShell)
{
MOZ_ASSERT(NS_IsMainThread());
UniquePtr<ObservedDocShell>& observed = aDocShell->mObserved;
MOZ_ASSERT(!observed);
@ -34,6 +45,7 @@ TimelineConsumers::AddConsumer(nsDocShell* aDocShell)
void
TimelineConsumers::RemoveConsumer(nsDocShell* aDocShell)
{
MOZ_ASSERT(NS_IsMainThread());
UniquePtr<ObservedDocShell>& observed = aDocShell->mObserved;
MOZ_ASSERT(observed);
@ -46,12 +58,14 @@ TimelineConsumers::RemoveConsumer(nsDocShell* aDocShell)
bool
TimelineConsumers::IsEmpty()
{
MOZ_ASSERT(NS_IsMainThread());
return sActiveConsumers == 0;
}
bool
TimelineConsumers::GetKnownDocShells(Vector<nsRefPtr<nsDocShell>>& aStore)
{
MOZ_ASSERT(NS_IsMainThread());
const LinkedList<ObservedDocShell>& docShells = GetOrCreateObservedDocShellsList();
for (const ObservedDocShell* rds = docShells.getFirst();
@ -70,6 +84,7 @@ TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
const char* aName,
MarkerTracingType aTracingType)
{
MOZ_ASSERT(NS_IsMainThread());
if (aDocShell->IsObserved()) {
aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aName, aTracingType)));
}
@ -81,6 +96,7 @@ TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
const TimeStamp& aTime,
MarkerTracingType aTracingType)
{
MOZ_ASSERT(NS_IsMainThread());
if (aDocShell->IsObserved()) {
aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aName, aTime, aTracingType)));
}
@ -88,18 +104,31 @@ TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
void
TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
UniquePtr<TimelineMarker>&& aMarker)
UniquePtr<AbstractTimelineMarker>&& aMarker)
{
MOZ_ASSERT(NS_IsMainThread());
if (aDocShell->IsObserved()) {
aDocShell->mObserved->AddMarker(Move(aMarker));
}
}
void
TimelineConsumers::AddOTMTMarkerForDocShell(nsDocShell* aDocShell,
UniquePtr<AbstractTimelineMarker>& aMarker)
{
MOZ_ASSERT(!NS_IsMainThread());
GetLock().AssertCurrentThreadOwns();
if (aDocShell->IsObserved()) {
aDocShell->mObserved->AddOTMTMarkerClone(aMarker);
}
}
void
TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
const char* aName,
MarkerTracingType aTracingType)
{
MOZ_ASSERT(NS_IsMainThread());
AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aName, aTracingType);
}
@ -109,21 +138,33 @@ TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
const TimeStamp& aTime,
MarkerTracingType aTracingType)
{
MOZ_ASSERT(NS_IsMainThread());
AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aName, aTime, aTracingType);
}
void
TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
UniquePtr<TimelineMarker>&& aMarker)
UniquePtr<AbstractTimelineMarker>&& aMarker)
{
MOZ_ASSERT(NS_IsMainThread());
AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), Move(aMarker));
}
void
TimelineConsumers::AddOTMTMarkerForDocShell(nsIDocShell* aDocShell,
UniquePtr<AbstractTimelineMarker>& aMarker)
{
MOZ_ASSERT(!NS_IsMainThread());
GetLock().AssertCurrentThreadOwns();
AddOTMTMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aMarker);
}
void
TimelineConsumers::AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
const char* aName,
MarkerTracingType aTracingType)
{
MOZ_ASSERT(NS_IsMainThread());
for (Vector<nsRefPtr<nsDocShell>>::Range range = aDocShells.all();
!range.empty();
range.popFront()) {
@ -131,18 +172,88 @@ TimelineConsumers::AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocS
}
}
void
TimelineConsumers::AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
const char* aName,
const TimeStamp& aTime,
MarkerTracingType aTracingType)
{
MOZ_ASSERT(NS_IsMainThread());
for (Vector<nsRefPtr<nsDocShell>>::Range range = aDocShells.all();
!range.empty();
range.popFront()) {
AddMarkerForDocShell(range.front(), aName, aTime, aTracingType);
}
}
void
TimelineConsumers::AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
UniquePtr<AbstractTimelineMarker>& aMarker)
{
MOZ_ASSERT(NS_IsMainThread());
for (Vector<nsRefPtr<nsDocShell>>::Range range = aDocShells.all();
!range.empty();
range.popFront()) {
UniquePtr<AbstractTimelineMarker> cloned = aMarker->Clone();
AddMarkerForDocShell(range.front(), Move(cloned));
}
}
void
TimelineConsumers::AddOTMTMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
UniquePtr<AbstractTimelineMarker>& aMarker)
{
MOZ_ASSERT(!NS_IsMainThread());
GetLock().AssertCurrentThreadOwns();
for (Vector<nsRefPtr<nsDocShell>>::Range range = aDocShells.all();
!range.empty();
range.popFront()) {
AddOTMTMarkerForDocShell(range.front(), aMarker);
}
}
void
TimelineConsumers::AddMarkerForAllObservedDocShells(const char* aName,
MarkerTracingType aTracingType)
{
MOZ_ASSERT(NS_IsMainThread());
Vector<nsRefPtr<nsDocShell>> docShells;
if (!GetKnownDocShells(docShells)) {
// If we don't successfully populate our vector with *all* docshells being
// observed, don't add the marker to *any* of them.
return;
}
if (GetKnownDocShells(docShells)) {
AddMarkerForDocShellsList(docShells, aName, aTracingType);
}
}
void
TimelineConsumers::AddMarkerForAllObservedDocShells(const char* aName,
const TimeStamp& aTime,
MarkerTracingType aTracingType)
{
MOZ_ASSERT(NS_IsMainThread());
Vector<nsRefPtr<nsDocShell>> docShells;
if (GetKnownDocShells(docShells)) {
AddMarkerForDocShellsList(docShells, aName, aTime, aTracingType);
}
}
void
TimelineConsumers::AddMarkerForAllObservedDocShells(UniquePtr<AbstractTimelineMarker>& aMarker)
{
MOZ_ASSERT(NS_IsMainThread());
Vector<nsRefPtr<nsDocShell>> docShells;
if (GetKnownDocShells(docShells)) {
AddMarkerForDocShellsList(docShells, aMarker);
}
}
void
TimelineConsumers::AddOTMTMarkerForAllObservedDocShells(UniquePtr<AbstractTimelineMarker>& aMarker)
{
MOZ_ASSERT(!NS_IsMainThread());
GetLock().AssertCurrentThreadOwns();
Vector<nsRefPtr<nsDocShell>> docShells;
if (GetKnownDocShells(docShells)) {
AddOTMTMarkerForDocShellsList(docShells, aMarker);
}
}
} // namespace mozilla

View File

@ -11,6 +11,7 @@
#include "mozilla/LinkedList.h"
#include "mozilla/Vector.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Mutex.h"
#include "TimelineMarkerEnums.h"
@ -19,7 +20,7 @@ class nsIDocShell;
namespace mozilla {
class ObservedDocShell;
class TimelineMarker;
class AbstractTimelineMarker;
class TimelineConsumers
{
@ -29,7 +30,12 @@ private:
static LinkedList<ObservedDocShell>* sObservedDocShells;
static LinkedList<ObservedDocShell>& GetOrCreateObservedDocShellsList();
// Lock used when adding off-the-main-thread markers.
static Mutex* sLock;
public:
static Mutex& GetLock();
static void AddConsumer(nsDocShell* aDocShell);
static void RemoveConsumer(nsDocShell* aDocShell);
static bool IsEmpty();
@ -65,19 +71,40 @@ public:
// These methods register and receive ownership of an already created marker,
// relevant for a specific docshell.
static void AddMarkerForDocShell(nsDocShell* aDocShell,
UniquePtr<TimelineMarker>&& aMarker);
UniquePtr<AbstractTimelineMarker>&& aMarker);
static void AddMarkerForDocShell(nsIDocShell* aDocShell,
UniquePtr<TimelineMarker>&& aMarker);
UniquePtr<AbstractTimelineMarker>&& aMarker);
// This method creates custom markers, relevant for a list of docshells.
// These methods create or clone markers relevant for a list of docshells.
static void AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
const char* aName,
MarkerTracingType aTracingType);
static void AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
const char* aName,
const TimeStamp& aTime,
MarkerTracingType aTracingType);
static void AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
UniquePtr<AbstractTimelineMarker>& aMarker);
// This method creates custom markers, none of which have to be tied to a
// particular docshell.
// These methods create or clone markers, none of which have to be tied to
// a particular docshell.
static void AddMarkerForAllObservedDocShells(const char* aName,
MarkerTracingType aTracingType);
static void AddMarkerForAllObservedDocShells(const char* aName,
const TimeStamp& aTime,
MarkerTracingType aTracingType);
static void AddMarkerForAllObservedDocShells(UniquePtr<AbstractTimelineMarker>& aMarker);
// Thread-safe versions of the above methods. Need to lock first using
// the mutex returned by `TimelineConsumers::GetLock()`.
static void AddOTMTMarkerForDocShell(nsDocShell* aDocShell,
UniquePtr<AbstractTimelineMarker>& aMarker);
static void AddOTMTMarkerForDocShell(nsIDocShell* aDocShell,
UniquePtr<AbstractTimelineMarker>& aMarker);
static void AddOTMTMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
UniquePtr<AbstractTimelineMarker>& aMarker);
static void AddOTMTMarkerForAllObservedDocShells(UniquePtr<AbstractTimelineMarker>& aMarker);
};
} // namespace mozilla

View File

@ -7,7 +7,6 @@
#ifndef mozilla_TimelineMarker_h_
#define mozilla_TimelineMarker_h_
#include "nsContentUtils.h"
#include "AbstractTimelineMarker.h"
namespace mozilla {
@ -29,8 +28,7 @@ public:
virtual bool Equals(const AbstractTimelineMarker& aOther) override;
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override;
JSObject* GetStack();
virtual JSObject* GetStack() override;
protected:
void CaptureStack();

View File

@ -13,6 +13,7 @@ EXPORTS.mozilla += [
'JavascriptTimelineMarker.h',
'LayerTimelineMarker.h',
'ObservedDocShell.h',
'OTMTMarkerReceiver.h',
'RestyleTimelineMarker.h',
'TimelineConsumers.h',
'TimelineMarker.h',