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:
Nazım Can Altınova
2023-03-22 10:12:50 +00:00
parent 9607a89189
commit 7a443c61f2
5 changed files with 79 additions and 31 deletions

View File

@@ -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()) {

View File

@@ -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

View File

@@ -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 {

View File

@@ -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); }

View File

@@ -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