Bug 1608556 - Expose to privileged JS an API to add markers with a start time and an associated text, r=gerald,mconley,baku.

Differential Revision: https://phabricator.services.mozilla.com/D68784

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Florian Quèze 2020-04-03 13:47:25 +00:00
Родитель e4c3013b95
Коммит d10cae0789
7 изменённых файлов: 128 добавлений и 14 удалений

Просмотреть файл

@ -2293,13 +2293,13 @@ BrowserGlue.prototype = {
ChromeUtils.idleDispatch(
() => {
if (!Services.startup.shuttingDown) {
if (Services.profiler) {
Services.profiler.AddMarker("startupIdleTask");
}
let startTime = Cu.now();
try {
task.task();
} catch (ex) {
Cu.reportError(ex);
} finally {
ChromeUtils.addProfilerMarker("startupIdleTask", startTime);
}
}
},
@ -2372,13 +2372,13 @@ BrowserGlue.prototype = {
for (let task of idleTasks) {
ChromeUtils.idleDispatch(() => {
if (!Services.startup.shuttingDown) {
if (Services.profiler) {
Services.profiler.AddMarker("startupLateIdleTask");
}
let startTime = Cu.now();
try {
task();
} catch (ex) {
Cu.reportError(ex);
} finally {
ChromeUtils.addProfilerMarker("startupLateIdleTask", startTime);
}
}
});

Просмотреть файл

@ -31,6 +31,7 @@
#include "mozilla/dom/MediaControlService.h"
#include "mozilla/dom/MediaMetadata.h"
#include "mozilla/dom/MediaSessionBinding.h"
#include "mozilla/dom/Performance.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ReportingHeader.h"
#include "mozilla/dom/UnionTypes.h"
@ -44,6 +45,9 @@
#include "nsThreadUtils.h"
#include "mozJSComponentLoader.h"
#include "GeckoProfiler.h"
#ifdef MOZ_GECKO_PROFILER
# include "ProfilerMarkerPayload.h"
#endif
#include "nsIException.h"
namespace mozilla {
@ -184,6 +188,57 @@ void ChromeUtils::ReleaseAssert(GlobalObject& aGlobal, bool aCondition,
messageUtf8.get(), filenameUtf8.get(), lineNo);
}
/* static */
void ChromeUtils::AddProfilerMarker(
GlobalObject& aGlobal, const nsACString& aName,
const Optional<DOMHighResTimeStamp>& aStartTime,
const Optional<nsACString>& aText) {
#ifdef MOZ_GECKO_PROFILER
const nsCString& name = PromiseFlatCString(aName);
if (!aText.WasPassed() && !aStartTime.WasPassed()) {
profiler_add_js_marker(name.get());
return;
}
TimeStamp now = mozilla::TimeStamp::NowUnfuzzed();
TimeStamp startTime = now;
if (aStartTime.WasPassed()) {
RefPtr<Performance> performance;
if (NS_IsMainThread()) {
nsCOMPtr<nsPIDOMWindowInner> ownerWindow =
do_QueryInterface(aGlobal.GetAsSupports());
if (ownerWindow) {
performance = ownerWindow->GetPerformance();
}
} else {
JSContext* cx = aGlobal.Context();
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
if (workerPrivate) {
performance = workerPrivate->GlobalScope()->GetPerformance();
}
}
if (performance) {
startTime = performance->CreationTimeStamp() +
TimeDuration::FromMilliseconds(aStartTime.Value());
} else {
startTime = TimeStamp::ProcessCreation() +
TimeDuration::FromMilliseconds(aStartTime.Value());
}
}
if (aText.WasPassed()) {
profiler_add_text_marker(name.get(), aText.Value(),
JS::ProfilingCategoryPair::JS, startTime, now);
} else {
profiler_add_marker(name.get(), JS::ProfilingCategoryPair::JS,
TimingMarkerPayload(startTime, now));
}
#endif
}
/* static */
void ChromeUtils::WaiveXrays(GlobalObject& aGlobal, JS::HandleValue aVal,
JS::MutableHandleValue aRetval, ErrorResult& aRv) {

Просмотреть файл

@ -11,6 +11,7 @@
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/ChromeUtilsBinding.h"
#include "mozilla/ErrorResult.h"
#include "nsDOMNavigationTiming.h" // for DOMHighResTimeStamp
#include "nsIContentChild.h"
namespace mozilla {
@ -78,6 +79,10 @@ class ChromeUtils {
static void ReleaseAssert(GlobalObject& aGlobal, bool aCondition,
const nsAString& aMessage);
static void AddProfilerMarker(GlobalObject& aGlobal, const nsACString& aName,
const Optional<DOMHighResTimeStamp>& aStartTime,
const Optional<nsACString>& text);
static void OriginAttributesToSuffix(
GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
nsCString& aSuffix);

Просмотреть файл

@ -157,6 +157,22 @@ namespace ChromeUtils {
void clearRecentJSDevError();
#endif // NIGHTLY_BUILD
/**
* If the profiler is currently running and recording the current thread,
* add a marker for the current thread. No-op otherwise.
*
* @param name The name of the marker.
* @param startTime The timestamp to use as the start of the marker.
* If omitted, the marker will have no duration.
* In window and ChromeWorker contexts, use a
* timestamp from `performance.now()`.
* In JS modules, use `Cu.now()` to get a timestamp.
* @param text Text to associate with the marker.
*/
void addProfilerMarker(UTF8String name,
optional DOMHighResTimeStamp startTime,
optional UTF8String text);
/**
* IF YOU ADD NEW METHODS HERE, MAKE SURE THEY ARE THREAD-SAFE.
*/

Просмотреть файл

@ -29,22 +29,21 @@ if (this.Components) {
let worker = new PromiseWorker.AbstractWorker();
worker.dispatch = function(method, args = []) {
let prefix = "OS.File " + method;
performance.mark(prefix + "-start");
let startTime = performance.now();
try {
return Agent[method](...args);
} finally {
let name = prefix;
let text = method;
if (args.length && args[0] instanceof Object && args[0].string) {
// Including the path in the marker name here means it will be part of
// Including the path in the marker text here means it will be part of
// profiles. It's fine to include personally identifiable information
// in profiles, because when a profile is captured only the user will
// see it, and before uploading it a sanitization step will be offered.
// The 'OS.File ' prefix will help the profiler know that these marker
// names should be sanitized.
name += " — " + args[0].string;
// The 'OS.File' name will help the profiler know that these markers
// should be sanitized.
text += " — " + args[0].string;
}
performance.measure(name, prefix + "-start");
ChromeUtils.addProfilerMarker("OS.File", startTime, text);
}
};
worker.log = LOG;

Просмотреть файл

@ -300,6 +300,32 @@ void UserTimingMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
}
}
ProfileBufferEntryWriter::Length TimingMarkerPayload::TagAndSerializationBytes()
const {
return CommonPropsTagAndSerializationBytes();
}
void TimingMarkerPayload::SerializeTagAndPayload(
ProfileBufferEntryWriter& aEntryWriter) const {
static const DeserializerTag tag = TagForDeserializer(Deserialize);
SerializeTagAndCommonProps(tag, aEntryWriter);
}
// static
UniquePtr<ProfilerMarkerPayload> TimingMarkerPayload::Deserialize(
ProfileBufferEntryReader& aEntryReader) {
ProfilerMarkerPayload::CommonProps props =
DeserializeCommonProps(aEntryReader);
return UniquePtr<ProfilerMarkerPayload>(
new TimingMarkerPayload(std::move(props)));
}
void TimingMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
const TimeStamp& aProcessStartTime,
UniqueStacks& aUniqueStacks) const {
StreamCommonProps("Timing", aWriter, aProcessStartTime, aUniqueStacks);
}
ProfileBufferEntryWriter::Length TextMarkerPayload::TagAndSerializationBytes()
const {
return CommonPropsTagAndSerializationBytes() +

Просмотреть файл

@ -578,6 +578,19 @@ class LongTaskMarkerPayload : public ProfilerMarkerPayload {
: ProfilerMarkerPayload(std::move(aCommonProps)) {}
};
class TimingMarkerPayload : public ProfilerMarkerPayload {
public:
TimingMarkerPayload(const mozilla::TimeStamp& aStartTime,
const mozilla::TimeStamp& aEndTime)
: ProfilerMarkerPayload(aStartTime, aEndTime) {}
DECL_STREAM_PAYLOAD
private:
TimingMarkerPayload(CommonProps&& aCommonProps)
: ProfilerMarkerPayload(std::move(aCommonProps)) {}
};
class TextMarkerPayload : public ProfilerMarkerPayload {
public:
TextMarkerPayload(const nsACString& aText,