2016-06-09 20:04:42 +03:00
|
|
|
/* -*- 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 "Performance.h"
|
|
|
|
|
|
|
|
#include "GeckoProfiler.h"
|
2017-06-06 06:45:14 +03:00
|
|
|
#include "nsRFPService.h"
|
2016-06-09 20:04:42 +03:00
|
|
|
#include "PerformanceEntry.h"
|
|
|
|
#include "PerformanceMainThread.h"
|
|
|
|
#include "PerformanceMark.h"
|
|
|
|
#include "PerformanceMeasure.h"
|
|
|
|
#include "PerformanceObserver.h"
|
|
|
|
#include "PerformanceResourceTiming.h"
|
2016-11-17 12:00:05 +03:00
|
|
|
#include "PerformanceService.h"
|
2016-06-09 20:04:42 +03:00
|
|
|
#include "PerformanceWorker.h"
|
|
|
|
#include "mozilla/ErrorResult.h"
|
|
|
|
#include "mozilla/dom/PerformanceBinding.h"
|
|
|
|
#include "mozilla/dom/PerformanceEntryEvent.h"
|
|
|
|
#include "mozilla/dom/PerformanceNavigationBinding.h"
|
|
|
|
#include "mozilla/dom/PerformanceObserverBinding.h"
|
2016-04-17 23:03:28 +03:00
|
|
|
#include "mozilla/dom/PerformanceNavigationTiming.h"
|
2016-06-09 20:04:42 +03:00
|
|
|
#include "mozilla/IntegerPrintfMacros.h"
|
|
|
|
#include "mozilla/Preferences.h"
|
2018-01-31 10:24:08 +03:00
|
|
|
#include "mozilla/dom/WorkerPrivate.h"
|
|
|
|
#include "mozilla/dom/WorkerRunnable.h"
|
2016-06-09 20:04:42 +03:00
|
|
|
|
2017-10-04 01:11:18 +03:00
|
|
|
#ifdef MOZ_GECKO_PROFILER
|
|
|
|
#include "ProfilerMarkerPayload.h"
|
|
|
|
#endif
|
|
|
|
|
2016-06-09 20:04:42 +03:00
|
|
|
#define PERFLOG(msg, ...) printf_stderr(msg, ##__VA_ARGS__)
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace dom {
|
|
|
|
|
2017-08-30 02:02:48 +03:00
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Performance)
|
2016-06-09 20:04:42 +03:00
|
|
|
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_INHERITED(Performance,
|
|
|
|
DOMEventTargetHelper,
|
|
|
|
mUserEntries,
|
|
|
|
mResourceEntries);
|
|
|
|
|
|
|
|
NS_IMPL_ADDREF_INHERITED(Performance, DOMEventTargetHelper)
|
|
|
|
NS_IMPL_RELEASE_INHERITED(Performance, DOMEventTargetHelper)
|
|
|
|
|
|
|
|
/* static */ already_AddRefed<Performance>
|
|
|
|
Performance::CreateForMainThread(nsPIDOMWindowInner* aWindow,
|
2018-03-09 18:29:33 +03:00
|
|
|
nsIPrincipal* aPrincipal,
|
2016-06-09 20:04:42 +03:00
|
|
|
nsDOMNavigationTiming* aDOMTiming,
|
2016-12-13 04:27:28 +03:00
|
|
|
nsITimedChannel* aChannel)
|
2016-06-09 20:04:42 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
RefPtr<Performance> performance =
|
2018-06-16 17:21:46 +03:00
|
|
|
new PerformanceMainThread(aWindow,
|
|
|
|
aDOMTiming,
|
|
|
|
aChannel,
|
|
|
|
nsContentUtils::IsSystemPrincipal(aPrincipal));
|
2016-06-09 20:04:42 +03:00
|
|
|
return performance.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ already_AddRefed<Performance>
|
2018-01-31 10:24:08 +03:00
|
|
|
Performance::CreateForWorker(WorkerPrivate* aWorkerPrivate)
|
2016-06-09 20:04:42 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(aWorkerPrivate);
|
|
|
|
aWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
|
|
|
|
RefPtr<Performance> performance = new PerformanceWorker(aWorkerPrivate);
|
|
|
|
return performance.forget();
|
|
|
|
}
|
|
|
|
|
2018-06-16 17:21:46 +03:00
|
|
|
Performance::Performance(bool aSystemPrincipal)
|
2016-06-09 20:04:42 +03:00
|
|
|
: mResourceTimingBufferSize(kDefaultResourceTimingBufferSize)
|
|
|
|
, mPendingNotificationObserversTask(false)
|
2018-06-16 17:21:46 +03:00
|
|
|
, mSystemPrincipal(aSystemPrincipal)
|
2016-06-09 20:04:42 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
}
|
|
|
|
|
2018-06-16 17:21:46 +03:00
|
|
|
Performance::Performance(nsPIDOMWindowInner* aWindow, bool aSystemPrincipal)
|
2016-06-09 20:04:42 +03:00
|
|
|
: DOMEventTargetHelper(aWindow)
|
|
|
|
, mResourceTimingBufferSize(kDefaultResourceTimingBufferSize)
|
|
|
|
, mPendingNotificationObserversTask(false)
|
2018-06-16 17:21:46 +03:00
|
|
|
, mSystemPrincipal(aSystemPrincipal)
|
2016-06-09 20:04:42 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
}
|
|
|
|
|
|
|
|
Performance::~Performance()
|
|
|
|
{}
|
|
|
|
|
2016-12-16 11:07:04 +03:00
|
|
|
DOMHighResTimeStamp
|
2018-03-10 05:12:53 +03:00
|
|
|
Performance::Now()
|
2016-12-16 11:07:04 +03:00
|
|
|
{
|
2018-03-10 05:12:53 +03:00
|
|
|
DOMHighResTimeStamp rawTime = NowUnclamped();
|
2018-03-09 18:29:33 +03:00
|
|
|
if (mSystemPrincipal) {
|
|
|
|
return rawTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
const double maxResolutionMs = 0.020;
|
|
|
|
DOMHighResTimeStamp minimallyClamped = floor(rawTime / maxResolutionMs) * maxResolutionMs;
|
2018-03-13 20:36:34 +03:00
|
|
|
return nsRFPService::ReduceTimePrecisionAsMSecs(minimallyClamped, GetRandomTimelineSeed());
|
2016-12-16 11:07:04 +03:00
|
|
|
}
|
|
|
|
|
2018-03-10 05:12:53 +03:00
|
|
|
DOMHighResTimeStamp
|
|
|
|
Performance::NowUnclamped() const
|
|
|
|
{
|
|
|
|
TimeDuration duration = TimeStamp::Now() - CreationTimeStamp();
|
|
|
|
return duration.ToMilliseconds();
|
|
|
|
}
|
|
|
|
|
2016-11-17 12:00:05 +03:00
|
|
|
DOMHighResTimeStamp
|
|
|
|
Performance::TimeOrigin()
|
|
|
|
{
|
|
|
|
if (!mPerformanceService) {
|
|
|
|
mPerformanceService = PerformanceService::GetOrCreate();
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(mPerformanceService);
|
2018-03-09 18:29:33 +03:00
|
|
|
DOMHighResTimeStamp rawTimeOrigin = mPerformanceService->TimeOrigin(CreationTimeStamp());
|
|
|
|
if (mSystemPrincipal) {
|
|
|
|
return rawTimeOrigin;
|
|
|
|
}
|
|
|
|
|
2018-03-13 20:36:34 +03:00
|
|
|
// Time Origin is an absolute timestamp, so we supply a 0 context mix-in
|
|
|
|
return nsRFPService::ReduceTimePrecisionAsMSecs(rawTimeOrigin, 0);
|
2016-11-17 12:00:05 +03:00
|
|
|
}
|
|
|
|
|
2016-06-09 20:04:42 +03:00
|
|
|
JSObject*
|
|
|
|
Performance::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|
|
|
{
|
2018-06-26 00:20:54 +03:00
|
|
|
return Performance_Binding::Wrap(aCx, this, aGivenProto);
|
2016-06-09 20:04:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::GetEntries(nsTArray<RefPtr<PerformanceEntry>>& aRetval)
|
|
|
|
{
|
2017-06-15 11:48:27 +03:00
|
|
|
// We return an empty list when 'privacy.resistFingerprinting' is on.
|
|
|
|
if (nsContentUtils::ShouldResistFingerprinting()) {
|
|
|
|
aRetval.Clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-06-09 20:04:42 +03:00
|
|
|
aRetval = mResourceEntries;
|
|
|
|
aRetval.AppendElements(mUserEntries);
|
|
|
|
aRetval.Sort(PerformanceEntryComparator());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::GetEntriesByType(const nsAString& aEntryType,
|
|
|
|
nsTArray<RefPtr<PerformanceEntry>>& aRetval)
|
|
|
|
{
|
2017-06-15 11:48:27 +03:00
|
|
|
// We return an empty list when 'privacy.resistFingerprinting' is on.
|
|
|
|
if (nsContentUtils::ShouldResistFingerprinting()) {
|
|
|
|
aRetval.Clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-06-09 20:04:42 +03:00
|
|
|
if (aEntryType.EqualsLiteral("resource")) {
|
|
|
|
aRetval = mResourceEntries;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
aRetval.Clear();
|
|
|
|
|
|
|
|
if (aEntryType.EqualsLiteral("mark") ||
|
|
|
|
aEntryType.EqualsLiteral("measure")) {
|
|
|
|
for (PerformanceEntry* entry : mUserEntries) {
|
|
|
|
if (entry->GetEntryType().Equals(aEntryType)) {
|
|
|
|
aRetval.AppendElement(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::GetEntriesByName(const nsAString& aName,
|
|
|
|
const Optional<nsAString>& aEntryType,
|
|
|
|
nsTArray<RefPtr<PerformanceEntry>>& aRetval)
|
|
|
|
{
|
|
|
|
aRetval.Clear();
|
|
|
|
|
2017-06-15 11:48:27 +03:00
|
|
|
// We return an empty list when 'privacy.resistFingerprinting' is on.
|
|
|
|
if (nsContentUtils::ShouldResistFingerprinting()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-06-09 20:04:42 +03:00
|
|
|
for (PerformanceEntry* entry : mResourceEntries) {
|
|
|
|
if (entry->GetName().Equals(aName) &&
|
|
|
|
(!aEntryType.WasPassed() ||
|
|
|
|
entry->GetEntryType().Equals(aEntryType.Value()))) {
|
|
|
|
aRetval.AppendElement(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (PerformanceEntry* entry : mUserEntries) {
|
|
|
|
if (entry->GetName().Equals(aName) &&
|
|
|
|
(!aEntryType.WasPassed() ||
|
|
|
|
entry->GetEntryType().Equals(aEntryType.Value()))) {
|
|
|
|
aRetval.AppendElement(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
aRetval.Sort(PerformanceEntryComparator());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::ClearUserEntries(const Optional<nsAString>& aEntryName,
|
|
|
|
const nsAString& aEntryType)
|
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < mUserEntries.Length();) {
|
|
|
|
if ((!aEntryName.WasPassed() ||
|
|
|
|
mUserEntries[i]->GetName().Equals(aEntryName.Value())) &&
|
|
|
|
(aEntryType.IsEmpty() ||
|
|
|
|
mUserEntries[i]->GetEntryType().Equals(aEntryType))) {
|
|
|
|
mUserEntries.RemoveElementAt(i);
|
|
|
|
} else {
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::ClearResourceTimings()
|
|
|
|
{
|
|
|
|
mResourceEntries.Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::Mark(const nsAString& aName, ErrorResult& aRv)
|
|
|
|
{
|
2017-06-15 11:48:27 +03:00
|
|
|
// We add nothing when 'privacy.resistFingerprinting' is on.
|
|
|
|
if (nsContentUtils::ShouldResistFingerprinting()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-06-09 20:04:42 +03:00
|
|
|
if (IsPerformanceTimingAttribute(aName)) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<PerformanceMark> performanceMark =
|
2017-07-20 20:05:38 +03:00
|
|
|
new PerformanceMark(GetParentObject(), aName, Now());
|
2016-06-09 20:04:42 +03:00
|
|
|
InsertUserEntry(performanceMark);
|
|
|
|
|
2017-10-04 01:11:18 +03:00
|
|
|
#ifdef MOZ_GECKO_PROFILER
|
2016-06-09 20:04:42 +03:00
|
|
|
if (profiler_is_active()) {
|
2017-06-22 06:40:21 +03:00
|
|
|
profiler_add_marker(
|
2017-06-16 05:26:26 +03:00
|
|
|
"UserTiming",
|
|
|
|
MakeUnique<UserTimingMarkerPayload>(aName, TimeStamp::Now()));
|
2016-06-09 20:04:42 +03:00
|
|
|
}
|
2017-10-04 01:11:18 +03:00
|
|
|
#endif
|
2016-06-09 20:04:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::ClearMarks(const Optional<nsAString>& aName)
|
|
|
|
{
|
|
|
|
ClearUserEntries(aName, NS_LITERAL_STRING("mark"));
|
|
|
|
}
|
|
|
|
|
|
|
|
DOMHighResTimeStamp
|
|
|
|
Performance::ResolveTimestampFromName(const nsAString& aName,
|
2016-11-17 12:00:05 +03:00
|
|
|
ErrorResult& aRv)
|
2016-06-09 20:04:42 +03:00
|
|
|
{
|
|
|
|
AutoTArray<RefPtr<PerformanceEntry>, 1> arr;
|
|
|
|
Optional<nsAString> typeParam;
|
|
|
|
nsAutoString str;
|
|
|
|
str.AssignLiteral("mark");
|
|
|
|
typeParam = &str;
|
|
|
|
GetEntriesByName(aName, typeParam, arr);
|
|
|
|
if (!arr.IsEmpty()) {
|
|
|
|
return arr.LastElement()->StartTime();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IsPerformanceTimingAttribute(aName)) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-09 10:23:44 +03:00
|
|
|
DOMHighResTimeStamp ts = GetPerformanceTimingFromString(aName);
|
2016-06-09 20:04:42 +03:00
|
|
|
if (!ts) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ts - CreationTime();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::Measure(const nsAString& aName,
|
|
|
|
const Optional<nsAString>& aStartMark,
|
|
|
|
const Optional<nsAString>& aEndMark,
|
|
|
|
ErrorResult& aRv)
|
|
|
|
{
|
2017-06-15 11:48:27 +03:00
|
|
|
// We add nothing when 'privacy.resistFingerprinting' is on.
|
|
|
|
if (nsContentUtils::ShouldResistFingerprinting()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-06-09 20:04:42 +03:00
|
|
|
DOMHighResTimeStamp startTime;
|
|
|
|
DOMHighResTimeStamp endTime;
|
|
|
|
|
|
|
|
if (aStartMark.WasPassed()) {
|
|
|
|
startTime = ResolveTimestampFromName(aStartMark.Value(), aRv);
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Navigation start is used in this case, but since DOMHighResTimeStamp is
|
|
|
|
// in relation to navigation start, this will be zero if a name is not
|
|
|
|
// passed.
|
|
|
|
startTime = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aEndMark.WasPassed()) {
|
|
|
|
endTime = ResolveTimestampFromName(aEndMark.Value(), aRv);
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
endTime = Now();
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<PerformanceMeasure> performanceMeasure =
|
2017-07-20 20:05:38 +03:00
|
|
|
new PerformanceMeasure(GetParentObject(), aName, startTime, endTime);
|
2016-06-09 20:04:42 +03:00
|
|
|
InsertUserEntry(performanceMeasure);
|
2017-04-24 18:15:11 +03:00
|
|
|
|
2017-10-04 01:11:18 +03:00
|
|
|
#ifdef MOZ_GECKO_PROFILER
|
2017-04-24 18:15:11 +03:00
|
|
|
if (profiler_is_active()) {
|
|
|
|
TimeStamp startTimeStamp = CreationTimeStamp() +
|
|
|
|
TimeDuration::FromMilliseconds(startTime);
|
|
|
|
TimeStamp endTimeStamp = CreationTimeStamp() +
|
|
|
|
TimeDuration::FromMilliseconds(endTime);
|
2018-03-09 01:36:53 +03:00
|
|
|
|
|
|
|
// Convert to Maybe values so that Optional types do not need to be used in
|
|
|
|
// the profiler.
|
|
|
|
Maybe<nsString> startMark;
|
|
|
|
if (aStartMark.WasPassed()) {
|
|
|
|
startMark.emplace(aStartMark.Value());
|
|
|
|
}
|
|
|
|
Maybe<nsString> endMark;
|
|
|
|
if (aEndMark.WasPassed()) {
|
|
|
|
endMark.emplace(aEndMark.Value());
|
|
|
|
}
|
|
|
|
|
2017-06-22 06:40:21 +03:00
|
|
|
profiler_add_marker(
|
2017-06-16 05:26:26 +03:00
|
|
|
"UserTiming",
|
2018-03-09 01:36:53 +03:00
|
|
|
MakeUnique<UserTimingMarkerPayload>(aName, startMark, endMark,
|
|
|
|
startTimeStamp, endTimeStamp));
|
2017-04-24 18:15:11 +03:00
|
|
|
}
|
2017-10-04 01:11:18 +03:00
|
|
|
#endif
|
2016-06-09 20:04:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::ClearMeasures(const Optional<nsAString>& aName)
|
|
|
|
{
|
|
|
|
ClearUserEntries(aName, NS_LITERAL_STRING("measure"));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::LogEntry(PerformanceEntry* aEntry, const nsACString& aOwner) const
|
|
|
|
{
|
|
|
|
PERFLOG("Performance Entry: %s|%s|%s|%f|%f|%" PRIu64 "\n",
|
|
|
|
aOwner.BeginReading(),
|
|
|
|
NS_ConvertUTF16toUTF8(aEntry->GetEntryType()).get(),
|
|
|
|
NS_ConvertUTF16toUTF8(aEntry->GetName()).get(),
|
|
|
|
aEntry->StartTime(),
|
|
|
|
aEntry->Duration(),
|
|
|
|
static_cast<uint64_t>(PR_Now() / PR_USEC_PER_MSEC));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::TimingNotification(PerformanceEntry* aEntry,
|
|
|
|
const nsACString& aOwner, uint64_t aEpoch)
|
|
|
|
{
|
|
|
|
PerformanceEntryEventInit init;
|
|
|
|
init.mBubbles = false;
|
|
|
|
init.mCancelable = false;
|
|
|
|
init.mName = aEntry->GetName();
|
|
|
|
init.mEntryType = aEntry->GetEntryType();
|
|
|
|
init.mStartTime = aEntry->StartTime();
|
|
|
|
init.mDuration = aEntry->Duration();
|
|
|
|
init.mEpoch = aEpoch;
|
|
|
|
init.mOrigin = NS_ConvertUTF8toUTF16(aOwner.BeginReading());
|
|
|
|
|
|
|
|
RefPtr<PerformanceEntryEvent> perfEntryEvent =
|
|
|
|
PerformanceEntryEvent::Constructor(this, NS_LITERAL_STRING("performanceentry"), init);
|
|
|
|
|
|
|
|
nsCOMPtr<EventTarget> et = do_QueryInterface(GetOwner());
|
|
|
|
if (et) {
|
2018-04-05 20:42:41 +03:00
|
|
|
et->DispatchEvent(*perfEntryEvent);
|
2016-06-09 20:04:42 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::InsertUserEntry(PerformanceEntry* aEntry)
|
|
|
|
{
|
|
|
|
mUserEntries.InsertElementSorted(aEntry,
|
|
|
|
PerformanceEntryComparator());
|
|
|
|
|
|
|
|
QueueEntry(aEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::SetResourceTimingBufferSize(uint64_t aMaxSize)
|
|
|
|
{
|
|
|
|
mResourceTimingBufferSize = aMaxSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::InsertResourceEntry(PerformanceEntry* aEntry)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aEntry);
|
2017-06-15 11:48:27 +03:00
|
|
|
|
|
|
|
// We won't add an entry when 'privacy.resistFingerprint' is true.
|
|
|
|
if (nsContentUtils::ShouldResistFingerprinting()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-24 19:17:32 +03:00
|
|
|
// Don't add the entry if the buffer is full
|
2016-06-09 20:04:42 +03:00
|
|
|
if (mResourceEntries.Length() >= mResourceTimingBufferSize) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mResourceEntries.InsertElementSorted(aEntry,
|
|
|
|
PerformanceEntryComparator());
|
|
|
|
if (mResourceEntries.Length() == mResourceTimingBufferSize) {
|
|
|
|
// call onresourcetimingbufferfull
|
|
|
|
DispatchBufferFullEvent();
|
|
|
|
}
|
|
|
|
QueueEntry(aEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::AddObserver(PerformanceObserver* aObserver)
|
|
|
|
{
|
|
|
|
mObservers.AppendElementUnlessExists(aObserver);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::RemoveObserver(PerformanceObserver* aObserver)
|
|
|
|
{
|
|
|
|
mObservers.RemoveElement(aObserver);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::NotifyObservers()
|
|
|
|
{
|
|
|
|
mPendingNotificationObserversTask = false;
|
|
|
|
NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mObservers,
|
|
|
|
PerformanceObserver,
|
|
|
|
Notify, ());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::CancelNotificationObservers()
|
|
|
|
{
|
|
|
|
mPendingNotificationObserversTask = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
class NotifyObserversTask final : public CancelableRunnable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit NotifyObserversTask(Performance* aPerformance)
|
2017-06-12 22:34:10 +03:00
|
|
|
: CancelableRunnable("dom::NotifyObserversTask")
|
|
|
|
, mPerformance(aPerformance)
|
2016-06-09 20:04:42 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(mPerformance);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD Run() override
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(mPerformance);
|
|
|
|
mPerformance->NotifyObservers();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult Cancel() override
|
|
|
|
{
|
|
|
|
mPerformance->CancelNotificationObservers();
|
|
|
|
mPerformance = nullptr;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
~NotifyObserversTask()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<Performance> mPerformance;
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::RunNotificationObserversTask()
|
|
|
|
{
|
|
|
|
mPendingNotificationObserversTask = true;
|
|
|
|
nsCOMPtr<nsIRunnable> task = new NotifyObserversTask(this);
|
2018-02-08 23:54:00 +03:00
|
|
|
nsresult rv;
|
|
|
|
if (GetOwnerGlobal()) {
|
|
|
|
rv = GetOwnerGlobal()->Dispatch(TaskCategory::Other, task.forget());
|
|
|
|
} else {
|
|
|
|
rv = NS_DispatchToCurrentThread(task);
|
|
|
|
}
|
2016-06-09 20:04:42 +03:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
mPendingNotificationObserversTask = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Performance::QueueEntry(PerformanceEntry* aEntry)
|
|
|
|
{
|
|
|
|
if (mObservers.IsEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mObservers,
|
|
|
|
PerformanceObserver,
|
|
|
|
QueueEntry, (aEntry));
|
|
|
|
|
|
|
|
if (!mPendingNotificationObserversTask) {
|
|
|
|
RunNotificationObserversTask();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-20 13:57:08 +03:00
|
|
|
void
|
|
|
|
Performance::MemoryPressure()
|
|
|
|
{
|
|
|
|
mUserEntries.Clear();
|
|
|
|
}
|
|
|
|
|
2017-07-27 10:05:51 +03:00
|
|
|
size_t
|
|
|
|
Performance::SizeOfUserEntries(mozilla::MallocSizeOf aMallocSizeOf) const
|
|
|
|
{
|
|
|
|
size_t userEntries = 0;
|
|
|
|
for (const PerformanceEntry* entry : mUserEntries) {
|
|
|
|
userEntries += entry->SizeOfIncludingThis(aMallocSizeOf);
|
|
|
|
}
|
|
|
|
return userEntries;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
|
|
|
Performance::SizeOfResourceEntries(mozilla::MallocSizeOf aMallocSizeOf) const
|
|
|
|
{
|
|
|
|
size_t resourceEntries = 0;
|
|
|
|
for (const PerformanceEntry* entry : mResourceEntries) {
|
|
|
|
resourceEntries += entry->SizeOfIncludingThis(aMallocSizeOf);
|
|
|
|
}
|
|
|
|
return resourceEntries;
|
|
|
|
}
|
|
|
|
|
2016-06-09 20:04:42 +03:00
|
|
|
} // dom namespace
|
|
|
|
} // mozilla namespace
|