Bug 1692350 - Implement a telemetry probe to collect page load data for documents that use lazyload r=emilio,chutten

Differential Revision: https://phabricator.services.mozilla.com/D104912
This commit is contained in:
Sean Feng
2021-02-17 17:17:52 +00:00
parent c4ac4ac515
commit be7a7a24d9
10 changed files with 122 additions and 9 deletions

View File

@@ -5776,6 +5776,15 @@ var TabsProgressListener = {
stopwatchRunning /* we won't see STATE_START events for pre-rendered tabs */ stopwatchRunning /* we won't see STATE_START events for pre-rendered tabs */
) { ) {
if (recordLoadTelemetry) { if (recordLoadTelemetry) {
if (aBrowser.browsingContext?.topWindowContext?.hadLazyLoadImage) {
let timeElapsed = TelemetryStopwatch.timeElapsed(
histogram,
aBrowser
);
Services.telemetry
.getHistogramById("FX_LAZYLOAD_IMAGE_PAGE_LOAD_MS")
.add(timeElapsed);
}
TelemetryStopwatch.finish(histogram, aBrowser); TelemetryStopwatch.finish(histogram, aBrowser);
BrowserTelemetryUtils.recordSiteOriginTelemetry(browserWindows()); BrowserTelemetryUtils.recordSiteOriginTelemetry(browserWindows());
} }

View File

@@ -260,6 +260,11 @@ bool WindowContext::CanSet(FieldIndex<IDX_IsLocalIP>, const bool& aValue,
return CheckOnlyOwningProcessCanSet(aSource); return CheckOnlyOwningProcessCanSet(aSource);
} }
bool WindowContext::CanSet(FieldIndex<IDX_HadLazyLoadImage>, const bool& aValue,
ContentParent* aSource) {
return IsTop() && CheckOnlyOwningProcessCanSet(aSource);
}
void WindowContext::DidSet(FieldIndex<IDX_SHEntryHasUserInteraction>, void WindowContext::DidSet(FieldIndex<IDX_SHEntryHasUserInteraction>,
bool aOldValue) { bool aOldValue) {
MOZ_ASSERT( MOZ_ASSERT(

View File

@@ -82,7 +82,10 @@ class BrowsingContextGroup;
FIELD(HasReportedShadowDOMUsage, bool) \ FIELD(HasReportedShadowDOMUsage, bool) \
/* Whether the principal of this window is for a local \ /* Whether the principal of this window is for a local \
* IP address */ \ * IP address */ \
FIELD(IsLocalIP, bool) FIELD(IsLocalIP, bool) \
/* Whether the corresponding document has `loading='lazy'` \
* images; It won't become false if the image becomes non-lazy */ \
FIELD(HadLazyLoadImage, bool)
class WindowContext : public nsISupports, public nsWrapperCache { class WindowContext : public nsISupports, public nsWrapperCache {
MOZ_DECL_SYNCED_CONTEXT(WindowContext, MOZ_EACH_WC_FIELD) MOZ_DECL_SYNCED_CONTEXT(WindowContext, MOZ_EACH_WC_FIELD)
@@ -175,6 +178,8 @@ class WindowContext : public nsISupports, public nsWrapperCache {
bool CanShowPopup(); bool CanShowPopup();
bool HadLazyLoadImage() const { return GetHadLazyLoadImage(); }
protected: protected:
WindowContext(BrowsingContext* aBrowsingContext, uint64_t aInnerWindowId, WindowContext(BrowsingContext* aBrowsingContext, uint64_t aInnerWindowId,
uint64_t aOuterWindowId, bool aInProcess, uint64_t aOuterWindowId, bool aInProcess,
@@ -262,6 +267,9 @@ class WindowContext : public nsISupports, public nsWrapperCache {
bool CanSet(FieldIndex<IDX_IsLocalIP>, const bool& aValue, bool CanSet(FieldIndex<IDX_IsLocalIP>, const bool& aValue,
ContentParent* aSource); ContentParent* aSource);
bool CanSet(FieldIndex<IDX_HadLazyLoadImage>, const bool& aValue,
ContentParent* aSource);
void DidSet(FieldIndex<IDX_HasReportedShadowDOMUsage>, bool aOldValue); void DidSet(FieldIndex<IDX_HasReportedShadowDOMUsage>, bool aOldValue);
void DidSet(FieldIndex<IDX_SHEntryHasUserInteraction>, bool aOldValue); void DidSet(FieldIndex<IDX_SHEntryHasUserInteraction>, bool aOldValue);

View File

@@ -15572,6 +15572,17 @@ bool Document::ConsumeTransientUserGestureActivation() {
return wc && wc->ConsumeTransientUserGestureActivation(); return wc && wc->ConsumeTransientUserGestureActivation();
} }
void Document::IncLazyLoadImageCount() {
if (!mLazyLoadImageCount) {
if (WindowContext* wc = GetTopLevelWindowContext()) {
if (!wc->HadLazyLoadImage()) {
Unused << wc->SetHadLazyLoadImage(true);
}
}
}
++mLazyLoadImageCount;
}
void Document::SetDocTreeHadMedia() { void Document::SetDocTreeHadMedia() {
RefPtr<WindowContext> topWc = GetTopLevelWindowContext(); RefPtr<WindowContext> topWc = GetTopLevelWindowContext();
if (topWc && !topWc->IsDiscarded() && !topWc->GetDocTreeHadMedia()) { if (topWc && !topWc->IsDiscarded() && !topWc->GetDocTreeHadMedia()) {

View File

@@ -3739,7 +3739,7 @@ class Document : public nsINode,
} }
DOMIntersectionObserver& EnsureLazyLoadImageObserver(); DOMIntersectionObserver& EnsureLazyLoadImageObserver();
DOMIntersectionObserver& EnsureLazyLoadImageObserverViewport(); DOMIntersectionObserver& EnsureLazyLoadImageObserverViewport();
void IncLazyLoadImageCount() { ++mLazyLoadImageCount; } void IncLazyLoadImageCount();
void DecLazyLoadImageCount() { void DecLazyLoadImageCount() {
MOZ_DIAGNOSTIC_ASSERT(mLazyLoadImageCount > 0); MOZ_DIAGNOSTIC_ASSERT(mLazyLoadImageCount > 0);
--mLazyLoadImageCount; --mLazyLoadImageCount;

View File

@@ -25,6 +25,10 @@ interface WindowContext {
// True if the principal of this window is for a local ip address. // True if the principal of this window is for a local ip address.
readonly attribute boolean isLocalIP; readonly attribute boolean isLocalIP;
// True if the corresponding document has `loading='lazy'` images;
// It won't become false if the image becomes non-lazy.
readonly attribute boolean hadLazyLoadImage;
}; };
// Keep this in sync with nsIContentViewer::PermitUnloadAction. // Keep this in sync with nsIContentViewer::PermitUnloadAction.

View File

@@ -26,3 +26,7 @@ support-files =
support-files = support-files =
file_lazyload_telemetry.html file_lazyload_telemetry.html
image_rgrg-256x256.png image_rgrg-256x256.png
[browser_lazyload_page_load_telemetry_iframe.js]
support-files =
file_lazyload_telemetry.html
image_rgrg-256x256.png

View File

@@ -0,0 +1,48 @@
const baseURL = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://example.com"
);
const testFileURL = `${baseURL}file_lazyload_telemetry.html`;
const { TelemetryTestUtils } = ChromeUtils.import(
"resource://testing-common/TelemetryTestUtils.jsm"
);
function OtherLazyLoadDataIsReported() {
const snapshot = Services.telemetry.getSnapshotForHistograms("main", false)
.content;
return snapshot.LAZYLOAD_IMAGE_TOTAL;
}
function pageLoadIsReported() {
const snapshot = Services.telemetry.getSnapshotForHistograms("main", false)
.parent;
return snapshot.FX_LAZYLOAD_IMAGE_PAGE_LOAD_MS;
}
add_task(async function testTelemetryCollection() {
Services.telemetry.getHistogramById("FX_LAZYLOAD_IMAGE_PAGE_LOAD_MS").clear();
const testTab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
"data:text/html,<body><iframe src='" + testFileURL + "'></iframe></body>",
true
);
await BrowserTestUtils.waitForCondition(pageLoadIsReported);
gBrowser.removeTab(testTab);
// Running this test also causes some other LAZYLOAD related data
// to be collected. Wait for them to be collected to avoid firing
// them at an unexpected time.
await BrowserTestUtils.waitForCondition(OtherLazyLoadDataIsReported);
const snapshot = Services.telemetry.getSnapshotForHistograms("main", false);
ok(
snapshot.parent.FX_LAZYLOAD_IMAGE_PAGE_LOAD_MS.sum > 0,
"lazyload image page load telemetry"
);
});

View File

@@ -9,6 +9,12 @@ const { TelemetryTestUtils } = ChromeUtils.import(
"resource://testing-common/TelemetryTestUtils.jsm" "resource://testing-common/TelemetryTestUtils.jsm"
); );
function pageLoadIsReported() {
const snapshot = Services.telemetry.getSnapshotForHistograms("main", false)
.parent;
return snapshot.FX_LAZYLOAD_IMAGE_PAGE_LOAD_MS;
}
function dataIsReported() { function dataIsReported() {
const snapshot = Services.telemetry.getSnapshotForHistograms("main", false) const snapshot = Services.telemetry.getSnapshotForHistograms("main", false)
.content; .content;
@@ -25,6 +31,7 @@ add_task(async function testTelemetryCollection() {
.getHistogramById("LAZYLOAD_IMAGE_VIEWPORT_LOADING") .getHistogramById("LAZYLOAD_IMAGE_VIEWPORT_LOADING")
.clear(); .clear();
Services.telemetry.getHistogramById("LAZYLOAD_IMAGE_VIEWPORT_LOADED").clear(); Services.telemetry.getHistogramById("LAZYLOAD_IMAGE_VIEWPORT_LOADED").clear();
Services.telemetry.getHistogramById("FX_LAZYLOAD_IMAGE_PAGE_LOAD_MS").clear();
const testTab = await BrowserTestUtils.openNewForegroundTab( const testTab = await BrowserTestUtils.openNewForegroundTab(
gBrowser, gBrowser,
@@ -47,20 +54,21 @@ add_task(async function testTelemetryCollection() {
} }
); );
await BrowserTestUtils.waitForCondition(pageLoadIsReported);
gBrowser.removeTab(testTab); gBrowser.removeTab(testTab);
await BrowserTestUtils.waitForCondition(dataIsReported); await BrowserTestUtils.waitForCondition(dataIsReported);
const snapshot = Services.telemetry.getSnapshotForHistograms("main", false) const snapshot = Services.telemetry.getSnapshotForHistograms("main", false);
.content;
// Ensures we have 4 lazyload images. // Ensures we have 4 lazyload images.
is(snapshot.LAZYLOAD_IMAGE_TOTAL.values[4], 1, "total images"); is(snapshot.content.LAZYLOAD_IMAGE_TOTAL.values[4], 1, "total images");
// All 4 images should be lazy-loaded. // All 4 images should be lazy-loaded.
is(snapshot.LAZYLOAD_IMAGE_STARTED.values[4], 1, "started to load"); is(snapshot.content.LAZYLOAD_IMAGE_STARTED.values[4], 1, "started to load");
// The last image didn't reach to the viewport. // The last image didn't reach to the viewport.
is( is(
snapshot.LAZYLOAD_IMAGE_NOT_VIEWPORT.values[1], snapshot.content.LAZYLOAD_IMAGE_NOT_VIEWPORT.values[1],
1, 1,
"images didn't reach viewport" "images didn't reach viewport"
); );
@@ -68,9 +76,13 @@ add_task(async function testTelemetryCollection() {
// should be three. This includes all images except // should be three. This includes all images except
// the last one. // the last one.
is( is(
snapshot.LAZYLOAD_IMAGE_VIEWPORT_LOADING.sum + snapshot.content.LAZYLOAD_IMAGE_VIEWPORT_LOADING.sum +
snapshot.LAZYLOAD_IMAGE_VIEWPORT_LOADED.sum, snapshot.content.LAZYLOAD_IMAGE_VIEWPORT_LOADED.sum,
3, 3,
"images reached viewport" "images reached viewport"
); );
ok(
snapshot.parent.FX_LAZYLOAD_IMAGE_PAGE_LOAD_MS.sum > 0,
"lazyload image page load telemetry"
);
}); });

View File

@@ -7708,6 +7708,18 @@
"alert_emails": ["tdsmith@mozilla.com", "perf-telemetry-alerts@mozilla.com", "product-metrics-telemetry-alerts@mozilla.com"], "alert_emails": ["tdsmith@mozilla.com", "perf-telemetry-alerts@mozilla.com", "product-metrics-telemetry-alerts@mozilla.com"],
"releaseChannelCollection": "opt-out" "releaseChannelCollection": "opt-out"
}, },
"FX_LAZYLOAD_IMAGE_PAGE_LOAD_MS": {
"record_in_processes": ["main"],
"products": ["firefox"],
"expires_in_version": "never",
"kind": "linear",
"high": 10000,
"n_buckets": 100,
"description": "Firefox: Time taken to load a page that has at least one `loading='lazy'` image. (This metric includes both loads and reloads)",
"bug_numbers": [1692350],
"alert_emails": ["sefeng@mozilla.com", "perf-telemetry-alerts@mozilla.com"],
"releaseChannelCollection": "opt-out"
},
"FX_PAGE_RELOAD_NORMAL_MS": { "FX_PAGE_RELOAD_NORMAL_MS": {
"record_in_processes": ["main"], "record_in_processes": ["main"],
"products": ["firefox", "fennec"], "products": ["firefox", "fennec"],