mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1202657 - Add markers for workers' message passing and serialization/deserialization, r=smaug, jsantell, tromey, ejpbruel
This commit is contained in:
parent
8fc84a1244
commit
306f80152f
@ -30,6 +30,7 @@ marker.label.garbageCollection.nonIncremental=Non-incremental GC
|
||||
marker.label.cycleCollection=Cycle Collection
|
||||
marker.label.cycleCollection.forgetSkippable=CC Graph Reduction
|
||||
marker.label.timestamp=Timestamp
|
||||
marker.label.worker=Worker
|
||||
marker.label.unknown=Unknown
|
||||
|
||||
# LOCALIZATION NOTE (marker.label.javascript.*):
|
||||
@ -75,6 +76,11 @@ marker.field.restyleHint=Restyle Hint:
|
||||
marker.field.causeName=Cause:
|
||||
# General "type" for a marker (Cycle Collection, Garbage Collection)
|
||||
marker.field.type=Type:
|
||||
# The type of operation performed by a Worker.
|
||||
marker.worker.serializeDataOffMainThread=Serialize data in Worker
|
||||
marker.worker.serializeDataOnMainThread=Serialize data on the main thread
|
||||
marker.worker.deserializeDataOffMainThread=Deserialize data in Worker
|
||||
marker.worker.deserializeDataOnMainThread=Deserialize data on the main thread
|
||||
|
||||
# Strings used in the waterfall sidebar as values.
|
||||
marker.value.unknownFrame=<unknown location>
|
||||
|
@ -439,6 +439,13 @@ const Formatters = {
|
||||
[L10N.getStr("marker.field.type")]: marker.name.replace(/nsCycleCollector::/g, "")
|
||||
};
|
||||
},
|
||||
|
||||
WorkerFields: function(marker) {
|
||||
return {
|
||||
[L10N.getStr("marker.field.type")]:
|
||||
L10N.getStr(`marker.worker.${marker.workerOperation}`)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -125,6 +125,12 @@ const TIMELINE_BLUEPRINT = {
|
||||
label: L10N.getStr("marker.label.cycleCollection.forgetSkippable"),
|
||||
fields: Formatters.CycleCollectionFields,
|
||||
},
|
||||
"Worker": {
|
||||
group: 1,
|
||||
colorName: "graphs-orange",
|
||||
label: L10N.getStr("marker.label.worker"),
|
||||
fields: Formatters.WorkerFields
|
||||
},
|
||||
|
||||
/* Group 2 - User Controlled */
|
||||
"ConsoleTime": {
|
||||
|
@ -6,6 +6,8 @@ support-files =
|
||||
doc_innerHTML.html
|
||||
doc_markers.html
|
||||
doc_simple-test.html
|
||||
doc_worker.html
|
||||
js_simpleWorker.js
|
||||
head.js
|
||||
|
||||
[browser_aaa-run-first-leaktest.js]
|
||||
@ -145,3 +147,4 @@ skip-if = true # Bug 1176370
|
||||
skip-if = true # Bug 1170105
|
||||
[browser_timeline-waterfall-sidebar.js]
|
||||
skip-if = true # Bug 1161817
|
||||
[browser_timeline-waterfall-workers.js]
|
||||
|
@ -0,0 +1,78 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests if the sidebar is properly updated with worker markers.
|
||||
*/
|
||||
|
||||
function* spawnTest() {
|
||||
let { panel } = yield initPerformance(WORKER_URL);
|
||||
let { PerformanceController } = panel.panelWin;
|
||||
|
||||
loadFrameScripts();
|
||||
|
||||
yield startRecording(panel);
|
||||
ok(true, "Recording has started.");
|
||||
|
||||
evalInDebuggee("performWork()");
|
||||
|
||||
yield waitUntil(() => {
|
||||
// Wait until we get the worker markers.
|
||||
let markers = PerformanceController.getCurrentRecording().getMarkers();
|
||||
if (!markers.some(m => m.name == "Worker") ||
|
||||
!markers.some(m => m.workerOperation == "serializeDataOffMainThread") ||
|
||||
!markers.some(m => m.workerOperation == "serializeDataOnMainThread") ||
|
||||
!markers.some(m => m.workerOperation == "deserializeDataOffMainThread") ||
|
||||
!markers.some(m => m.workerOperation == "deserializeDataOnMainThread")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
testWorkerMarker(markers.find(m => m.name == "Worker"));
|
||||
return true;
|
||||
});
|
||||
|
||||
yield stopRecording(panel);
|
||||
ok(true, "Recording has ended.");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
||||
|
||||
function testWorkerMarker(marker) {
|
||||
ok(true, "Found a worker marker.");
|
||||
|
||||
ok("start" in marker,
|
||||
"The start time is specified in the worker marker.");
|
||||
ok("end" in marker,
|
||||
"The end time is specified in the worker marker.");
|
||||
ok("workerOperation" in marker,
|
||||
"The worker operation is specified in the worker marker.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a string `script` and evaluates it directly in the content
|
||||
* in potentially a different process.
|
||||
*/
|
||||
function evalInDebuggee (script) {
|
||||
let { generateUUID } = Cc['@mozilla.org/uuid-generator;1'].getService(Ci.nsIUUIDGenerator);
|
||||
let deferred = Promise.defer();
|
||||
|
||||
if (!mm) {
|
||||
throw new Error("`loadFrameScripts()` must be called when using MessageManager.");
|
||||
}
|
||||
|
||||
let id = generateUUID().toString();
|
||||
mm.sendAsyncMessage("devtools:test:eval", { script: script, id: id });
|
||||
mm.addMessageListener("devtools:test:eval:response", handler);
|
||||
|
||||
function handler ({ data }) {
|
||||
if (id !== data.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
mm.removeMessageListener("devtools:test:eval:response", handler);
|
||||
deferred.resolve(data.value);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
26
devtools/client/performance/test/doc_worker.html
Normal file
26
devtools/client/performance/test/doc_worker.html
Normal file
@ -0,0 +1,26 @@
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Performance test page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
function performWork() {
|
||||
var worker = new Worker("js_simpleWorker.js");
|
||||
|
||||
worker.addEventListener("message", function(e) {
|
||||
console.log(e.data);
|
||||
console.timeStamp("Done");
|
||||
}, false);
|
||||
|
||||
worker.postMessage("Hello World");
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -29,6 +29,7 @@ const EXAMPLE_URL = "http://example.com/browser/devtools/client/performance/test
|
||||
const SIMPLE_URL = EXAMPLE_URL + "doc_simple-test.html";
|
||||
const MARKERS_URL = EXAMPLE_URL + "doc_markers.html";
|
||||
const ALLOCS_URL = EXAMPLE_URL + "doc_allocs.html";
|
||||
const WORKER_URL = EXAMPLE_URL + "doc_worker.html";
|
||||
|
||||
const MEMORY_SAMPLE_PROB_PREF = "devtools.performance.memory.sample-probability";
|
||||
const MEMORY_MAX_LOG_LEN_PREF = "devtools.performance.memory.max-log-length";
|
||||
|
4
devtools/client/performance/test/js_simpleWorker.js
Normal file
4
devtools/client/performance/test/js_simpleWorker.js
Normal file
@ -0,0 +1,4 @@
|
||||
self.addEventListener('message', function(e) {
|
||||
self.postMessage(e.data);
|
||||
self.close()
|
||||
}, false);
|
@ -569,6 +569,10 @@ menuitem.marker-color-graphs-yellow:before,
|
||||
.marker-color-graphs-yellow {
|
||||
background-color: var(--theme-graphs-yellow);
|
||||
}
|
||||
menuitem.marker-color-graphs-orange:before,
|
||||
.marker-color-graphs-orange {
|
||||
background-color: var(--theme-graphs-orange);
|
||||
}
|
||||
menuitem.marker-color-graphs-red:before,
|
||||
.marker-color-graphs-red {
|
||||
background-color: var(--theme-graphs-red);
|
||||
|
@ -48,6 +48,7 @@
|
||||
--theme-graphs-bluegrey: #0072ab;
|
||||
--theme-graphs-purple: #b693eb;
|
||||
--theme-graphs-yellow: #efc052;
|
||||
--theme-graphs-orange: #d97e00;
|
||||
--theme-graphs-red: #e57180;
|
||||
--theme-graphs-grey: #cccccc;
|
||||
}
|
||||
@ -86,6 +87,7 @@
|
||||
--theme-graphs-bluegrey: #5e88b0;
|
||||
--theme-graphs-purple: #df80ff;
|
||||
--theme-graphs-yellow: #d99b28;
|
||||
--theme-graphs-orange: #d96629;
|
||||
--theme-graphs-red: #eb5368;
|
||||
--theme-graphs-grey: #757873;
|
||||
}
|
||||
|
@ -840,7 +840,7 @@ nsDocShell::nsDocShell()
|
||||
|
||||
nsDocShell::~nsDocShell()
|
||||
{
|
||||
MOZ_ASSERT(!IsObserved());
|
||||
MOZ_ASSERT(!mObserved);
|
||||
|
||||
Destroy();
|
||||
|
||||
@ -2839,14 +2839,25 @@ NS_IMETHODIMP
|
||||
nsDocShell::SetRecordProfileTimelineMarkers(bool aValue)
|
||||
{
|
||||
bool currentValue = nsIDocShell::GetRecordProfileTimelineMarkers();
|
||||
if (currentValue != aValue) {
|
||||
if (aValue) {
|
||||
TimelineConsumers::AddConsumer(this);
|
||||
UseEntryScriptProfiling();
|
||||
} else {
|
||||
TimelineConsumers::RemoveConsumer(this);
|
||||
UnuseEntryScriptProfiling();
|
||||
}
|
||||
if (currentValue == aValue) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
if (!timelines) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aValue) {
|
||||
MOZ_ASSERT(!timelines->HasConsumer(this));
|
||||
timelines->AddConsumer(this);
|
||||
MOZ_ASSERT(timelines->HasConsumer(this));
|
||||
UseEntryScriptProfiling();
|
||||
} else {
|
||||
MOZ_ASSERT(timelines->HasConsumer(this));
|
||||
timelines->RemoveConsumer(this);
|
||||
MOZ_ASSERT(!timelines->HasConsumer(this));
|
||||
UnuseEntryScriptProfiling();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -2855,7 +2866,7 @@ nsDocShell::SetRecordProfileTimelineMarkers(bool aValue)
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetRecordProfileTimelineMarkers(bool* aValue)
|
||||
{
|
||||
*aValue = IsObserved();
|
||||
*aValue = !!mObserved;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2867,7 +2878,7 @@ nsDocShell::PopProfileTimelineMarkers(
|
||||
nsTArray<dom::ProfileTimelineMarker> store;
|
||||
SequenceRooter<dom::ProfileTimelineMarker> rooter(aCx, &store);
|
||||
|
||||
if (IsObserved()) {
|
||||
if (mObserved) {
|
||||
mObserved->PopMarkers(aCx, store);
|
||||
}
|
||||
|
||||
@ -10650,7 +10661,7 @@ nsDocShell::DoURILoad(nsIURI* aURI,
|
||||
nsCOMPtr<nsICacheInfoChannel> cacheChannel(do_QueryInterface(channel));
|
||||
nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(channel));
|
||||
|
||||
|
||||
|
||||
/* Get the cache Key from SH */
|
||||
nsCOMPtr<nsISupports> cacheKey;
|
||||
if (mLSHE) {
|
||||
@ -10658,7 +10669,7 @@ nsDocShell::DoURILoad(nsIURI* aURI,
|
||||
} else if (mOSHE) { // for reload cases
|
||||
mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
|
||||
}
|
||||
|
||||
|
||||
if (uploadChannel) {
|
||||
// figure out if we need to set the post data stream on the channel...
|
||||
// right now, this is only done for http channels.....
|
||||
@ -10709,7 +10720,7 @@ nsDocShell::DoURILoad(nsIURI* aURI,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (httpChannel) {
|
||||
if (aHeadersData) {
|
||||
rv = AddHeadersToChannel(aHeadersData, httpChannel);
|
||||
@ -13892,26 +13903,30 @@ nsDocShell::NotifyJSRunToCompletionStart(const char* aReason,
|
||||
const char16_t* aFilename,
|
||||
const uint32_t aLineNumber)
|
||||
{
|
||||
bool timelineOn = nsIDocShell::GetRecordProfileTimelineMarkers();
|
||||
|
||||
// If first start, mark interval start.
|
||||
if (timelineOn && mJSRunToCompletionDepth == 0) {
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<JavascriptTimelineMarker>(
|
||||
aReason, aFunctionName, aFilename, aLineNumber, MarkerTracingType::START);
|
||||
TimelineConsumers::AddMarkerForDocShell(this, Move(marker));
|
||||
if (mJSRunToCompletionDepth == 0) {
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
if (timelines && timelines->HasConsumer(this)) {
|
||||
timelines->AddMarkerForDocShell(this, Move(
|
||||
MakeUnique<JavascriptTimelineMarker>(
|
||||
aReason, aFunctionName, aFilename, aLineNumber, MarkerTracingType::START)));
|
||||
}
|
||||
}
|
||||
|
||||
mJSRunToCompletionDepth++;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShell::NotifyJSRunToCompletionStop()
|
||||
{
|
||||
bool timelineOn = nsIDocShell::GetRecordProfileTimelineMarkers();
|
||||
mJSRunToCompletionDepth--;
|
||||
|
||||
// If last stop, mark interval end.
|
||||
mJSRunToCompletionDepth--;
|
||||
if (timelineOn && mJSRunToCompletionDepth == 0) {
|
||||
TimelineConsumers::AddMarkerForDocShell(this, "Javascript", MarkerTracingType::END);
|
||||
if (mJSRunToCompletionDepth == 0) {
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
if (timelines && timelines->HasConsumer(this)) {
|
||||
timelines->AddMarkerForDocShell(this, "Javascript", MarkerTracingType::END);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,7 +275,6 @@ public:
|
||||
private:
|
||||
// An observed docshell wrapper is created when recording markers is enabled.
|
||||
mozilla::UniquePtr<mozilla::ObservedDocShell> mObserved;
|
||||
bool IsObserved() const { return !!mObserved; }
|
||||
|
||||
// It is necessary to allow adding a timeline marker wherever a docshell
|
||||
// instance is available. This operation happens frequently and needs to
|
||||
@ -290,8 +289,6 @@ private:
|
||||
nsDocShell*, const char*, const TimeStamp&, MarkerTracingType);
|
||||
friend void mozilla::TimelineConsumers::AddMarkerForDocShell(
|
||||
nsDocShell*, UniquePtr<AbstractTimelineMarker>&&);
|
||||
friend void mozilla::TimelineConsumers::AddOTMTMarkerForDocShell(
|
||||
nsDocShell*, UniquePtr<AbstractTimelineMarker>&);
|
||||
|
||||
public:
|
||||
// Tell the favicon service that aNewURI has the same favicon as aOldURI.
|
||||
|
@ -35,6 +35,14 @@ AbstractTimelineMarker::Clone()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
AbstractTimelineMarker::Equals(const AbstractTimelineMarker& aOther)
|
||||
{
|
||||
// Check whether two markers should be considered the same, for the purpose
|
||||
// of pairing start and end markers. Normally this definition suffices.
|
||||
return strcmp(mName, aOther.mName) == 0;
|
||||
}
|
||||
|
||||
AbstractTimelineMarker::~AbstractTimelineMarker()
|
||||
{
|
||||
MOZ_COUNT_DTOR(AbstractTimelineMarker);
|
||||
@ -54,4 +62,10 @@ AbstractTimelineMarker::SetCustomTime(const TimeStamp& aTime)
|
||||
mTime = (aTime - TimeStamp::ProcessCreation(isInconsistent)).ToMilliseconds();
|
||||
}
|
||||
|
||||
void
|
||||
AbstractTimelineMarker::SetCustomTime(DOMHighResTimeStamp aTime)
|
||||
{
|
||||
mTime = aTime;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
struct JSContext;
|
||||
class JSObject;
|
||||
|
||||
namespace mozilla {
|
||||
class TimeStamp;
|
||||
@ -28,18 +29,18 @@ private:
|
||||
void operator=(const AbstractTimelineMarker& aOther) = delete;
|
||||
|
||||
public:
|
||||
AbstractTimelineMarker(const char* aName,
|
||||
MarkerTracingType aTracingType);
|
||||
explicit AbstractTimelineMarker(const char* aName,
|
||||
MarkerTracingType aTracingType);
|
||||
|
||||
AbstractTimelineMarker(const char* aName,
|
||||
const TimeStamp& aTime,
|
||||
MarkerTracingType aTracingType);
|
||||
explicit AbstractTimelineMarker(const char* aName,
|
||||
const TimeStamp& aTime,
|
||||
MarkerTracingType aTracingType);
|
||||
|
||||
virtual ~AbstractTimelineMarker();
|
||||
|
||||
virtual UniquePtr<AbstractTimelineMarker> Clone();
|
||||
virtual bool Equals(const AbstractTimelineMarker& aOther);
|
||||
|
||||
virtual bool Equals(const AbstractTimelineMarker& aOther) = 0;
|
||||
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) = 0;
|
||||
virtual JSObject* GetStack() = 0;
|
||||
|
||||
@ -52,8 +53,10 @@ private:
|
||||
DOMHighResTimeStamp mTime;
|
||||
MarkerTracingType mTracingType;
|
||||
|
||||
protected:
|
||||
void SetCurrentTime();
|
||||
void SetCustomTime(const TimeStamp& aTime);
|
||||
void SetCustomTime(DOMHighResTimeStamp aTime);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -4,7 +4,7 @@
|
||||
* 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/. */
|
||||
|
||||
#include "mozilla/AutoGlobalTimelineMarker.h"
|
||||
#include "AutoGlobalTimelineMarker.h"
|
||||
|
||||
#include "TimelineConsumers.h"
|
||||
#include "MainThreadUtils.h"
|
||||
@ -18,20 +18,24 @@ AutoGlobalTimelineMarker::AutoGlobalTimelineMarker(const char* aName
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (TimelineConsumers::IsEmpty()) {
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
if (!timelines || timelines->IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TimelineConsumers::AddMarkerForAllObservedDocShells(mName, MarkerTracingType::START);
|
||||
timelines->AddMarkerForAllObservedDocShells(mName, MarkerTracingType::START);
|
||||
}
|
||||
|
||||
AutoGlobalTimelineMarker::~AutoGlobalTimelineMarker()
|
||||
{
|
||||
if (TimelineConsumers::IsEmpty()) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
if (!timelines || timelines->IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TimelineConsumers::AddMarkerForAllObservedDocShells(mName, MarkerTracingType::END);
|
||||
timelines->AddMarkerForAllObservedDocShells(mName, MarkerTracingType::END);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -8,9 +8,6 @@
|
||||
#define mozilla_AutoGlobalTimelineMarker_h_
|
||||
|
||||
#include "mozilla/GuardObjects.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
class nsDocShell;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -4,11 +4,10 @@
|
||||
* 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/. */
|
||||
|
||||
#include "mozilla/AutoTimelineMarker.h"
|
||||
#include "AutoTimelineMarker.h"
|
||||
|
||||
#include "TimelineConsumers.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "nsDocShell.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -20,21 +19,33 @@ AutoTimelineMarker::AutoTimelineMarker(nsIDocShell* aDocShell, const char* aName
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!aDocShell || TimelineConsumers::IsEmpty()) {
|
||||
if (!aDocShell) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDocShell = static_cast<nsDocShell*>(aDocShell);
|
||||
TimelineConsumers::AddMarkerForDocShell(mDocShell, mName, MarkerTracingType::START);
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
if (!timelines || !timelines->HasConsumer(aDocShell)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDocShell = aDocShell;
|
||||
timelines->AddMarkerForDocShell(mDocShell, mName, MarkerTracingType::START);
|
||||
}
|
||||
|
||||
AutoTimelineMarker::~AutoTimelineMarker()
|
||||
{
|
||||
if (!mDocShell || TimelineConsumers::IsEmpty()) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mDocShell) {
|
||||
return;
|
||||
}
|
||||
|
||||
TimelineConsumers::AddMarkerForDocShell(mDocShell, mName, MarkerTracingType::END);
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
if (!timelines || !timelines->HasConsumer(mDocShell)) {
|
||||
return;
|
||||
}
|
||||
|
||||
timelines->AddMarkerForDocShell(mDocShell, mName, MarkerTracingType::END);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
class nsIDocShell;
|
||||
class nsDocShell;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -36,7 +35,7 @@ class MOZ_RAII AutoTimelineMarker
|
||||
const char* mName;
|
||||
|
||||
// The docshell that is associated with this marker.
|
||||
RefPtr<nsDocShell> mDocShell;
|
||||
RefPtr<nsIDocShell> mDocShell;
|
||||
|
||||
public:
|
||||
explicit AutoTimelineMarker(nsIDocShell* aDocShell, const char* aName
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "TimelineMarker.h"
|
||||
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
|
||||
#include "nsRegion.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -20,9 +21,6 @@ public:
|
||||
, mRegion(aRegion)
|
||||
{}
|
||||
|
||||
~LayerTimelineMarker()
|
||||
{}
|
||||
|
||||
void AddLayerRectangles(dom::Sequence<dom::ProfileTimelineLayerRect>& aRectangles)
|
||||
{
|
||||
nsIntRegionRectIterator it(mRegion);
|
||||
|
29
docshell/base/timeline/MarkersStorage.cpp
Normal file
29
docshell/base/timeline/MarkersStorage.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include "MarkersStorage.h"
|
||||
#include "MainThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MarkersStorage::MarkersStorage(const char* aMutexName)
|
||||
: mLock(aMutexName)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
MarkersStorage::~MarkersStorage()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
Mutex&
|
||||
MarkersStorage::GetLock()
|
||||
{
|
||||
return mLock;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
48
docshell/base/timeline/MarkersStorage.h
Normal file
48
docshell/base/timeline/MarkersStorage.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* -*- 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_MarkersStorage_h_
|
||||
#define mozilla_MarkersStorage_h_
|
||||
|
||||
#include "TimelineMarkerEnums.h" // for MarkerReleaseRequest
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
class AbstractTimelineMarker;
|
||||
|
||||
namespace dom {
|
||||
struct ProfileTimelineMarker;
|
||||
}
|
||||
|
||||
class MarkersStorage : public LinkedListElement<MarkersStorage>
|
||||
{
|
||||
private:
|
||||
MarkersStorage() = delete;
|
||||
MarkersStorage(const MarkersStorage& aOther) = delete;
|
||||
void operator=(const MarkersStorage& aOther) = delete;
|
||||
|
||||
public:
|
||||
explicit MarkersStorage(const char* aMutexName);
|
||||
virtual ~MarkersStorage();
|
||||
|
||||
virtual void AddMarker(UniquePtr<AbstractTimelineMarker>&& aMarker) = 0;
|
||||
virtual void AddOTMTMarker(UniquePtr<AbstractTimelineMarker>&& aMarker) = 0;
|
||||
virtual void ClearMarkers() = 0;
|
||||
virtual void PopMarkers(JSContext* aCx, nsTArray<dom::ProfileTimelineMarker>& aStore) = 0;
|
||||
|
||||
protected:
|
||||
Mutex& GetLock();
|
||||
|
||||
private:
|
||||
Mutex mLock;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_MarkersStorage_h_ */
|
@ -1,40 +0,0 @@
|
||||
/* -*- 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_ */
|
@ -13,8 +13,8 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
ObservedDocShell::ObservedDocShell(nsDocShell* aDocShell)
|
||||
: OTMTMarkerReceiver("ObservedDocShellMutex")
|
||||
ObservedDocShell::ObservedDocShell(nsIDocShell* aDocShell)
|
||||
: MarkersStorage("ObservedDocShellMutex")
|
||||
, mDocShell(aDocShell)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
@ -23,24 +23,31 @@ ObservedDocShell::ObservedDocShell(nsDocShell* aDocShell)
|
||||
void
|
||||
ObservedDocShell::AddMarker(UniquePtr<AbstractTimelineMarker>&& aMarker)
|
||||
{
|
||||
// Only allow main thread markers to go into this list. No need to lock
|
||||
// here since `mTimelineMarkers` will only be accessed or modified on the
|
||||
// main thread only.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mTimelineMarkers.AppendElement(Move(aMarker));
|
||||
}
|
||||
|
||||
void
|
||||
ObservedDocShell::AddOTMTMarkerClone(UniquePtr<AbstractTimelineMarker>& aMarker)
|
||||
ObservedDocShell::AddOTMTMarker(UniquePtr<AbstractTimelineMarker>&& aMarker)
|
||||
{
|
||||
// Only allow off the main thread markers to go into this list. Since most
|
||||
// of our markers come from the main thread, be a little more efficient and
|
||||
// avoid dealing with multithreading scenarios until all the markers are
|
||||
// actually cleared or popped in `ClearMarkers` or `PopMarkers`.
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MutexAutoLock lock(GetLock());
|
||||
UniquePtr<AbstractTimelineMarker> cloned = aMarker->Clone();
|
||||
mTimelineMarkers.AppendElement(Move(cloned));
|
||||
MutexAutoLock lock(GetLock()); // for `mOffTheMainThreadTimelineMarkers`.
|
||||
mOffTheMainThreadTimelineMarkers.AppendElement(Move(aMarker));
|
||||
}
|
||||
|
||||
void
|
||||
ObservedDocShell::ClearMarkers()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MutexAutoLock lock(GetLock()); // for `mOffTheMainThreadTimelineMarkers`.
|
||||
mTimelineMarkers.Clear();
|
||||
mOffTheMainThreadTimelineMarkers.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
@ -48,13 +55,19 @@ ObservedDocShell::PopMarkers(JSContext* aCx,
|
||||
nsTArray<dom::ProfileTimelineMarker>& aStore)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MutexAutoLock lock(GetLock()); // for `mOffTheMainThreadTimelineMarkers`.
|
||||
|
||||
// First, move all of our markers into a single array. We'll chose
|
||||
// the `mTimelineMarkers` store because that's where we expect most of
|
||||
// our markers to be.
|
||||
mTimelineMarkers.AppendElements(Move(mOffTheMainThreadTimelineMarkers));
|
||||
|
||||
// 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<AbstractTimelineMarker>> keptStartMarkers;
|
||||
|
||||
for (uint32_t i = 0; i < mTimelineMarkers.Length(); ++i) {
|
||||
UniquePtr<AbstractTimelineMarker>& startPayload = mTimelineMarkers[i];
|
||||
UniquePtr<AbstractTimelineMarker>& startPayload = mTimelineMarkers.ElementAt(i);
|
||||
|
||||
// If this is a TIMESTAMP marker, there's no corresponding END,
|
||||
// as it's a single unit of time, not a duration.
|
||||
@ -93,12 +106,13 @@ 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<AbstractTimelineMarker>& endPayload = mTimelineMarkers[j];
|
||||
UniquePtr<AbstractTimelineMarker>& endPayload = mTimelineMarkers.ElementAt(j);
|
||||
bool endIsLayerType = strcmp(endPayload->GetName(), "Layer") == 0;
|
||||
|
||||
// Look for "Layer" markers to stream out "Paint" markers.
|
||||
if (startIsPaintType && endIsLayerType) {
|
||||
LayerTimelineMarker* layerPayload = static_cast<LayerTimelineMarker*>(endPayload.get());
|
||||
AbstractTimelineMarker* raw = endPayload.get();
|
||||
LayerTimelineMarker* layerPayload = static_cast<LayerTimelineMarker*>(raw);
|
||||
layerPayload->AddLayerRectangles(layerRectangles);
|
||||
hasSeenLayerType = true;
|
||||
}
|
||||
@ -133,7 +147,7 @@ ObservedDocShell::PopMarkers(JSContext* aCx,
|
||||
|
||||
// If we did not see the corresponding END, keep the START.
|
||||
if (!hasSeenEnd) {
|
||||
keptStartMarkers.AppendElement(Move(mTimelineMarkers[i]));
|
||||
keptStartMarkers.AppendElement(Move(mTimelineMarkers.ElementAt(i)));
|
||||
mTimelineMarkers.RemoveElementAt(i);
|
||||
--i;
|
||||
}
|
||||
|
@ -7,11 +7,12 @@
|
||||
#ifndef mozilla_ObservedDocShell_h_
|
||||
#define mozilla_ObservedDocShell_h_
|
||||
|
||||
#include "OTMTMarkerReceiver.h"
|
||||
#include "nsTArray.h"
|
||||
#include "MarkersStorage.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsDocShell;
|
||||
class nsIDocShell;
|
||||
|
||||
namespace mozilla {
|
||||
class AbstractTimelineMarker;
|
||||
@ -24,22 +25,25 @@ 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>,
|
||||
public OTMTMarkerReceiver
|
||||
class ObservedDocShell : public MarkersStorage
|
||||
{
|
||||
private:
|
||||
RefPtr<nsDocShell> mDocShell;
|
||||
RefPtr<nsIDocShell> mDocShell;
|
||||
|
||||
// Main thread only.
|
||||
nsTArray<UniquePtr<AbstractTimelineMarker>> mTimelineMarkers;
|
||||
|
||||
// Off the main thread only.
|
||||
nsTArray<UniquePtr<AbstractTimelineMarker>> mOffTheMainThreadTimelineMarkers;
|
||||
|
||||
public:
|
||||
explicit ObservedDocShell(nsDocShell* aDocShell);
|
||||
nsDocShell* operator*() const { return mDocShell.get(); }
|
||||
explicit ObservedDocShell(nsIDocShell* aDocShell);
|
||||
nsIDocShell* operator*() const { return mDocShell.get(); }
|
||||
|
||||
void AddMarker(UniquePtr<AbstractTimelineMarker>&& aMarker);
|
||||
void AddOTMTMarkerClone(UniquePtr<AbstractTimelineMarker>& aMarker) override;
|
||||
|
||||
void ClearMarkers();
|
||||
void PopMarkers(JSContext* aCx, nsTArray<dom::ProfileTimelineMarker>& aStore);
|
||||
void AddMarker(UniquePtr<AbstractTimelineMarker>&& aMarker) override;
|
||||
void AddOTMTMarker(UniquePtr<AbstractTimelineMarker>&& aMarker) override;
|
||||
void ClearMarkers() override;
|
||||
void PopMarkers(JSContext* aCx, nsTArray<dom::ProfileTimelineMarker>& aStore) override;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -4,79 +4,174 @@
|
||||
* 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/. */
|
||||
|
||||
#include "mozilla/TimelineConsumers.h"
|
||||
#include "TimelineConsumers.h"
|
||||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "nsAppRunner.h" // for XRE_IsContentProcess, XRE_IsParentProcess
|
||||
#include "nsDocShell.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
unsigned long TimelineConsumers::sActiveConsumers = 0;
|
||||
LinkedList<ObservedDocShell>* TimelineConsumers::sObservedDocShells = nullptr;
|
||||
Mutex* TimelineConsumers::sLock = nullptr;
|
||||
NS_IMPL_ISUPPORTS(TimelineConsumers, nsIObserver);
|
||||
|
||||
LinkedList<ObservedDocShell>&
|
||||
TimelineConsumers::GetOrCreateObservedDocShellsList()
|
||||
StaticMutex TimelineConsumers::sMutex;
|
||||
|
||||
// Manually manage this singleton's lifetime and destroy it before shutdown.
|
||||
// This avoids the leakchecker detecting false-positive memory leaks when
|
||||
// using automatic memory management (i.e. statically instantiating this
|
||||
// singleton inside the `Get` method), which would automatically destroy it on
|
||||
// application shutdown, but too late for the leakchecker. Sigh...
|
||||
StaticRefPtr<TimelineConsumers> TimelineConsumers::sInstance;
|
||||
|
||||
// This flag makes sure the singleton never gets instantiated while a shutdown
|
||||
// is in progress. This can actually happen, and `ClearOnShutdown` doesn't work
|
||||
// in these cases.
|
||||
bool TimelineConsumers::sInShutdown = false;
|
||||
|
||||
already_AddRefed<TimelineConsumers>
|
||||
TimelineConsumers::Get()
|
||||
{
|
||||
if (!sObservedDocShells) {
|
||||
sObservedDocShells = new LinkedList<ObservedDocShell>();
|
||||
// Using this class is not supported yet for other processes other than
|
||||
// parent or content. To avoid accidental checks to methods like `IsEmpty`,
|
||||
// which would probably always be true in those cases, assert here.
|
||||
// Remember, there will be different singletons available to each process.
|
||||
MOZ_ASSERT(XRE_IsContentProcess() || XRE_IsParentProcess());
|
||||
|
||||
// If we are shutting down, don't bother doing anything. Note: we can only
|
||||
// know whether or not we're in shutdown if we're instantiated.
|
||||
if (sInShutdown) {
|
||||
return nullptr;
|
||||
}
|
||||
return *sObservedDocShells;
|
||||
|
||||
// Note: We don't simply check `sInstance` for null-ness here, since otherwise
|
||||
// this can resurrect the TimelineConsumers pretty late during shutdown.
|
||||
// We won't know if we're in shutdown or not though, because the singleton
|
||||
// could have been destroyed or just never instantiated, so in the previous
|
||||
// conditional `sInShutdown` would be false.
|
||||
static bool firstTime = true;
|
||||
if (firstTime) {
|
||||
firstTime = false;
|
||||
|
||||
StaticMutexAutoLock lock(sMutex);
|
||||
sInstance = new TimelineConsumers();
|
||||
|
||||
// Make sure the initialization actually suceeds, otherwise don't allow
|
||||
// access by destroying the instance immediately.
|
||||
if (sInstance->Init()) {
|
||||
ClearOnShutdown(&sInstance);
|
||||
} else {
|
||||
NS_WARNING("TimelineConsumers could not be initialized.");
|
||||
sInstance->RemoveObservers();
|
||||
sInstance = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<TimelineConsumers> copy = sInstance.get();
|
||||
return copy.forget();
|
||||
}
|
||||
|
||||
Mutex&
|
||||
TimelineConsumers::GetLock()
|
||||
bool
|
||||
TimelineConsumers::Init()
|
||||
{
|
||||
if (!sLock) {
|
||||
sLock = new Mutex("TimelineConsumersMutex");
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (!obs) {
|
||||
return false;
|
||||
}
|
||||
return *sLock;
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false)))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TimelineConsumers::RemoveObservers()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (!obs) {
|
||||
return false;
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TimelineConsumers::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
|
||||
sInShutdown = true;
|
||||
RemoveObservers();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false, "TimelineConsumers got unexpected topic!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
TimelineConsumers::TimelineConsumers()
|
||||
: mActiveConsumers(0)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
TimelineConsumers::AddConsumer(nsDocShell* aDocShell)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
UniquePtr<ObservedDocShell>& observed = aDocShell->mObserved;
|
||||
StaticMutexAutoLock lock(sMutex); // for `mActiveConsumers` and `mMarkersStores`.
|
||||
|
||||
UniquePtr<ObservedDocShell>& observed = aDocShell->mObserved;
|
||||
MOZ_ASSERT(!observed);
|
||||
sActiveConsumers++;
|
||||
observed.reset(new ObservedDocShell(aDocShell));
|
||||
GetOrCreateObservedDocShellsList().insertFront(observed.get());
|
||||
|
||||
mActiveConsumers++;
|
||||
|
||||
ObservedDocShell* obsDocShell = new ObservedDocShell(aDocShell);
|
||||
MarkersStorage* storage = static_cast<MarkersStorage*>(obsDocShell);
|
||||
|
||||
observed.reset(obsDocShell);
|
||||
mMarkersStores.insertFront(storage);
|
||||
}
|
||||
|
||||
void
|
||||
TimelineConsumers::RemoveConsumer(nsDocShell* aDocShell)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
UniquePtr<ObservedDocShell>& observed = aDocShell->mObserved;
|
||||
StaticMutexAutoLock lock(sMutex); // for `mActiveConsumers` and `mMarkersStores`.
|
||||
|
||||
UniquePtr<ObservedDocShell>& observed = aDocShell->mObserved;
|
||||
MOZ_ASSERT(observed);
|
||||
sActiveConsumers--;
|
||||
|
||||
mActiveConsumers--;
|
||||
|
||||
// Clear all markers from the `mTimelineMarkers` store.
|
||||
observed.get()->ClearMarkers();
|
||||
// Remove self from the `mMarkersStores` store.
|
||||
observed.get()->remove();
|
||||
// Prepare for becoming a consumer later.
|
||||
observed.reset(nullptr);
|
||||
}
|
||||
|
||||
bool
|
||||
TimelineConsumers::HasConsumer(nsIDocShell* aDocShell)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!aDocShell) {
|
||||
return false;
|
||||
}
|
||||
bool isTimelineRecording = false;
|
||||
aDocShell->GetRecordProfileTimelineMarkers(&isTimelineRecording);
|
||||
return isTimelineRecording;
|
||||
}
|
||||
|
||||
bool
|
||||
TimelineConsumers::IsEmpty()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return sActiveConsumers == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
TimelineConsumers::GetKnownDocShells(Vector<RefPtr<nsDocShell>>& aStore)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
const LinkedList<ObservedDocShell>& docShells = GetOrCreateObservedDocShellsList();
|
||||
|
||||
for (const ObservedDocShell* rds = docShells.getFirst();
|
||||
rds != nullptr;
|
||||
rds = rds->getNext()) {
|
||||
if (!aStore.append(**rds)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
StaticMutexAutoLock lock(sMutex); // for `mActiveConsumers`.
|
||||
return mActiveConsumers == 0;
|
||||
}
|
||||
|
||||
void
|
||||
@ -85,7 +180,7 @@ TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
|
||||
MarkerTracingType aTracingType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (aDocShell->IsObserved()) {
|
||||
if (HasConsumer(aDocShell)) {
|
||||
aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aName, aTracingType)));
|
||||
}
|
||||
}
|
||||
@ -97,7 +192,7 @@ TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
|
||||
MarkerTracingType aTracingType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (aDocShell->IsObserved()) {
|
||||
if (HasConsumer(aDocShell)) {
|
||||
aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aName, aTime, aTracingType)));
|
||||
}
|
||||
}
|
||||
@ -107,22 +202,11 @@ TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
|
||||
UniquePtr<AbstractTimelineMarker>&& aMarker)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (aDocShell->IsObserved()) {
|
||||
if (HasConsumer(aDocShell)) {
|
||||
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,
|
||||
@ -150,76 +234,23 @@ TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
|
||||
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<RefPtr<nsDocShell>>& aDocShells,
|
||||
const char* aName,
|
||||
MarkerTracingType aTracingType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
for (Vector<RefPtr<nsDocShell>>::Range range = aDocShells.all();
|
||||
!range.empty();
|
||||
range.popFront()) {
|
||||
AddMarkerForDocShell(range.front(), aName, aTracingType);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TimelineConsumers::AddMarkerForDocShellsList(Vector<RefPtr<nsDocShell>>& aDocShells,
|
||||
const char* aName,
|
||||
const TimeStamp& aTime,
|
||||
MarkerTracingType aTracingType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
for (Vector<RefPtr<nsDocShell>>::Range range = aDocShells.all();
|
||||
!range.empty();
|
||||
range.popFront()) {
|
||||
AddMarkerForDocShell(range.front(), aName, aTime, aTracingType);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TimelineConsumers::AddMarkerForDocShellsList(Vector<RefPtr<nsDocShell>>& aDocShells,
|
||||
UniquePtr<AbstractTimelineMarker>& aMarker)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
for (Vector<RefPtr<nsDocShell>>::Range range = aDocShells.all();
|
||||
!range.empty();
|
||||
range.popFront()) {
|
||||
UniquePtr<AbstractTimelineMarker> cloned = aMarker->Clone();
|
||||
AddMarkerForDocShell(range.front(), Move(cloned));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TimelineConsumers::AddOTMTMarkerForDocShellsList(Vector<RefPtr<nsDocShell>>& aDocShells,
|
||||
UniquePtr<AbstractTimelineMarker>& aMarker)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
GetLock().AssertCurrentThreadOwns();
|
||||
for (Vector<RefPtr<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<RefPtr<nsDocShell>> docShells;
|
||||
if (GetKnownDocShells(docShells)) {
|
||||
AddMarkerForDocShellsList(docShells, aName, aTracingType);
|
||||
bool isMainThread = NS_IsMainThread();
|
||||
StaticMutexAutoLock lock(sMutex); // for `mMarkersStores`.
|
||||
|
||||
for (MarkersStorage* storage = mMarkersStores.getFirst();
|
||||
storage != nullptr;
|
||||
storage = storage->getNext()) {
|
||||
UniquePtr<AbstractTimelineMarker> marker =
|
||||
MakeUnique<TimelineMarker>(aName, aTracingType);
|
||||
if (isMainThread) {
|
||||
storage->AddMarker(Move(marker));
|
||||
} else {
|
||||
storage->AddOTMTMarker(Move(marker));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,31 +259,37 @@ TimelineConsumers::AddMarkerForAllObservedDocShells(const char* aName,
|
||||
const TimeStamp& aTime,
|
||||
MarkerTracingType aTracingType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
Vector<RefPtr<nsDocShell>> docShells;
|
||||
if (GetKnownDocShells(docShells)) {
|
||||
AddMarkerForDocShellsList(docShells, aName, aTime, aTracingType);
|
||||
bool isMainThread = NS_IsMainThread();
|
||||
StaticMutexAutoLock lock(sMutex); // for `mMarkersStores`.
|
||||
|
||||
for (MarkersStorage* storage = mMarkersStores.getFirst();
|
||||
storage != nullptr;
|
||||
storage = storage->getNext()) {
|
||||
UniquePtr<AbstractTimelineMarker> marker =
|
||||
MakeUnique<TimelineMarker>(aName, aTime, aTracingType);
|
||||
if (isMainThread) {
|
||||
storage->AddMarker(Move(marker));
|
||||
} else {
|
||||
storage->AddOTMTMarker(Move(marker));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TimelineConsumers::AddMarkerForAllObservedDocShells(UniquePtr<AbstractTimelineMarker>& aMarker)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
Vector<RefPtr<nsDocShell>> docShells;
|
||||
if (GetKnownDocShells(docShells)) {
|
||||
AddMarkerForDocShellsList(docShells, aMarker);
|
||||
}
|
||||
}
|
||||
bool isMainThread = NS_IsMainThread();
|
||||
StaticMutexAutoLock lock(sMutex); // for `mMarkersStores`.
|
||||
|
||||
void
|
||||
TimelineConsumers::AddOTMTMarkerForAllObservedDocShells(UniquePtr<AbstractTimelineMarker>& aMarker)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
GetLock().AssertCurrentThreadOwns();
|
||||
Vector<RefPtr<nsDocShell>> docShells;
|
||||
if (GetKnownDocShells(docShells)) {
|
||||
AddOTMTMarkerForDocShellsList(docShells, aMarker);
|
||||
for (MarkersStorage* storage = mMarkersStores.getFirst();
|
||||
storage != nullptr;
|
||||
storage = storage->getNext()) {
|
||||
UniquePtr<AbstractTimelineMarker> clone = aMarker->Clone();
|
||||
if (isMainThread) {
|
||||
storage->AddMarker(Move(clone));
|
||||
} else {
|
||||
storage->AddOTMTMarker(Move(clone));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* -*- 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
|
||||
@ -7,104 +6,113 @@
|
||||
#ifndef mozilla_TimelineConsumers_h_
|
||||
#define mozilla_TimelineConsumers_h_
|
||||
|
||||
#include "nsIObserver.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/Vector.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
#include "TimelineMarkerEnums.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "TimelineMarkerEnums.h" // for MarkerTracingType
|
||||
|
||||
class nsDocShell;
|
||||
class nsIDocShell;
|
||||
|
||||
namespace mozilla {
|
||||
class ObservedDocShell;
|
||||
class TimeStamp;
|
||||
class MarkersStorage;
|
||||
class AbstractTimelineMarker;
|
||||
|
||||
class TimelineConsumers
|
||||
class TimelineConsumers : public nsIObserver
|
||||
{
|
||||
private:
|
||||
// Counter for how many timelines are currently interested in markers.
|
||||
static unsigned long sActiveConsumers;
|
||||
static LinkedList<ObservedDocShell>* sObservedDocShells;
|
||||
static LinkedList<ObservedDocShell>& GetOrCreateObservedDocShellsList();
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
// Lock used when adding off-the-main-thread markers.
|
||||
static Mutex* sLock;
|
||||
private:
|
||||
TimelineConsumers();
|
||||
TimelineConsumers(const TimelineConsumers& aOther) = delete;
|
||||
void operator=(const TimelineConsumers& aOther) = delete;
|
||||
virtual ~TimelineConsumers() = default;
|
||||
|
||||
bool Init();
|
||||
bool RemoveObservers();
|
||||
|
||||
public:
|
||||
static Mutex& GetLock();
|
||||
static already_AddRefed<TimelineConsumers> Get();
|
||||
|
||||
static void AddConsumer(nsDocShell* aDocShell);
|
||||
static void RemoveConsumer(nsDocShell* aDocShell);
|
||||
static bool IsEmpty();
|
||||
static bool GetKnownDocShells(Vector<RefPtr<nsDocShell>>& aStore);
|
||||
// Methods for registering interested consumers (i.e. "devtools toolboxes").
|
||||
// Each consumer should be directly focused on a particular docshell, but
|
||||
// timeline markers don't necessarily have to be tied to that docshell.
|
||||
// See the public `AddMarker*` methods below.
|
||||
// Main thread only.
|
||||
void AddConsumer(nsDocShell* aDocShell);
|
||||
void RemoveConsumer(nsDocShell* aDocShell);
|
||||
|
||||
bool HasConsumer(nsIDocShell* aDocShell);
|
||||
|
||||
// Checks if there's any existing interested consumer.
|
||||
// May be called from any thread.
|
||||
bool IsEmpty();
|
||||
|
||||
// Methods for adding markers relevant for particular docshells, or generic
|
||||
// (meaning that they either can't be tied to a particular docshell, or one
|
||||
// wasn't accessible in the part of the codebase where they're instantiated).
|
||||
|
||||
// These will only add markers if at least one docshell is currently being
|
||||
// observed by a timeline. Markers tied to a particular docshell won't be
|
||||
// created unless that docshell is specifically being currently observed.
|
||||
// See nsIDocShell::recordProfileTimelineMarkers
|
||||
|
||||
// These methods create a custom marker from a name and some metadata,
|
||||
// These methods create a basic TimelineMarker from a name and some metadata,
|
||||
// relevant for a specific docshell.
|
||||
static void AddMarkerForDocShell(nsDocShell* aDocShell,
|
||||
const char* aName,
|
||||
MarkerTracingType aTracingType);
|
||||
static void AddMarkerForDocShell(nsIDocShell* aDocShell,
|
||||
const char* aName,
|
||||
MarkerTracingType aTracingType);
|
||||
// Main thread only.
|
||||
void AddMarkerForDocShell(nsDocShell* aDocShell,
|
||||
const char* aName,
|
||||
MarkerTracingType aTracingType);
|
||||
void AddMarkerForDocShell(nsIDocShell* aDocShell,
|
||||
const char* aName,
|
||||
MarkerTracingType aTracingType);
|
||||
|
||||
static void AddMarkerForDocShell(nsDocShell* aDocShell,
|
||||
const char* aName,
|
||||
const TimeStamp& aTime,
|
||||
MarkerTracingType aTracingType);
|
||||
static void AddMarkerForDocShell(nsIDocShell* aDocShell,
|
||||
const char* aName,
|
||||
const TimeStamp& aTime,
|
||||
MarkerTracingType aTracingType);
|
||||
void AddMarkerForDocShell(nsDocShell* aDocShell,
|
||||
const char* aName,
|
||||
const TimeStamp& aTime,
|
||||
MarkerTracingType aTracingType);
|
||||
void AddMarkerForDocShell(nsIDocShell* aDocShell,
|
||||
const char* aName,
|
||||
const TimeStamp& aTime,
|
||||
MarkerTracingType aTracingType);
|
||||
|
||||
// These methods register and receive ownership of an already created marker,
|
||||
// relevant for a specific docshell.
|
||||
static void AddMarkerForDocShell(nsDocShell* aDocShell,
|
||||
UniquePtr<AbstractTimelineMarker>&& aMarker);
|
||||
static void AddMarkerForDocShell(nsIDocShell* aDocShell,
|
||||
UniquePtr<AbstractTimelineMarker>&& aMarker);
|
||||
// Main thread only.
|
||||
void AddMarkerForDocShell(nsDocShell* aDocShell,
|
||||
UniquePtr<AbstractTimelineMarker>&& aMarker);
|
||||
void AddMarkerForDocShell(nsIDocShell* aDocShell,
|
||||
UniquePtr<AbstractTimelineMarker>&& aMarker);
|
||||
|
||||
// These methods create or clone markers relevant for a list of docshells.
|
||||
static void AddMarkerForDocShellsList(Vector<RefPtr<nsDocShell>>& aDocShells,
|
||||
const char* aName,
|
||||
// These methods create a basic marker from a name and some metadata,
|
||||
// which doesn't have to be relevant to a specific docshell.
|
||||
// May be called from any thread.
|
||||
void AddMarkerForAllObservedDocShells(const char* aName,
|
||||
MarkerTracingType aTracingType);
|
||||
static void AddMarkerForDocShellsList(Vector<RefPtr<nsDocShell>>& aDocShells,
|
||||
const char* aName,
|
||||
void AddMarkerForAllObservedDocShells(const char* aName,
|
||||
const TimeStamp& aTime,
|
||||
MarkerTracingType aTracingType);
|
||||
static void AddMarkerForDocShellsList(Vector<RefPtr<nsDocShell>>& aDocShells,
|
||||
UniquePtr<AbstractTimelineMarker>& aMarker);
|
||||
|
||||
// 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);
|
||||
// This method clones and registers an already instantiated marker,
|
||||
// which doesn't have to be relevant to a specific docshell.
|
||||
// May be called from any thread.
|
||||
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<RefPtr<nsDocShell>>& aDocShells,
|
||||
UniquePtr<AbstractTimelineMarker>& aMarker);
|
||||
static void AddOTMTMarkerForAllObservedDocShells(UniquePtr<AbstractTimelineMarker>& aMarker);
|
||||
private:
|
||||
static StaticRefPtr<TimelineConsumers> sInstance;
|
||||
static bool sInShutdown;
|
||||
|
||||
// Counter for how many timelines are currently interested in markers,
|
||||
// and a list of the MarkersStorage interfaces representing them.
|
||||
unsigned long mActiveConsumers;
|
||||
LinkedList<MarkersStorage> mMarkersStores;
|
||||
|
||||
// Protects this class's data structures.
|
||||
static StaticMutex sMutex;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -25,14 +25,6 @@ TimelineMarker::TimelineMarker(const char* aName,
|
||||
CaptureStackIfNecessary(aTracingType, aStackRequest);
|
||||
}
|
||||
|
||||
bool
|
||||
TimelineMarker::Equals(const AbstractTimelineMarker& aOther)
|
||||
{
|
||||
// Check whether two markers should be considered the same, for the purpose
|
||||
// of pairing start and end markers. Normally this definition suffices.
|
||||
return strcmp(GetName(), aOther.GetName()) == 0;
|
||||
}
|
||||
|
||||
void
|
||||
TimelineMarker::AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker)
|
||||
{
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define mozilla_TimelineMarker_h_
|
||||
|
||||
#include "AbstractTimelineMarker.h"
|
||||
#include "js/RootingAPI.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -17,16 +18,15 @@ namespace mozilla {
|
||||
class TimelineMarker : public AbstractTimelineMarker
|
||||
{
|
||||
public:
|
||||
TimelineMarker(const char* aName,
|
||||
MarkerTracingType aTracingType,
|
||||
MarkerStackRequest aStackRequest = MarkerStackRequest::STACK);
|
||||
explicit TimelineMarker(const char* aName,
|
||||
MarkerTracingType aTracingType,
|
||||
MarkerStackRequest aStackRequest = MarkerStackRequest::STACK);
|
||||
|
||||
TimelineMarker(const char* aName,
|
||||
const TimeStamp& aTime,
|
||||
MarkerTracingType aTracingType,
|
||||
MarkerStackRequest aStackRequest = MarkerStackRequest::STACK);
|
||||
explicit TimelineMarker(const char* aName,
|
||||
const TimeStamp& aTime,
|
||||
MarkerTracingType aTracingType,
|
||||
MarkerStackRequest aStackRequest = MarkerStackRequest::STACK);
|
||||
|
||||
virtual bool Equals(const AbstractTimelineMarker& aOther) override;
|
||||
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override;
|
||||
virtual JSObject* GetStack() override;
|
||||
|
||||
|
44
docshell/base/timeline/WorkerTimelineMarker.h
Normal file
44
docshell/base/timeline/WorkerTimelineMarker.h
Normal file
@ -0,0 +1,44 @@
|
||||
/* -*- 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_WorkerTimelineMarker_h_
|
||||
#define mozilla_WorkerTimelineMarker_h_
|
||||
|
||||
#include "TimelineMarker.h"
|
||||
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class WorkerTimelineMarker : public TimelineMarker
|
||||
{
|
||||
public:
|
||||
explicit WorkerTimelineMarker(ProfileTimelineWorkerOperationType aOperationType,
|
||||
MarkerTracingType aTracingType)
|
||||
: TimelineMarker("Worker", aTracingType, MarkerStackRequest::NO_STACK)
|
||||
, mOperationType(aOperationType)
|
||||
{}
|
||||
|
||||
virtual UniquePtr<AbstractTimelineMarker> Clone() override
|
||||
{
|
||||
WorkerTimelineMarker* clone = new WorkerTimelineMarker(mOperationType, GetTracingType());
|
||||
clone->SetCustomTime(GetTime());
|
||||
return UniquePtr<AbstractTimelineMarker>(clone);
|
||||
}
|
||||
|
||||
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
|
||||
{
|
||||
if (GetTracingType() == MarkerTracingType::START) {
|
||||
aMarker.mWorkerOperation.Construct(mOperationType);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ProfileTimelineWorkerOperationType mOperationType;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_WorkerTimelineMarker_h_ */
|
@ -12,19 +12,21 @@ EXPORTS.mozilla += [
|
||||
'EventTimelineMarker.h',
|
||||
'JavascriptTimelineMarker.h',
|
||||
'LayerTimelineMarker.h',
|
||||
'MarkersStorage.h',
|
||||
'ObservedDocShell.h',
|
||||
'OTMTMarkerReceiver.h',
|
||||
'RestyleTimelineMarker.h',
|
||||
'TimelineConsumers.h',
|
||||
'TimelineMarker.h',
|
||||
'TimelineMarkerEnums.h',
|
||||
'TimestampTimelineMarker.h',
|
||||
'WorkerTimelineMarker.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AbstractTimelineMarker.cpp',
|
||||
'AutoGlobalTimelineMarker.cpp',
|
||||
'AutoTimelineMarker.cpp',
|
||||
'MarkersStorage.cpp',
|
||||
'ObservedDocShell.cpp',
|
||||
'TimelineConsumers.cpp',
|
||||
'TimelineMarker.cpp',
|
||||
|
@ -105,6 +105,7 @@ var TESTS = [{
|
||||
content.console.timeStamp(undefined);
|
||||
},
|
||||
check: function (markers) {
|
||||
markers = markers.filter(e => e.name != "Worker");
|
||||
is(markers.length, 4, "Got 4 markers");
|
||||
is(markers[0].name, "TimeStamp", "Got Timestamp marker");
|
||||
is(markers[0].causeName, "paper", "Got Timestamp label value");
|
||||
|
@ -1065,42 +1065,41 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
|
||||
|
||||
callData->mMonotonicTimer = performance->Now();
|
||||
|
||||
// 'time' and 'timeEnd' are displayed in the devtools timeline if active.
|
||||
bool isTimelineRecording = false;
|
||||
nsDocShell* docShell = static_cast<nsDocShell*>(mWindow->GetDocShell());
|
||||
if (docShell) {
|
||||
docShell->GetRecordProfileTimelineMarkers(&isTimelineRecording);
|
||||
}
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
bool isTimelineRecording = timelines && timelines->HasConsumer(docShell);
|
||||
|
||||
// 'timeStamp' recordings do not need an argument; use empty string
|
||||
// if no arguments passed in
|
||||
// The 'timeStamp' recordings do not need an argument; use empty string
|
||||
// if no arguments passed in.
|
||||
if (isTimelineRecording && aMethodName == MethodTimeStamp) {
|
||||
JS::Rooted<JS::Value> value(aCx, aData.Length() == 0 ?
|
||||
JS_GetEmptyStringValue(aCx) : aData[0]);
|
||||
JS::Rooted<JS::Value> value(aCx, aData.Length() == 0
|
||||
? JS_GetEmptyStringValue(aCx)
|
||||
: aData[0]);
|
||||
JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
|
||||
|
||||
nsAutoJSString key;
|
||||
if (jsString) {
|
||||
key.init(aCx, jsString);
|
||||
}
|
||||
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<TimestampTimelineMarker>(key);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
|
||||
timelines->AddMarkerForDocShell(docShell, Move(
|
||||
MakeUnique<TimestampTimelineMarker>(key)));
|
||||
}
|
||||
// For `console.time(foo)` and `console.timeEnd(foo)`
|
||||
// For `console.time(foo)` and `console.timeEnd(foo)`.
|
||||
else if (isTimelineRecording && aData.Length() == 1) {
|
||||
JS::Rooted<JS::Value> value(aCx, aData[0]);
|
||||
JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
|
||||
|
||||
if (jsString) {
|
||||
nsAutoJSString key;
|
||||
if (key.init(aCx, jsString)) {
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<ConsoleTimelineMarker>(
|
||||
key, aMethodName == MethodTime ? MarkerTracingType::START
|
||||
: MarkerTracingType::END);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
|
||||
timelines->AddMarkerForDocShell(docShell, Move(
|
||||
MakeUnique<ConsoleTimelineMarker>(
|
||||
key, aMethodName == MethodTime ? MarkerTracingType::START
|
||||
: MarkerTracingType::END)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
@ -1114,35 +1114,35 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
|
||||
|
||||
// Maybe add a marker to the docshell's timeline, but only
|
||||
// bother with all the logic if some docshell is recording.
|
||||
nsCOMPtr<nsIDocShell> docShell;
|
||||
bool isTimelineRecording = false;
|
||||
nsDocShell* docShell;
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
bool needsEndEventMarker = false;
|
||||
|
||||
if (mIsMainThreadELM &&
|
||||
!TimelineConsumers::IsEmpty() &&
|
||||
listener->mListenerType != Listener::eNativeListener) {
|
||||
docShell = GetDocShellForTarget();
|
||||
if (docShell) {
|
||||
docShell->GetRecordProfileTimelineMarkers(&isTimelineRecording);
|
||||
}
|
||||
if (isTimelineRecording) {
|
||||
nsDocShell* ds = static_cast<nsDocShell*>(docShell.get());
|
||||
nsAutoString typeStr;
|
||||
(*aDOMEvent)->GetType(typeStr);
|
||||
uint16_t phase;
|
||||
(*aDOMEvent)->GetEventPhase(&phase);
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<EventTimelineMarker>(
|
||||
typeStr, phase, MarkerTracingType::START);
|
||||
TimelineConsumers::AddMarkerForDocShell(ds, Move(marker));
|
||||
nsCOMPtr<nsIDocShell> docShellComPtr = GetDocShellForTarget();
|
||||
if (docShellComPtr) {
|
||||
docShell = static_cast<nsDocShell*>(docShellComPtr.get());
|
||||
if (timelines && timelines->HasConsumer(docShell)) {
|
||||
needsEndEventMarker = true;
|
||||
nsAutoString typeStr;
|
||||
(*aDOMEvent)->GetType(typeStr);
|
||||
uint16_t phase;
|
||||
(*aDOMEvent)->GetEventPhase(&phase);
|
||||
timelines->AddMarkerForDocShell(docShell, Move(
|
||||
MakeUnique<EventTimelineMarker>(
|
||||
typeStr, phase, MarkerTracingType::START)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(HandleEventSubType(listener, *aDOMEvent,
|
||||
aCurrentTarget))) {
|
||||
if (NS_FAILED(HandleEventSubType(listener, *aDOMEvent, aCurrentTarget))) {
|
||||
aEvent->mFlags.mExceptionHasBeenRisen = true;
|
||||
}
|
||||
|
||||
if (isTimelineRecording) {
|
||||
nsDocShell* ds = static_cast<nsDocShell*>(docShell.get());
|
||||
TimelineConsumers::AddMarkerForDocShell(ds, "DOMEvent", MarkerTracingType::END);
|
||||
if (needsEndEventMarker) {
|
||||
timelines->AddMarkerForDocShell(
|
||||
docShell, "DOMEvent", MarkerTracingType::END);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2975,15 +2975,20 @@ void
|
||||
TabChild::DidRequestComposite(const TimeStamp& aCompositeReqStart,
|
||||
const TimeStamp& aCompositeReqEnd)
|
||||
{
|
||||
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
|
||||
if (!docShell) {
|
||||
nsCOMPtr<nsIDocShell> docShellComPtr = do_GetInterface(WebNavigation());
|
||||
if (!docShellComPtr) {
|
||||
return;
|
||||
}
|
||||
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell.get(),
|
||||
"CompositeForwardTransaction", aCompositeReqStart, MarkerTracingType::START);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell.get(),
|
||||
"CompositeForwardTransaction", aCompositeReqEnd, MarkerTracingType::END);
|
||||
nsDocShell* docShell = static_cast<nsDocShell*>(docShellComPtr.get());
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
|
||||
if (timelines && timelines->HasConsumer(docShell)) {
|
||||
timelines->AddMarkerForDocShell(docShell,
|
||||
"CompositeForwardTransaction", aCompositeReqStart, MarkerTracingType::START);
|
||||
timelines->AddMarkerForDocShell(docShell,
|
||||
"CompositeForwardTransaction", aCompositeReqEnd, MarkerTracingType::END);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -25,20 +25,35 @@ dictionary ProfileTimelineLayerRect {
|
||||
long height = 0;
|
||||
};
|
||||
|
||||
enum ProfileTimelineWorkerOperationType {
|
||||
"serializeDataOffMainThread",
|
||||
"serializeDataOnMainThread",
|
||||
"deserializeDataOffMainThread",
|
||||
"deserializeDataOnMainThread",
|
||||
};
|
||||
|
||||
dictionary ProfileTimelineMarker {
|
||||
DOMString name = "";
|
||||
DOMHighResTimeStamp start = 0;
|
||||
DOMHighResTimeStamp end = 0;
|
||||
object? stack = null;
|
||||
|
||||
/* For ConsoleTime, Timestamp and Javascript markers. */
|
||||
DOMString causeName;
|
||||
|
||||
/* For ConsoleTime markers. */
|
||||
object? endStack = null;
|
||||
|
||||
/* For DOMEvent markers. */
|
||||
DOMString type;
|
||||
unsigned short eventPhase;
|
||||
|
||||
/* For Paint markers. */
|
||||
sequence<ProfileTimelineLayerRect> rectangles;
|
||||
|
||||
/* For Style markers. */
|
||||
DOMString restyleHint;
|
||||
|
||||
/* For Worker markers. */
|
||||
ProfileTimelineWorkerOperationType workerOperation;
|
||||
};
|
||||
|
@ -65,6 +65,8 @@
|
||||
#include "mozilla/dom/WorkerGlobalScopeBinding.h"
|
||||
#include "mozilla/dom/indexedDB/IDBFactory.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/TimelineConsumers.h"
|
||||
#include "mozilla/WorkerTimelineMarker.h"
|
||||
#include "nsAlgorithm.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCycleCollector.h"
|
||||
@ -638,7 +640,30 @@ public:
|
||||
|
||||
JS::Rooted<JS::Value> messageData(aCx);
|
||||
ErrorResult rv;
|
||||
|
||||
UniquePtr<AbstractTimelineMarker> start;
|
||||
UniquePtr<AbstractTimelineMarker> end;
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
bool isTimelineRecording = timelines && !timelines->IsEmpty();
|
||||
|
||||
if (isTimelineRecording) {
|
||||
start = MakeUnique<WorkerTimelineMarker>(aIsMainThread
|
||||
? ProfileTimelineWorkerOperationType::DeserializeDataOnMainThread
|
||||
: ProfileTimelineWorkerOperationType::DeserializeDataOffMainThread,
|
||||
MarkerTracingType::START);
|
||||
}
|
||||
|
||||
Read(parent, aCx, &messageData, rv);
|
||||
|
||||
if (isTimelineRecording) {
|
||||
end = MakeUnique<WorkerTimelineMarker>(aIsMainThread
|
||||
? ProfileTimelineWorkerOperationType::DeserializeDataOnMainThread
|
||||
: ProfileTimelineWorkerOperationType::DeserializeDataOffMainThread,
|
||||
MarkerTracingType::END);
|
||||
timelines->AddMarkerForAllObservedDocShells(start);
|
||||
timelines->AddMarkerForAllObservedDocShells(end);
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
xpc::Throw(aCx, rv.StealNSResult());
|
||||
return false;
|
||||
@ -2796,7 +2821,29 @@ WorkerPrivateParent<Derived>::PostMessageInternal(
|
||||
new MessageEventRunnable(ParentAsWorkerPrivate(),
|
||||
WorkerRunnable::WorkerThreadModifyBusyCount);
|
||||
|
||||
UniquePtr<AbstractTimelineMarker> start;
|
||||
UniquePtr<AbstractTimelineMarker> end;
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
bool isTimelineRecording = timelines && !timelines->IsEmpty();
|
||||
|
||||
if (isTimelineRecording) {
|
||||
start = MakeUnique<WorkerTimelineMarker>(NS_IsMainThread()
|
||||
? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
|
||||
: ProfileTimelineWorkerOperationType::SerializeDataOffMainThread,
|
||||
MarkerTracingType::START);
|
||||
}
|
||||
|
||||
runnable->Write(aCx, aMessage, transferable, aRv);
|
||||
|
||||
if (isTimelineRecording) {
|
||||
end = MakeUnique<WorkerTimelineMarker>(NS_IsMainThread()
|
||||
? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
|
||||
: ProfileTimelineWorkerOperationType::SerializeDataOffMainThread,
|
||||
MarkerTracingType::END);
|
||||
timelines->AddMarkerForAllObservedDocShells(start);
|
||||
timelines->AddMarkerForAllObservedDocShells(end);
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
@ -5385,7 +5432,29 @@ WorkerPrivate::PostMessageToParentInternal(
|
||||
new MessageEventRunnable(this,
|
||||
WorkerRunnable::ParentThreadUnchangedBusyCount);
|
||||
|
||||
UniquePtr<AbstractTimelineMarker> start;
|
||||
UniquePtr<AbstractTimelineMarker> end;
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
bool isTimelineRecording = timelines && !timelines->IsEmpty();
|
||||
|
||||
if (isTimelineRecording) {
|
||||
start = MakeUnique<WorkerTimelineMarker>(NS_IsMainThread()
|
||||
? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
|
||||
: ProfileTimelineWorkerOperationType::SerializeDataOffMainThread,
|
||||
MarkerTracingType::START);
|
||||
}
|
||||
|
||||
runnable->Write(aCx, aMessage, transferable, aRv);
|
||||
|
||||
if (isTimelineRecording) {
|
||||
end = MakeUnique<WorkerTimelineMarker>(NS_IsMainThread()
|
||||
? ProfileTimelineWorkerOperationType::SerializeDataOnMainThread
|
||||
: ProfileTimelineWorkerOperationType::SerializeDataOffMainThread,
|
||||
MarkerTracingType::END);
|
||||
timelines->AddMarkerForAllObservedDocShells(start);
|
||||
timelines->AddMarkerForAllObservedDocShells(end);
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
@ -5919,11 +5919,11 @@ FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
|
||||
|
||||
if (presContext && presContext->GetDocShell() && isActiveLayerManager) {
|
||||
nsDocShell* docShell = static_cast<nsDocShell*>(presContext->GetDocShell());
|
||||
bool isRecording;
|
||||
docShell->GetRecordProfileTimelineMarkers(&isRecording);
|
||||
if (isRecording) {
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<LayerTimelineMarker>(aRegionToDraw);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
|
||||
if (timelines && timelines->HasConsumer(docShell)) {
|
||||
timelines->AddMarkerForDocShell(docShell, Move(
|
||||
MakeUnique<LayerTimelineMarker>(aRegionToDraw)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,12 +218,9 @@ RestyleTracker::DoProcessRestyles()
|
||||
PROFILER_LABEL_PRINTF("RestyleTracker", "ProcessRestyles",
|
||||
js::ProfileEntry::Category::CSS, "(%s)", docURL.get());
|
||||
|
||||
bool isTimelineRecording = false;
|
||||
nsDocShell* docShell =
|
||||
static_cast<nsDocShell*>(mRestyleManager->PresContext()->GetDocShell());
|
||||
if (docShell) {
|
||||
docShell->GetRecordProfileTimelineMarkers(&isTimelineRecording);
|
||||
}
|
||||
nsDocShell* docShell = static_cast<nsDocShell*>(mRestyleManager->PresContext()->GetDocShell());
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
bool isTimelineRecording = timelines && timelines->HasConsumer(docShell);
|
||||
|
||||
// Create a AnimationsWithDestroyedFrame during restyling process to
|
||||
// stop animations on elements that have no frame at the end of the
|
||||
@ -341,9 +338,9 @@ RestyleTracker::DoProcessRestyles()
|
||||
}
|
||||
|
||||
if (isTimelineRecording) {
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<RestyleTimelineMarker>(
|
||||
data->mRestyleHint, MarkerTracingType::START);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
|
||||
timelines->AddMarkerForDocShell(docShell, Move(
|
||||
MakeUnique<RestyleTimelineMarker>(
|
||||
data->mRestyleHint, MarkerTracingType::START)));
|
||||
}
|
||||
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API)
|
||||
@ -357,9 +354,9 @@ RestyleTracker::DoProcessRestyles()
|
||||
AddRestyleRootsIfAwaitingRestyle(data->mDescendants);
|
||||
|
||||
if (isTimelineRecording) {
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<RestyleTimelineMarker>(
|
||||
data->mRestyleHint, MarkerTracingType::END);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
|
||||
timelines->AddMarkerForDocShell(docShell, Move(
|
||||
MakeUnique<RestyleTimelineMarker>(
|
||||
data->mRestyleHint, MarkerTracingType::END)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -402,9 +399,9 @@ RestyleTracker::DoProcessRestyles()
|
||||
}
|
||||
#endif
|
||||
if (isTimelineRecording) {
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<RestyleTimelineMarker>(
|
||||
currentRestyle->mRestyleHint, MarkerTracingType::START);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
|
||||
timelines->AddMarkerForDocShell(docShell, Move(
|
||||
MakeUnique<RestyleTimelineMarker>(
|
||||
currentRestyle->mRestyleHint, MarkerTracingType::START)));
|
||||
}
|
||||
|
||||
ProcessOneRestyle(currentRestyle->mElement,
|
||||
@ -413,9 +410,9 @@ RestyleTracker::DoProcessRestyles()
|
||||
currentRestyle->mRestyleHintData);
|
||||
|
||||
if (isTimelineRecording) {
|
||||
UniquePtr<TimelineMarker> marker = MakeUnique<RestyleTimelineMarker>(
|
||||
currentRestyle->mRestyleHint, MarkerTracingType::END);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
|
||||
timelines->AddMarkerForDocShell(docShell, Move(
|
||||
MakeUnique<RestyleTimelineMarker>(
|
||||
currentRestyle->mRestyleHint, MarkerTracingType::END)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8970,8 +8970,11 @@ PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
|
||||
js::ProfileEntry::Category::GRAPHICS, "(%s)", docURL.get());
|
||||
|
||||
nsDocShell* docShell = static_cast<nsDocShell*>(GetPresContext()->GetDocShell());
|
||||
if (docShell) {
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, "Reflow", MarkerTracingType::START);
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
bool isTimelineRecording = timelines && timelines->HasConsumer(docShell);
|
||||
|
||||
if (isTimelineRecording) {
|
||||
timelines->AddMarkerForDocShell(docShell, "Reflow", MarkerTracingType::START);
|
||||
}
|
||||
|
||||
if (mReflowContinueTimer) {
|
||||
@ -9148,9 +9151,10 @@ PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
|
||||
tp->Accumulate();
|
||||
}
|
||||
|
||||
if (docShell) {
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, "Reflow", MarkerTracingType::END);
|
||||
if (isTimelineRecording) {
|
||||
timelines->AddMarkerForDocShell(docShell, "Reflow", MarkerTracingType::END);
|
||||
}
|
||||
|
||||
return !interrupted;
|
||||
}
|
||||
|
||||
|
@ -1266,13 +1266,20 @@ HasPendingAnimations(nsIPresShell* aShell)
|
||||
static void GetProfileTimelineSubDocShells(nsDocShell* aRootDocShell,
|
||||
nsTArray<nsDocShell*>& aShells)
|
||||
{
|
||||
if (!aRootDocShell || TimelineConsumers::IsEmpty()) {
|
||||
if (!aRootDocShell) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
if (!timelines || timelines->IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> enumerator;
|
||||
nsresult rv = aRootDocShell->GetDocShellEnumerator(nsIDocShellTreeItem::typeAll,
|
||||
nsIDocShell::ENUMERATE_BACKWARDS, getter_AddRefs(enumerator));
|
||||
nsresult rv = aRootDocShell->GetDocShellEnumerator(
|
||||
nsIDocShellTreeItem::typeAll,
|
||||
nsIDocShell::ENUMERATE_BACKWARDS,
|
||||
getter_AddRefs(enumerator));
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
@ -1682,13 +1689,18 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
||||
mPresShellsToInvalidateIfHidden.Clear();
|
||||
|
||||
if (mViewManagerFlushIsPending) {
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
|
||||
nsTArray<nsDocShell*> profilingDocShells;
|
||||
GetProfileTimelineSubDocShells(GetDocShell(mPresContext), profilingDocShells);
|
||||
for (nsDocShell* docShell : profilingDocShells) {
|
||||
// For the sake of the profile timeline's simplicity, this is flagged as
|
||||
// paint even if it includes creating display lists
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, "Paint", MarkerTracingType::START);
|
||||
MOZ_ASSERT(timelines);
|
||||
MOZ_ASSERT(timelines->HasConsumer(docShell));
|
||||
timelines->AddMarkerForDocShell(docShell, "Paint", MarkerTracingType::START);
|
||||
}
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
|
||||
printf_stderr("Starting ProcessPendingUpdates\n");
|
||||
@ -1698,13 +1710,17 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
||||
mViewManagerFlushIsPending = false;
|
||||
RefPtr<nsViewManager> vm = mPresContext->GetPresShell()->GetViewManager();
|
||||
vm->ProcessPendingUpdates();
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
|
||||
printf_stderr("Ending ProcessPendingUpdates\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
for (nsDocShell* docShell : profilingDocShells) {
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell, "Paint", MarkerTracingType::END);
|
||||
MOZ_ASSERT(timelines);
|
||||
MOZ_ASSERT(timelines->HasConsumer(docShell));
|
||||
timelines->AddMarkerForDocShell(docShell, "Paint", MarkerTracingType::END);
|
||||
}
|
||||
|
||||
if (nsContentUtils::XPConnect()) {
|
||||
|
@ -62,9 +62,9 @@ nsView::~nsView()
|
||||
if (mViewManager)
|
||||
{
|
||||
DropMouseGrabbing();
|
||||
|
||||
|
||||
nsView *rootView = mViewManager->GetRootView();
|
||||
|
||||
|
||||
if (rootView)
|
||||
{
|
||||
// Root views can have parents!
|
||||
@ -83,7 +83,7 @@ nsView::~nsView()
|
||||
{
|
||||
mParent->RemoveChild(this);
|
||||
}
|
||||
|
||||
|
||||
mViewManager = nullptr;
|
||||
}
|
||||
else if (mParent)
|
||||
@ -126,7 +126,7 @@ void nsView::DestroyWidget()
|
||||
// If we are not attached to a base window, we're going to tear down our
|
||||
// widget here. However, if we're attached to somebody elses widget, we
|
||||
// want to leave the widget alone: don't reset the client data or call
|
||||
// Destroy. Just clear our event view ptr and free our reference to it.
|
||||
// Destroy. Just clear our event view ptr and free our reference to it.
|
||||
if (mWidgetIsTopLevel) {
|
||||
mWindow->SetAttachedWidgetListener(nullptr);
|
||||
}
|
||||
@ -589,7 +589,7 @@ nsresult nsView::CreateWidget(nsWidgetInitData *aWidgetInitData,
|
||||
if (!mWindow) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
InitializeWindow(aEnableDragDrop, aResetVisibility);
|
||||
|
||||
return NS_OK;
|
||||
@ -672,7 +672,7 @@ nsView::InitializeWindow(bool aEnableDragDrop, bool aResetVisibility)
|
||||
if (aEnableDragDrop) {
|
||||
mWindow->EnableDragDrop(true);
|
||||
}
|
||||
|
||||
|
||||
// propagate the z-index to the widget.
|
||||
UpdateNativeWidgetZIndexes(this, FindNonAutoZIndex(this));
|
||||
|
||||
@ -725,7 +725,7 @@ nsresult nsView::AttachToTopLevelWidget(nsIWidget* aWidget)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Detach this view from an attached widget.
|
||||
// Detach this view from an attached widget.
|
||||
nsresult nsView::DetachFromTopLevelWidget()
|
||||
{
|
||||
NS_PRECONDITION(mWidgetIsTopLevel, "Not attached currently!");
|
||||
@ -747,7 +747,7 @@ nsresult nsView::DetachFromTopLevelWidget()
|
||||
mWindow = nullptr;
|
||||
|
||||
mWidgetIsTopLevel = false;
|
||||
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -756,7 +756,7 @@ void nsView::SetZIndex(bool aAuto, int32_t aZIndex)
|
||||
bool oldIsAuto = GetZIndexIsAuto();
|
||||
mVFlags = (mVFlags & ~NS_VIEW_FLAG_AUTO_ZINDEX) | (aAuto ? NS_VIEW_FLAG_AUTO_ZINDEX : 0);
|
||||
mZIndex = aZIndex;
|
||||
|
||||
|
||||
if (HasWidget() || !oldIsAuto || !aAuto) {
|
||||
UpdateNativeWidgetZIndexes(this, FindNonAutoZIndex(this));
|
||||
}
|
||||
@ -1094,11 +1094,14 @@ nsView::DidCompositeWindow(const TimeStamp& aCompositeStart,
|
||||
}
|
||||
|
||||
nsIDocShell* docShell = context->GetDocShell();
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell,
|
||||
"Composite", aCompositeStart, MarkerTracingType::START);
|
||||
TimelineConsumers::AddMarkerForDocShell(docShell,
|
||||
"Composite", aCompositeEnd, MarkerTracingType::END);
|
||||
if (timelines && timelines->HasConsumer(docShell)) {
|
||||
timelines->AddMarkerForDocShell(docShell,
|
||||
"Composite", aCompositeStart, MarkerTracingType::START);
|
||||
timelines->AddMarkerForDocShell(docShell,
|
||||
"Composite", aCompositeEnd, MarkerTracingType::END);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user