Bug 1820813 - Keep an unclamped startTime inside PerformanceMark and use it for profiler markers r=sefeng
Differential Revision: https://phabricator.services.mozilla.com/D173002
This commit is contained in:
@@ -394,7 +394,7 @@ bool Performance::IsPerformanceTimingAttribute(const nsAString& aName) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DOMHighResTimeStamp Performance::ConvertMarkToTimestampWithString(
|
DOMHighResTimeStamp Performance::ConvertMarkToTimestampWithString(
|
||||||
const nsAString& aName, ErrorResult& aRv) {
|
const nsAString& aName, ErrorResult& aRv, bool aReturnUnclamped) {
|
||||||
if (IsPerformanceTimingAttribute(aName)) {
|
if (IsPerformanceTimingAttribute(aName)) {
|
||||||
return ConvertNameToTimestamp(aName, aRv);
|
return ConvertNameToTimestamp(aName, aRv);
|
||||||
}
|
}
|
||||||
@@ -406,6 +406,9 @@ DOMHighResTimeStamp Performance::ConvertMarkToTimestampWithString(
|
|||||||
typeParam = &str;
|
typeParam = &str;
|
||||||
GetEntriesByName(aName, typeParam, arr);
|
GetEntriesByName(aName, typeParam, arr);
|
||||||
if (!arr.IsEmpty()) {
|
if (!arr.IsEmpty()) {
|
||||||
|
if (aReturnUnclamped) {
|
||||||
|
return arr.LastElement()->UnclampedStartTime();
|
||||||
|
}
|
||||||
return arr.LastElement()->StartTime();
|
return arr.LastElement()->StartTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -441,10 +444,11 @@ DOMHighResTimeStamp Performance::ConvertMarkToTimestampWithDOMHighResTimeStamp(
|
|||||||
|
|
||||||
DOMHighResTimeStamp Performance::ConvertMarkToTimestamp(
|
DOMHighResTimeStamp Performance::ConvertMarkToTimestamp(
|
||||||
const ResolveTimestampAttribute aAttribute,
|
const ResolveTimestampAttribute aAttribute,
|
||||||
const OwningStringOrDouble& aMarkNameOrTimestamp, ErrorResult& aRv) {
|
const OwningStringOrDouble& aMarkNameOrTimestamp, ErrorResult& aRv,
|
||||||
|
bool aReturnUnclamped) {
|
||||||
if (aMarkNameOrTimestamp.IsString()) {
|
if (aMarkNameOrTimestamp.IsString()) {
|
||||||
return ConvertMarkToTimestampWithString(aMarkNameOrTimestamp.GetAsString(),
|
return ConvertMarkToTimestampWithString(aMarkNameOrTimestamp.GetAsString(),
|
||||||
aRv);
|
aRv, aReturnUnclamped);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ConvertMarkToTimestampWithDOMHighResTimeStamp(
|
return ConvertMarkToTimestampWithDOMHighResTimeStamp(
|
||||||
@@ -486,17 +490,21 @@ DOMHighResTimeStamp Performance::ConvertNameToTimestamp(const nsAString& aName,
|
|||||||
|
|
||||||
DOMHighResTimeStamp Performance::ResolveEndTimeForMeasure(
|
DOMHighResTimeStamp Performance::ResolveEndTimeForMeasure(
|
||||||
const Optional<nsAString>& aEndMark,
|
const Optional<nsAString>& aEndMark,
|
||||||
const Maybe<const PerformanceMeasureOptions&>& aOptions, ErrorResult& aRv) {
|
const Maybe<const PerformanceMeasureOptions&>& aOptions, ErrorResult& aRv,
|
||||||
|
bool aReturnUnclamped) {
|
||||||
DOMHighResTimeStamp endTime;
|
DOMHighResTimeStamp endTime;
|
||||||
if (aEndMark.WasPassed()) {
|
if (aEndMark.WasPassed()) {
|
||||||
endTime = ConvertMarkToTimestampWithString(aEndMark.Value(), aRv);
|
endTime = ConvertMarkToTimestampWithString(aEndMark.Value(), aRv,
|
||||||
|
aReturnUnclamped);
|
||||||
} else if (aOptions && aOptions->mEnd.WasPassed()) {
|
} else if (aOptions && aOptions->mEnd.WasPassed()) {
|
||||||
endTime = ConvertMarkToTimestamp(ResolveTimestampAttribute::End,
|
endTime =
|
||||||
aOptions->mEnd.Value(), aRv);
|
ConvertMarkToTimestamp(ResolveTimestampAttribute::End,
|
||||||
|
aOptions->mEnd.Value(), aRv, aReturnUnclamped);
|
||||||
} else if (aOptions && aOptions->mStart.WasPassed() &&
|
} else if (aOptions && aOptions->mStart.WasPassed() &&
|
||||||
aOptions->mDuration.WasPassed()) {
|
aOptions->mDuration.WasPassed()) {
|
||||||
const DOMHighResTimeStamp start = ConvertMarkToTimestamp(
|
const DOMHighResTimeStamp start =
|
||||||
ResolveTimestampAttribute::Start, aOptions->mStart.Value(), aRv);
|
ConvertMarkToTimestamp(ResolveTimestampAttribute::Start,
|
||||||
|
aOptions->mStart.Value(), aRv, aReturnUnclamped);
|
||||||
if (aRv.Failed()) {
|
if (aRv.Failed()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -519,11 +527,13 @@ DOMHighResTimeStamp Performance::ResolveEndTimeForMeasure(
|
|||||||
|
|
||||||
DOMHighResTimeStamp Performance::ResolveStartTimeForMeasure(
|
DOMHighResTimeStamp Performance::ResolveStartTimeForMeasure(
|
||||||
const Maybe<const nsAString&>& aStartMark,
|
const Maybe<const nsAString&>& aStartMark,
|
||||||
const Maybe<const PerformanceMeasureOptions&>& aOptions, ErrorResult& aRv) {
|
const Maybe<const PerformanceMeasureOptions&>& aOptions, ErrorResult& aRv,
|
||||||
|
bool aReturnUnclamped) {
|
||||||
DOMHighResTimeStamp startTime;
|
DOMHighResTimeStamp startTime;
|
||||||
if (aOptions && aOptions->mStart.WasPassed()) {
|
if (aOptions && aOptions->mStart.WasPassed()) {
|
||||||
startTime = ConvertMarkToTimestamp(ResolveTimestampAttribute::Start,
|
startTime =
|
||||||
aOptions->mStart.Value(), aRv);
|
ConvertMarkToTimestamp(ResolveTimestampAttribute::Start,
|
||||||
|
aOptions->mStart.Value(), aRv, aReturnUnclamped);
|
||||||
} else if (aOptions && aOptions->mDuration.WasPassed() &&
|
} else if (aOptions && aOptions->mDuration.WasPassed() &&
|
||||||
aOptions->mEnd.WasPassed()) {
|
aOptions->mEnd.WasPassed()) {
|
||||||
const DOMHighResTimeStamp duration =
|
const DOMHighResTimeStamp duration =
|
||||||
@@ -534,15 +544,17 @@ DOMHighResTimeStamp Performance::ResolveStartTimeForMeasure(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DOMHighResTimeStamp end = ConvertMarkToTimestamp(
|
const DOMHighResTimeStamp end =
|
||||||
ResolveTimestampAttribute::End, aOptions->mEnd.Value(), aRv);
|
ConvertMarkToTimestamp(ResolveTimestampAttribute::End,
|
||||||
|
aOptions->mEnd.Value(), aRv, aReturnUnclamped);
|
||||||
if (aRv.Failed()) {
|
if (aRv.Failed()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
startTime = end - duration;
|
startTime = end - duration;
|
||||||
} else if (aStartMark) {
|
} else if (aStartMark) {
|
||||||
startTime = ConvertMarkToTimestampWithString(*aStartMark, aRv);
|
startTime =
|
||||||
|
ConvertMarkToTimestampWithString(*aStartMark, aRv, aReturnUnclamped);
|
||||||
} else {
|
} else {
|
||||||
startTime = 0;
|
startTime = 0;
|
||||||
}
|
}
|
||||||
@@ -592,8 +604,8 @@ already_AddRefed<PerformanceMeasure> Performance::Measure(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DOMHighResTimeStamp endTime =
|
const DOMHighResTimeStamp endTime = ResolveEndTimeForMeasure(
|
||||||
ResolveEndTimeForMeasure(aEndMark, options, aRv);
|
aEndMark, options, aRv, /* aReturnUnclamped */ false);
|
||||||
if (NS_WARN_IF(aRv.Failed())) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -603,8 +615,8 @@ already_AddRefed<PerformanceMeasure> Performance::Measure(
|
|||||||
if (aStartOrMeasureOptions.IsString()) {
|
if (aStartOrMeasureOptions.IsString()) {
|
||||||
startMark.emplace(aStartOrMeasureOptions.GetAsString());
|
startMark.emplace(aStartOrMeasureOptions.GetAsString());
|
||||||
}
|
}
|
||||||
const DOMHighResTimeStamp startTime =
|
const DOMHighResTimeStamp startTime = ResolveStartTimeForMeasure(
|
||||||
ResolveStartTimeForMeasure(startMark, options, aRv);
|
startMark, options, aRv, /* aReturnUnclamped */ false);
|
||||||
if (NS_WARN_IF(aRv.Failed())) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -627,10 +639,16 @@ already_AddRefed<PerformanceMeasure> Performance::Measure(
|
|||||||
InsertUserEntry(performanceMeasure);
|
InsertUserEntry(performanceMeasure);
|
||||||
|
|
||||||
if (profiler_thread_is_being_profiled_for_markers()) {
|
if (profiler_thread_is_being_profiled_for_markers()) {
|
||||||
|
const DOMHighResTimeStamp unclampedStartTime = ResolveStartTimeForMeasure(
|
||||||
|
startMark, options, aRv, /* aReturnUnclamped */ true);
|
||||||
|
const DOMHighResTimeStamp unclampedEndTime =
|
||||||
|
ResolveEndTimeForMeasure(aEndMark, options, aRv, /* aReturnUnclamped */
|
||||||
|
true);
|
||||||
TimeStamp startTimeStamp =
|
TimeStamp startTimeStamp =
|
||||||
CreationTimeStamp() + TimeDuration::FromMilliseconds(startTime);
|
CreationTimeStamp() +
|
||||||
|
TimeDuration::FromMilliseconds(unclampedStartTime);
|
||||||
TimeStamp endTimeStamp =
|
TimeStamp endTimeStamp =
|
||||||
CreationTimeStamp() + TimeDuration::FromMilliseconds(endTime);
|
CreationTimeStamp() + TimeDuration::FromMilliseconds(unclampedEndTime);
|
||||||
|
|
||||||
Maybe<nsString> endMark;
|
Maybe<nsString> endMark;
|
||||||
if (aEndMark.WasPassed()) {
|
if (aEndMark.WasPassed()) {
|
||||||
|
|||||||
@@ -221,25 +221,27 @@ class Performance : public DOMEventTargetHelper {
|
|||||||
enum class ResolveTimestampAttribute;
|
enum class ResolveTimestampAttribute;
|
||||||
|
|
||||||
DOMHighResTimeStamp ConvertMarkToTimestampWithString(const nsAString& aName,
|
DOMHighResTimeStamp ConvertMarkToTimestampWithString(const nsAString& aName,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv,
|
||||||
|
bool aReturnUnclamped);
|
||||||
DOMHighResTimeStamp ConvertMarkToTimestampWithDOMHighResTimeStamp(
|
DOMHighResTimeStamp ConvertMarkToTimestampWithDOMHighResTimeStamp(
|
||||||
const ResolveTimestampAttribute aAttribute, const double aTimestamp,
|
const ResolveTimestampAttribute aAttribute, const double aTimestamp,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
DOMHighResTimeStamp ConvertMarkToTimestamp(
|
DOMHighResTimeStamp ConvertMarkToTimestamp(
|
||||||
const ResolveTimestampAttribute aAttribute,
|
const ResolveTimestampAttribute aAttribute,
|
||||||
const OwningStringOrDouble& aMarkNameOrTimestamp, ErrorResult& aRv);
|
const OwningStringOrDouble& aMarkNameOrTimestamp, ErrorResult& aRv,
|
||||||
|
bool aReturnUnclamped);
|
||||||
|
|
||||||
DOMHighResTimeStamp ConvertNameToTimestamp(const nsAString& aName,
|
DOMHighResTimeStamp ConvertNameToTimestamp(const nsAString& aName,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
|
|
||||||
DOMHighResTimeStamp ResolveEndTimeForMeasure(
|
DOMHighResTimeStamp ResolveEndTimeForMeasure(
|
||||||
const Optional<nsAString>& aEndMark,
|
const Optional<nsAString>& aEndMark,
|
||||||
const Maybe<const PerformanceMeasureOptions&>& aOptions,
|
const Maybe<const PerformanceMeasureOptions&>& aOptions, ErrorResult& aRv,
|
||||||
ErrorResult& aRv);
|
bool aReturnUnclamped);
|
||||||
DOMHighResTimeStamp ResolveStartTimeForMeasure(
|
DOMHighResTimeStamp ResolveStartTimeForMeasure(
|
||||||
const Maybe<const nsAString&>& aStartMark,
|
const Maybe<const nsAString&>& aStartMark,
|
||||||
const Maybe<const PerformanceMeasureOptions&>& aOptions,
|
const Maybe<const PerformanceMeasureOptions&>& aOptions, ErrorResult& aRv,
|
||||||
ErrorResult& aRv);
|
bool aReturnUnclamped);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
|||||||
@@ -54,6 +54,13 @@ class PerformanceEntry : public nsISupports, public nsWrapperCache {
|
|||||||
|
|
||||||
virtual DOMHighResTimeStamp StartTime() const { return 0; }
|
virtual DOMHighResTimeStamp StartTime() const { return 0; }
|
||||||
|
|
||||||
|
// This is used by the Gecko Profiler only for adding precise markers.
|
||||||
|
// It's not exposed to JS.
|
||||||
|
virtual DOMHighResTimeStamp UnclampedStartTime() const {
|
||||||
|
MOZ_ASSERT(false, "UnclampedStartTime should not be called on this class.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
virtual DOMHighResTimeStamp Duration() const { return 0; }
|
virtual DOMHighResTimeStamp Duration() const { return 0; }
|
||||||
|
|
||||||
virtual const PerformanceResourceTiming* ToResourceTiming() const {
|
virtual const PerformanceResourceTiming* ToResourceTiming() const {
|
||||||
|
|||||||
@@ -16,10 +16,12 @@ using namespace mozilla::dom;
|
|||||||
|
|
||||||
PerformanceMark::PerformanceMark(nsISupports* aParent, const nsAString& aName,
|
PerformanceMark::PerformanceMark(nsISupports* aParent, const nsAString& aName,
|
||||||
DOMHighResTimeStamp aStartTime,
|
DOMHighResTimeStamp aStartTime,
|
||||||
const JS::Handle<JS::Value>& aDetail)
|
const JS::Handle<JS::Value>& aDetail,
|
||||||
|
DOMHighResTimeStamp aUnclampedStartTime)
|
||||||
: PerformanceEntry(aParent, aName, u"mark"_ns),
|
: PerformanceEntry(aParent, aName, u"mark"_ns),
|
||||||
mStartTime(aStartTime),
|
mStartTime(aStartTime),
|
||||||
mDetail(aDetail) {
|
mDetail(aDetail),
|
||||||
|
mUnclampedStartTime(aUnclampedStartTime) {
|
||||||
mozilla::HoldJSObjects(this);
|
mozilla::HoldJSObjects(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,6 +55,13 @@ already_AddRefed<PerformanceMark> PerformanceMark::Constructor(
|
|||||||
DOMHighResTimeStamp startTime = aMarkOptions.mStartTime.WasPassed()
|
DOMHighResTimeStamp startTime = aMarkOptions.mStartTime.WasPassed()
|
||||||
? aMarkOptions.mStartTime.Value()
|
? aMarkOptions.mStartTime.Value()
|
||||||
: performance->Now();
|
: performance->Now();
|
||||||
|
// We need to get the unclamped start time to be able to add profiler markers
|
||||||
|
// with precise time/duration. This is not exposed to web and only used by the
|
||||||
|
// profiler.
|
||||||
|
// If a mStartTime is passed by the user, we will always have a clamped value.
|
||||||
|
DOMHighResTimeStamp unclampedStartTime = aMarkOptions.mStartTime.WasPassed()
|
||||||
|
? startTime
|
||||||
|
: performance->NowUnclamped();
|
||||||
if (startTime < 0) {
|
if (startTime < 0) {
|
||||||
aRv.ThrowTypeError("Expected startTime >= 0");
|
aRv.ThrowTypeError("Expected startTime >= 0");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -71,7 +80,8 @@ already_AddRefed<PerformanceMark> PerformanceMark::Constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return do_AddRef(new PerformanceMark(aGlobal, aMarkName, startTime, detail));
|
return do_AddRef(new PerformanceMark(aGlobal, aMarkName, startTime, detail,
|
||||||
|
unclampedStartTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
PerformanceMark::~PerformanceMark() { mozilla::DropJSObjects(this); }
|
PerformanceMark::~PerformanceMark() { mozilla::DropJSObjects(this); }
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#define mozilla_dom_performancemark_h___
|
#define mozilla_dom_performancemark_h___
|
||||||
|
|
||||||
#include "mozilla/dom/PerformanceEntry.h"
|
#include "mozilla/dom/PerformanceEntry.h"
|
||||||
|
#include "mozilla/ProfilerMarkers.h"
|
||||||
|
|
||||||
namespace mozilla::dom {
|
namespace mozilla::dom {
|
||||||
|
|
||||||
@@ -23,7 +24,8 @@ class PerformanceMark final : public PerformanceEntry {
|
|||||||
private:
|
private:
|
||||||
PerformanceMark(nsISupports* aParent, const nsAString& aName,
|
PerformanceMark(nsISupports* aParent, const nsAString& aName,
|
||||||
DOMHighResTimeStamp aStartTime,
|
DOMHighResTimeStamp aStartTime,
|
||||||
const JS::Handle<JS::Value>& aDetail);
|
const JS::Handle<JS::Value>& aDetail,
|
||||||
|
DOMHighResTimeStamp aUnclampedStartTime);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static already_AddRefed<PerformanceMark> Constructor(
|
static already_AddRefed<PerformanceMark> Constructor(
|
||||||
@@ -39,6 +41,12 @@ class PerformanceMark final : public PerformanceEntry {
|
|||||||
|
|
||||||
virtual DOMHighResTimeStamp StartTime() const override { return mStartTime; }
|
virtual DOMHighResTimeStamp StartTime() const override { return mStartTime; }
|
||||||
|
|
||||||
|
virtual DOMHighResTimeStamp UnclampedStartTime() const override {
|
||||||
|
MOZ_ASSERT(profiler_thread_is_being_profiled_for_markers(),
|
||||||
|
"This should only be called when the Gecko Profiler is active.");
|
||||||
|
return mUnclampedStartTime;
|
||||||
|
}
|
||||||
|
|
||||||
void GetDetail(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval);
|
void GetDetail(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval);
|
||||||
|
|
||||||
size_t SizeOfIncludingThis(
|
size_t SizeOfIncludingThis(
|
||||||
@@ -50,6 +58,9 @@ class PerformanceMark final : public PerformanceEntry {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
JS::Heap<JS::Value> mDetail;
|
JS::Heap<JS::Value> mDetail;
|
||||||
|
// This is used by the Gecko Profiler only to be able to add precise markers.
|
||||||
|
// It's not exposed to JS
|
||||||
|
DOMHighResTimeStamp mUnclampedStartTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla::dom
|
} // namespace mozilla::dom
|
||||||
|
|||||||
Reference in New Issue
Block a user