Bug 1362114 - JSBC: Add telemetry to later tune the heuristics. r=mrbkap,francois

This commit is contained in:
Nicolas B. Pierron
2017-06-20 09:53:10 +00:00
parent 5cd02f7ef8
commit 3125921cda
5 changed files with 257 additions and 0 deletions

View File

@@ -175,6 +175,59 @@ ScriptLoader::~ScriptLoader()
}
}
// Collect telemtry data about the cache information, and the kind of source
// which are being loaded, and where it is being loaded from.
static void
CollectScriptTelemetry(nsIIncrementalStreamLoader* aLoader,
ScriptLoadRequest* aRequest)
{
using namespace mozilla::Telemetry;
// Skip this function if we are not running telemetry.
if (!CanRecordExtended()) {
return;
}
// Report the type of source, as well as the size of the source.
if (aRequest->IsLoadingSource()) {
if (aRequest->mIsInline) {
AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::Inline);
nsAutoString inlineData;
aRequest->mElement->GetScriptText(inlineData);
Accumulate(DOM_SCRIPT_INLINE_SIZE, inlineData.Length());
} else {
AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::SourceFallback);
Accumulate(DOM_SCRIPT_SOURCE_SIZE, aRequest->mScriptText.length());
}
} else {
MOZ_ASSERT(aRequest->IsLoading());
if (aRequest->IsSource()) {
AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::Source);
Accumulate(DOM_SCRIPT_SOURCE_SIZE, aRequest->mScriptText.length());
} else {
MOZ_ASSERT(aRequest->IsBytecode());
AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::AltData);
Accumulate(DOM_SCRIPT_BYTECODE_SIZE, aRequest->mScriptBytecode.length());
}
}
// Skip if we do not have any cache information for the given script.
if (!aLoader) {
return;
}
nsCOMPtr<nsIRequest> channel;
aLoader->GetRequest(getter_AddRefs(channel));
nsCOMPtr<nsICacheInfoChannel> cic(do_QueryInterface(channel));
if (!cic) {
return;
}
int32_t fetchCount = 0;
if (NS_SUCCEEDED(cic->GetCacheTokenFetchCount(&fetchCount))) {
Accumulate(DOM_SCRIPT_FETCH_COUNT, fetchCount);
}
}
// Helper method for checking if the script element is an event-handler
// This means that it has both a for-attribute and a event-attribute.
// Also, if the for-attribute has a value that matches "\s*window\s*",
@@ -1364,6 +1417,7 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement* aElement)
request->mProgress = ScriptLoadRequest::Progress::Loading_Source;
request->mDataType = ScriptLoadRequest::DataType::Source;
TRACE_FOR_TEST_BOOL(request->mElement, "scriptloader_load_source");
CollectScriptTelemetry(nullptr, request);
if (request->IsModuleRequest()) {
ModuleLoadRequest* modReq = request->AsModuleRequest();
@@ -2002,6 +2056,7 @@ ScriptLoader::ShouldCacheBytecode(ScriptLoadRequest* aRequest)
nsresult
ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
{
using namespace mozilla::Telemetry;
MOZ_ASSERT(aRequest->IsReadyToRun());
// We need a document to evaluate scripts.
@@ -2016,6 +2071,9 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
return NS_ERROR_FAILURE;
}
// Report telemetry results of the number of scripts evaluated.
mDocument->SetDocumentIncCounter(IncCounter::eIncCounter_ScriptTag);
// Get the script-type to be used by this element.
NS_ASSERTION(scriptContent, "no content - what is default script-type?");
@@ -2081,9 +2139,11 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
nsJSUtils::ExecutionContext exec(aes.cx(), global);
if (aRequest->mOffThreadToken) {
LOG(("ScriptLoadRequest (%p): Decode Bytecode & Join and Execute", aRequest));
AutoTimer<DOM_SCRIPT_OFF_THREAD_DECODE_EXEC_MS> timer;
rv = exec.DecodeJoinAndExec(&aRequest->mOffThreadToken);
} else {
LOG(("ScriptLoadRequest (%p): Decode Bytecode and Execute", aRequest));
AutoTimer<DOM_SCRIPT_MAIN_THREAD_DECODE_EXEC_MS> timer;
rv = exec.DecodeAndExec(options, aRequest->mScriptBytecode,
aRequest->mBytecodeOffset);
}
@@ -2095,6 +2155,14 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
JS::Rooted<JSScript*> script(aes.cx());
bool encodeBytecode = ShouldCacheBytecode(aRequest);
TimeStamp start;
if (Telemetry::CanRecordExtended()) {
// Only record telemetry for scripts which are above the threshold.
if (aRequest->mCacheInfo && aRequest->mScriptText.length() < 1024) {
start = TimeStamp::Now();
}
}
{
nsJSUtils::ExecutionContext exec(aes.cx(), global);
exec.SetEncodeBytecode(encodeBytecode);
@@ -2104,12 +2172,24 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
LOG(("ScriptLoadRequest (%p): Join (off-thread parsing) and Execute",
aRequest));
rv = exec.JoinAndExec(&aRequest->mOffThreadToken, &script);
if (start) {
AccumulateTimeDelta(encodeBytecode
? DOM_SCRIPT_OFF_THREAD_PARSE_ENCODE_EXEC_MS
: DOM_SCRIPT_OFF_THREAD_PARSE_EXEC_MS,
start);
}
} else {
// Main thread parsing (inline and small scripts)
LOG(("ScriptLoadRequest (%p): Compile And Exec", aRequest));
nsAutoString inlineData;
SourceBufferHolder srcBuf = GetScriptSource(aRequest, inlineData);
rv = exec.CompileAndExec(options, srcBuf, &script);
if (start) {
AccumulateTimeDelta(encodeBytecode
? DOM_SCRIPT_MAIN_THREAD_PARSE_ENCODE_EXEC_MS
: DOM_SCRIPT_MAIN_THREAD_PARSE_EXEC_MS,
start);
}
}
}
@@ -2210,6 +2290,7 @@ ScriptLoader::EncodeBytecode()
return;
}
Telemetry::AutoTimer<Telemetry::DOM_SCRIPT_ENCODING_MS_PER_DOCUMENT> timer;
AutoEntryScript aes(globalObject, "encode bytecode", true);
RefPtr<ScriptLoadRequest> request;
while (!mBytecodeEncodingQueue.isEmpty()) {
@@ -2223,6 +2304,7 @@ ScriptLoader::EncodeBytecode()
void
ScriptLoader::EncodeRequestBytecode(JSContext* aCx, ScriptLoadRequest* aRequest)
{
using namespace mozilla::Telemetry;
nsresult rv = NS_OK;
MOZ_ASSERT(aRequest->mCacheInfo);
auto bytecodeFailed = mozilla::MakeScopeExit([&]() {
@@ -2233,12 +2315,14 @@ ScriptLoader::EncodeRequestBytecode(JSContext* aCx, ScriptLoadRequest* aRequest)
if (!JS::FinishIncrementalEncoding(aCx, script, aRequest->mScriptBytecode)) {
LOG(("ScriptLoadRequest (%p): Cannot serialize bytecode",
aRequest));
AccumulateCategorical(LABELS_DOM_SCRIPT_ENCODING_STATUS::EncodingFailure);
return;
}
if (aRequest->mScriptBytecode.length() >= UINT32_MAX) {
LOG(("ScriptLoadRequest (%p): Bytecode cache is too large to be decoded correctly.",
aRequest));
AccumulateCategorical(LABELS_DOM_SCRIPT_ENCODING_STATUS::BufferTooLarge);
return;
}
@@ -2251,6 +2335,7 @@ ScriptLoader::EncodeRequestBytecode(JSContext* aCx, ScriptLoadRequest* aRequest)
if (NS_FAILED(rv)) {
LOG(("ScriptLoadRequest (%p): Cannot open bytecode cache (rv = %X, output = %p)",
aRequest, unsigned(rv), output.get()));
AccumulateCategorical(LABELS_DOM_SCRIPT_ENCODING_STATUS::OpenFailure);
return;
}
MOZ_ASSERT(output);
@@ -2258,6 +2343,9 @@ ScriptLoader::EncodeRequestBytecode(JSContext* aCx, ScriptLoadRequest* aRequest)
nsresult rv = output->Close();
LOG(("ScriptLoadRequest (%p): Closing (rv = %X)",
aRequest, unsigned(rv)));
if (NS_FAILED(rv)) {
AccumulateCategorical(LABELS_DOM_SCRIPT_ENCODING_STATUS::CloseFailure);
}
});
uint32_t n;
@@ -2266,11 +2354,13 @@ ScriptLoader::EncodeRequestBytecode(JSContext* aCx, ScriptLoadRequest* aRequest)
LOG(("ScriptLoadRequest (%p): Write bytecode cache (rv = %X, length = %u, written = %u)",
aRequest, unsigned(rv), unsigned(aRequest->mScriptBytecode.length()), n));
if (NS_FAILED(rv)) {
AccumulateCategorical(LABELS_DOM_SCRIPT_ENCODING_STATUS::WriteFailure);
return;
}
bytecodeFailed.release();
TRACE_FOR_TEST_NONE(aRequest->mElement, "scriptloader_bytecode_saved");
AccumulateCategorical(LABELS_DOM_SCRIPT_ENCODING_STATUS::EncodingSuccess);
}
void
@@ -2763,6 +2853,7 @@ ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest,
return NS_BINDING_ABORTED;
}
MOZ_ASSERT(aRequest->IsLoading());
CollectScriptTelemetry(aLoader, aRequest);
// If we don't have a document, then we need to abort further
// evaluation.