From 83f77707b72a9f9b88623266f2d5f33a5a200796 Mon Sep 17 00:00:00 2001 From: Wei-Cheng Pan Date: Tue, 8 Aug 2017 17:54:13 +0800 Subject: [PATCH] Bug 1373814 - Add new probe to measure start-up input latency. data-r=francois r=francois,smaug For parent process, users may expect the UI is interactable after they saw the first tab has restored/shown. So this patch added a new topic "sessionstore-one-or-no-tab-restored" which represents the parent process has finished a tab restoring. If there is nothing to restore, it is effectively equal to "sessionstore-windows-restored". For centent processes, users may expect web content is interactable when the top-level-content-document has finished loading, which is different from the parent case. MozReview-Commit-ID: AtEUW80Ea6n --HG-- extra : rebase_source : d920975bf95545ea9e3127d3f570b814fe301be9 --- .../components/sessionstore/SessionStore.jsm | 4 ++ layout/base/PresShell.cpp | 47 +++++++++++++++++++ layout/base/PresShell.h | 2 + toolkit/components/telemetry/Histograms.json | 22 +++++++++ 4 files changed, 75 insertions(+) diff --git a/browser/components/sessionstore/SessionStore.jsm b/browser/components/sessionstore/SessionStore.jsm index e5be21e258b9..663dad7a4875 100644 --- a/browser/components/sessionstore/SessionStore.jsm +++ b/browser/components/sessionstore/SessionStore.jsm @@ -971,6 +971,8 @@ var SessionStoreInternal = { SessionStoreInternal.restoreNextTab(); this._sendTabRestoredNotification(tab, data.isRemotenessUpdate); + + Services.obs.notifyObservers(null, "sessionstore-one-or-no-tab-restored"); break; case "SessionStore:crashedTabRevived": // The browser was revived by navigating to a different page @@ -1149,6 +1151,7 @@ var SessionStoreInternal = { // Nothing to restore now, notify observers things are complete. Services.obs.notifyObservers(null, NOTIFY_WINDOWS_RESTORED); + Services.obs.notifyObservers(null, "sessionstore-one-or-no-tab-restored"); this._deferredAllWindowsRestored.resolve(); } else { TelemetryTimestamps.add("sessionRestoreRestoring"); @@ -1168,6 +1171,7 @@ var SessionStoreInternal = { } else { // Nothing to restore, notify observers things are complete. Services.obs.notifyObservers(null, NOTIFY_WINDOWS_RESTORED); + Services.obs.notifyObservers(null, "sessionstore-one-or-no-tab-restored"); this._deferredAllWindowsRestored.resolve(); } // this window was opened by _openWindowWithState diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp index 2728b016c709..efd35b3efec1 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -560,6 +560,8 @@ mozilla::LazyLogModule PresShell::gLog("PresShell"); mozilla::TimeStamp PresShell::sLastInputCreated; mozilla::TimeStamp PresShell::sLastInputProcessed; +bool PresShell::sProcessInteractable = false; + #ifdef DEBUG static void VerifyStyleTree(nsPresContext* aPresContext, nsFrameManager* aFrameManager) @@ -1017,6 +1019,9 @@ PresShell::Init(nsIDocument* aDocument, #endif os->AddObserver(this, "memory-pressure", false); os->AddObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC, false); + if (XRE_IsParentProcess() && !sProcessInteractable) { + os->AddObserver(this, "sessionstore-one-or-no-tab-restored", false); + } } } @@ -1245,6 +1250,9 @@ PresShell::Destroy() #endif os->RemoveObserver(this, "memory-pressure"); os->RemoveObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC); + if (XRE_IsParentProcess()) { + os->RemoveObserver(this, "sessionstore-one-or-no-tab-restored"); + } } } @@ -8281,6 +8289,32 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, double lastMillis = (sLastInputProcessed - sLastInputCreated).ToMilliseconds(); Telemetry::Accumulate(Telemetry::INPUT_EVENT_RESPONSE_COALESCED_MS, lastMillis); + + if (MOZ_UNLIKELY(!sProcessInteractable)) { + // For content process, we use the ready state of + // top-level-content-document to know if the process has finished the + // start-up. + // For parent process, see the topic + // 'sessionstore-one-or-no-tab-restored' in PresShell::Observe. + if (XRE_IsContentProcess() && + mDocument && mDocument->IsTopLevelContentDocument()) { + switch (mDocument->GetReadyStateEnum()) { + case nsIDocument::READYSTATE_INTERACTIVE: + case nsIDocument::READYSTATE_COMPLETE: + sProcessInteractable = true; + break; + default: + break; + } + } + } + if (MOZ_LIKELY(sProcessInteractable)) { + Telemetry::Accumulate(Telemetry::INPUT_EVENT_RESPONSE_POST_STARTUP_MS, + lastMillis); + } else { + Telemetry::Accumulate(Telemetry::INPUT_EVENT_RESPONSE_STARTUP_MS, + lastMillis); + } } sLastInputCreated = aEvent->mTimeStamp; } else if (aEvent->mTimeStamp < sLastInputCreated) { @@ -9719,6 +9753,19 @@ PresShell::Observe(nsISupports* aSubject, return NS_OK; } + // For parent process, user may expect the UI is interactable after a + // tab (previously opened page or home page) has restored. + if (!nsCRT::strcmp(aTopic, "sessionstore-one-or-no-tab-restored")) { + MOZ_ASSERT(XRE_IsParentProcess()); + sProcessInteractable = true; + + nsCOMPtr os = mozilla::services::GetObserverService(); + if (os) { + os->RemoveObserver(this, "sessionstore-one-or-no-tab-restored"); + } + return NS_OK; + } + NS_WARNING("unrecognized topic in PresShell::Observe"); return NS_ERROR_FAILURE; } diff --git a/layout/base/PresShell.h b/layout/base/PresShell.h index 2fcd9fc76aa6..4c1eaafb5a15 100644 --- a/layout/base/PresShell.h +++ b/layout/base/PresShell.h @@ -902,6 +902,8 @@ protected: static mozilla::TimeStamp sLastInputCreated; static mozilla::TimeStamp sLastInputProcessed; + + static bool sProcessInteractable; }; } // namespace mozilla diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 9a558ddc122b..4c35f038aba2 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -6520,6 +6520,28 @@ "releaseChannelCollection": "opt-out", "description": "Time (ms) from the Input event being created to the end of it being handled, but with overlapping events coalesced." }, + "INPUT_EVENT_RESPONSE_STARTUP_MS": { + "record_in_processes": ["main", "content"], + "alert_emails": ["wpan@mozilla.com"], + "bug_numbers": [1373814], + "expires_in_version": "61", + "kind": "exponential", + "high": 10000, + "n_buckets": 50, + "releaseChannelCollection": "opt-out", + "description": "Time (ms) from the Input event being created to the end of it being handled, but with overlapping events coalesced, which happens before the process is ready for interaction." + }, + "INPUT_EVENT_RESPONSE_POST_STARTUP_MS": { + "record_in_processes": ["main", "content"], + "alert_emails": ["wpan@mozilla.com"], + "bug_numbers": [1373814], + "expires_in_version": "61", + "kind": "exponential", + "high": 10000, + "n_buckets": 50, + "releaseChannelCollection": "opt-out", + "description": "Time (ms) from the Input event being created to the end of it being handled, but with overlapping events coalesced, which happens after the process is ready for interaction." + }, "LOAD_INPUT_EVENT_RESPONSE_MS": { "record_in_processes": ["main", "content"], "alert_emails": ["perf-telemetry-alerts@mozilla.com"],