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(
|
||||
const nsAString& aName, ErrorResult& aRv) {
|
||||
const nsAString& aName, ErrorResult& aRv, bool aReturnUnclamped) {
|
||||
if (IsPerformanceTimingAttribute(aName)) {
|
||||
return ConvertNameToTimestamp(aName, aRv);
|
||||
}
|
||||
@@ -406,6 +406,9 @@ DOMHighResTimeStamp Performance::ConvertMarkToTimestampWithString(
|
||||
typeParam = &str;
|
||||
GetEntriesByName(aName, typeParam, arr);
|
||||
if (!arr.IsEmpty()) {
|
||||
if (aReturnUnclamped) {
|
||||
return arr.LastElement()->UnclampedStartTime();
|
||||
}
|
||||
return arr.LastElement()->StartTime();
|
||||
}
|
||||
|
||||
@@ -441,10 +444,11 @@ DOMHighResTimeStamp Performance::ConvertMarkToTimestampWithDOMHighResTimeStamp(
|
||||
|
||||
DOMHighResTimeStamp Performance::ConvertMarkToTimestamp(
|
||||
const ResolveTimestampAttribute aAttribute,
|
||||
const OwningStringOrDouble& aMarkNameOrTimestamp, ErrorResult& aRv) {
|
||||
const OwningStringOrDouble& aMarkNameOrTimestamp, ErrorResult& aRv,
|
||||
bool aReturnUnclamped) {
|
||||
if (aMarkNameOrTimestamp.IsString()) {
|
||||
return ConvertMarkToTimestampWithString(aMarkNameOrTimestamp.GetAsString(),
|
||||
aRv);
|
||||
aRv, aReturnUnclamped);
|
||||
}
|
||||
|
||||
return ConvertMarkToTimestampWithDOMHighResTimeStamp(
|
||||
@@ -486,17 +490,21 @@ DOMHighResTimeStamp Performance::ConvertNameToTimestamp(const nsAString& aName,
|
||||
|
||||
DOMHighResTimeStamp Performance::ResolveEndTimeForMeasure(
|
||||
const Optional<nsAString>& aEndMark,
|
||||
const Maybe<const PerformanceMeasureOptions&>& aOptions, ErrorResult& aRv) {
|
||||
const Maybe<const PerformanceMeasureOptions&>& aOptions, ErrorResult& aRv,
|
||||
bool aReturnUnclamped) {
|
||||
DOMHighResTimeStamp endTime;
|
||||
if (aEndMark.WasPassed()) {
|
||||
endTime = ConvertMarkToTimestampWithString(aEndMark.Value(), aRv);
|
||||
endTime = ConvertMarkToTimestampWithString(aEndMark.Value(), aRv,
|
||||
aReturnUnclamped);
|
||||
} else if (aOptions && aOptions->mEnd.WasPassed()) {
|
||||
endTime = ConvertMarkToTimestamp(ResolveTimestampAttribute::End,
|
||||
aOptions->mEnd.Value(), aRv);
|
||||
endTime =
|
||||
ConvertMarkToTimestamp(ResolveTimestampAttribute::End,
|
||||
aOptions->mEnd.Value(), aRv, aReturnUnclamped);
|
||||
} else if (aOptions && aOptions->mStart.WasPassed() &&
|
||||
aOptions->mDuration.WasPassed()) {
|
||||
const DOMHighResTimeStamp start = ConvertMarkToTimestamp(
|
||||
ResolveTimestampAttribute::Start, aOptions->mStart.Value(), aRv);
|
||||
const DOMHighResTimeStamp start =
|
||||
ConvertMarkToTimestamp(ResolveTimestampAttribute::Start,
|
||||
aOptions->mStart.Value(), aRv, aReturnUnclamped);
|
||||
if (aRv.Failed()) {
|
||||
return 0;
|
||||
}
|
||||
@@ -519,11 +527,13 @@ DOMHighResTimeStamp Performance::ResolveEndTimeForMeasure(
|
||||
|
||||
DOMHighResTimeStamp Performance::ResolveStartTimeForMeasure(
|
||||
const Maybe<const nsAString&>& aStartMark,
|
||||
const Maybe<const PerformanceMeasureOptions&>& aOptions, ErrorResult& aRv) {
|
||||
const Maybe<const PerformanceMeasureOptions&>& aOptions, ErrorResult& aRv,
|
||||
bool aReturnUnclamped) {
|
||||
DOMHighResTimeStamp startTime;
|
||||
if (aOptions && aOptions->mStart.WasPassed()) {
|
||||
startTime = ConvertMarkToTimestamp(ResolveTimestampAttribute::Start,
|
||||
aOptions->mStart.Value(), aRv);
|
||||
startTime =
|
||||
ConvertMarkToTimestamp(ResolveTimestampAttribute::Start,
|
||||
aOptions->mStart.Value(), aRv, aReturnUnclamped);
|
||||
} else if (aOptions && aOptions->mDuration.WasPassed() &&
|
||||
aOptions->mEnd.WasPassed()) {
|
||||
const DOMHighResTimeStamp duration =
|
||||
@@ -534,15 +544,17 @@ DOMHighResTimeStamp Performance::ResolveStartTimeForMeasure(
|
||||
return 0;
|
||||
}
|
||||
|
||||
const DOMHighResTimeStamp end = ConvertMarkToTimestamp(
|
||||
ResolveTimestampAttribute::End, aOptions->mEnd.Value(), aRv);
|
||||
const DOMHighResTimeStamp end =
|
||||
ConvertMarkToTimestamp(ResolveTimestampAttribute::End,
|
||||
aOptions->mEnd.Value(), aRv, aReturnUnclamped);
|
||||
if (aRv.Failed()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
startTime = end - duration;
|
||||
} else if (aStartMark) {
|
||||
startTime = ConvertMarkToTimestampWithString(*aStartMark, aRv);
|
||||
startTime =
|
||||
ConvertMarkToTimestampWithString(*aStartMark, aRv, aReturnUnclamped);
|
||||
} else {
|
||||
startTime = 0;
|
||||
}
|
||||
@@ -592,8 +604,8 @@ already_AddRefed<PerformanceMeasure> Performance::Measure(
|
||||
}
|
||||
}
|
||||
|
||||
const DOMHighResTimeStamp endTime =
|
||||
ResolveEndTimeForMeasure(aEndMark, options, aRv);
|
||||
const DOMHighResTimeStamp endTime = ResolveEndTimeForMeasure(
|
||||
aEndMark, options, aRv, /* aReturnUnclamped */ false);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -603,8 +615,8 @@ already_AddRefed<PerformanceMeasure> Performance::Measure(
|
||||
if (aStartOrMeasureOptions.IsString()) {
|
||||
startMark.emplace(aStartOrMeasureOptions.GetAsString());
|
||||
}
|
||||
const DOMHighResTimeStamp startTime =
|
||||
ResolveStartTimeForMeasure(startMark, options, aRv);
|
||||
const DOMHighResTimeStamp startTime = ResolveStartTimeForMeasure(
|
||||
startMark, options, aRv, /* aReturnUnclamped */ false);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -627,10 +639,16 @@ already_AddRefed<PerformanceMeasure> Performance::Measure(
|
||||
InsertUserEntry(performanceMeasure);
|
||||
|
||||
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 =
|
||||
CreationTimeStamp() + TimeDuration::FromMilliseconds(startTime);
|
||||
CreationTimeStamp() +
|
||||
TimeDuration::FromMilliseconds(unclampedStartTime);
|
||||
TimeStamp endTimeStamp =
|
||||
CreationTimeStamp() + TimeDuration::FromMilliseconds(endTime);
|
||||
CreationTimeStamp() + TimeDuration::FromMilliseconds(unclampedEndTime);
|
||||
|
||||
Maybe<nsString> endMark;
|
||||
if (aEndMark.WasPassed()) {
|
||||
|
||||
@@ -221,25 +221,27 @@ class Performance : public DOMEventTargetHelper {
|
||||
enum class ResolveTimestampAttribute;
|
||||
|
||||
DOMHighResTimeStamp ConvertMarkToTimestampWithString(const nsAString& aName,
|
||||
ErrorResult& aRv);
|
||||
ErrorResult& aRv,
|
||||
bool aReturnUnclamped);
|
||||
DOMHighResTimeStamp ConvertMarkToTimestampWithDOMHighResTimeStamp(
|
||||
const ResolveTimestampAttribute aAttribute, const double aTimestamp,
|
||||
ErrorResult& aRv);
|
||||
DOMHighResTimeStamp ConvertMarkToTimestamp(
|
||||
const ResolveTimestampAttribute aAttribute,
|
||||
const OwningStringOrDouble& aMarkNameOrTimestamp, ErrorResult& aRv);
|
||||
const OwningStringOrDouble& aMarkNameOrTimestamp, ErrorResult& aRv,
|
||||
bool aReturnUnclamped);
|
||||
|
||||
DOMHighResTimeStamp ConvertNameToTimestamp(const nsAString& aName,
|
||||
ErrorResult& aRv);
|
||||
|
||||
DOMHighResTimeStamp ResolveEndTimeForMeasure(
|
||||
const Optional<nsAString>& aEndMark,
|
||||
const Maybe<const PerformanceMeasureOptions&>& aOptions,
|
||||
ErrorResult& aRv);
|
||||
const Maybe<const PerformanceMeasureOptions&>& aOptions, ErrorResult& aRv,
|
||||
bool aReturnUnclamped);
|
||||
DOMHighResTimeStamp ResolveStartTimeForMeasure(
|
||||
const Maybe<const nsAString&>& aStartMark,
|
||||
const Maybe<const PerformanceMeasureOptions&>& aOptions,
|
||||
ErrorResult& aRv);
|
||||
const Maybe<const PerformanceMeasureOptions&>& aOptions, ErrorResult& aRv,
|
||||
bool aReturnUnclamped);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -54,6 +54,13 @@ class PerformanceEntry : public nsISupports, public nsWrapperCache {
|
||||
|
||||
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 const PerformanceResourceTiming* ToResourceTiming() const {
|
||||
|
||||
@@ -16,10 +16,12 @@ using namespace mozilla::dom;
|
||||
|
||||
PerformanceMark::PerformanceMark(nsISupports* aParent, const nsAString& aName,
|
||||
DOMHighResTimeStamp aStartTime,
|
||||
const JS::Handle<JS::Value>& aDetail)
|
||||
const JS::Handle<JS::Value>& aDetail,
|
||||
DOMHighResTimeStamp aUnclampedStartTime)
|
||||
: PerformanceEntry(aParent, aName, u"mark"_ns),
|
||||
mStartTime(aStartTime),
|
||||
mDetail(aDetail) {
|
||||
mDetail(aDetail),
|
||||
mUnclampedStartTime(aUnclampedStartTime) {
|
||||
mozilla::HoldJSObjects(this);
|
||||
}
|
||||
|
||||
@@ -53,6 +55,13 @@ already_AddRefed<PerformanceMark> PerformanceMark::Constructor(
|
||||
DOMHighResTimeStamp startTime = aMarkOptions.mStartTime.WasPassed()
|
||||
? aMarkOptions.mStartTime.Value()
|
||||
: 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) {
|
||||
aRv.ThrowTypeError("Expected startTime >= 0");
|
||||
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); }
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define mozilla_dom_performancemark_h___
|
||||
|
||||
#include "mozilla/dom/PerformanceEntry.h"
|
||||
#include "mozilla/ProfilerMarkers.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
@@ -23,7 +24,8 @@ class PerformanceMark final : public PerformanceEntry {
|
||||
private:
|
||||
PerformanceMark(nsISupports* aParent, const nsAString& aName,
|
||||
DOMHighResTimeStamp aStartTime,
|
||||
const JS::Handle<JS::Value>& aDetail);
|
||||
const JS::Handle<JS::Value>& aDetail,
|
||||
DOMHighResTimeStamp aUnclampedStartTime);
|
||||
|
||||
public:
|
||||
static already_AddRefed<PerformanceMark> Constructor(
|
||||
@@ -39,6 +41,12 @@ class PerformanceMark final : public PerformanceEntry {
|
||||
|
||||
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);
|
||||
|
||||
size_t SizeOfIncludingThis(
|
||||
@@ -50,6 +58,9 @@ class PerformanceMark final : public PerformanceEntry {
|
||||
|
||||
private:
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user