Fenix hangs and memory usage jumps on theguardian.com when opening headlines in new tab
Categories
(Fenix :: Performance, defect, P2)
Tracking
(Performance Impact:high)
Performance Impact | high |
People
(Reporter: mcomella, Unassigned)
References
(Depends on 1 open bug, Blocks 1 open bug)
Details
(Keywords: perf:resource-use, perf:responsiveness, reproducible, Whiteboard: [fxdroid] [foundation]perf-android)
Attachments
(2 files)
Moved from https://github.com/mozilla-mobile/fenix/issues/26554:
Steps to reproduce
- Go to https theguardian.com/uk, an English language newspaper website with multiple clickable headlines. I have not been able to reproduce the problem on any other website.
- Long press any headline or article to open it in a new tab.
- Repeat by opening three more headlines or articles, each in a new tab.
- Firefox will stop responding for (at best) a minute or two.
Expected behavior
- The page should allow me to continue selecting items for opening in new tabs, so that I have a set of pages ready to read.
- When I review these other pages in their respective tabs, rendering should be near instantaneous exactly as usual.
Actual behavior
- Firefox stops accepting long press - or indeed any press. On a good day I can scroll up and down the part of the page that has already been rendered, but unrendered visuals "below the visible page" will not be rendered and I end up scrolling a blank page.
- New tabs and those I might have had open before this test will not render - I get a blank page for each.
- After a minute or so, Firefox might start to respond again, sluggishly recognising some earlier presses, but rendering is gone.
The workaround is to press Home on the Android device and swipe out Firefox. Wait a minute. Restart Firefox. At this point rendering will work fine again until I open more than two or three tabs from this particular website.
Looking in the phone's Settings / System / Developer options / Memory, I see that during this event Firefox memory usage has suddenly escalated from around 500MB way up to multiple GB - often near the limit of the phone. This can cause even the phone's app launcher to struggle to run.
Device information
Android device: OnePlus 5T (Android 10) with 8GB RAM
Fenix version: ?
Firefox 103.2.0 (Build #2015895963)
┆Issue is synchronized with this Jira Task
Our QA team was able to reproduce on a OnePlus 6T on Nightly and was unable to reproduce on Chrome. They and provided profiles:
- https://profiler.firefox.com/public/7qqacntbqznkn9ppx87k435rttkq44vvzn72ye8
- https://profiler.firefox.com/public/xdy7dfseks2adz6mgdc31qpvsxaaz8dwbsjw7c8
During fenix performance triage, we found specific issues in the profiles and decided to move it to Bugzilla:
Triage: we suspect the root cause is a platform issue because, in the first profile, there are large jank markers in the child process w/ near 100% CPU use over 30 seconds and we see a lengthy GC calls when the original reporter mentioned unexpectedly high memory usage. By contrast, the JVM profile has nothing out of the ordinary.
And gave it a priority:
The Performance Priority Calculator has determined this bug's performance priority to be P1. If you'd like to request re-triage, you can reset the Performance flag to "?" or needinfo the triage sheriff.
Platforms: Android
Impact on browser UI: Renders browser effectively unusable
Impact on site: Renders site effectively unusable
[x] Causes severe resource usage
[x] Able to reproduce locally
However, we lacked the expertise to put it in an appropriate component: please find the proper component to put this in.
Comment 1•2 years ago
|
||
The second profile has a part where a script appears to get stuck in a loop: https://share.firefox.dev/3RVGWBw
Comment 2•2 years ago
|
||
Oh, in the first profile we can see that it's not actually stuck, it does end up finishing eventually, after about 30 seconds: https://share.firefox.dev/3dbS0eP
Updated•2 years ago
|
Comment 3•1 year ago
|
||
This GitHub issue says the loading performance is "fixed" by using uBlock Origin to block some scripts.
https://github.com/mozilla-mobile/fenix/issues/27300#issuecomment-1359110027
Comment 5•1 year ago
|
||
The severity field for this bug is set to S3. However, the Performance Impact
field flags this bug as having a high impact on the performance.
:cpeterson, could you consider increasing the severity of this performance-impacting bug? Alternatively, if you think the performance impact is lower than previously assessed, could you request a re-triage from the performance team by setting the Performance Impact
flag to ?
?
For more information, please visit auto_nag documentation.
Updated•1 year ago
|
Comment 6•1 year ago
|
||
Yes, this is reproducible with the latest Nightly 111.0a1 (2023-01-31) build.
The described actual result is pretty accurate. The websites opened in a new tab continued to remain blank even after refresh.
Device used: Oppo Find X5 (Android 12). - 8Gb RAM.
Updated•1 year ago
|
Comment 7•9 months ago
|
||
Comment 8•9 months ago
|
||
Comment 9•9 months ago
|
||
TLDR: The most simple mitigation: ** If you do "Reject All“ in "Manage or reject cookies" , the site becomes normal. **
A bit deeper:
The stucked function could be tracked to the code in https://assets.guim.co.uk/javascripts/commercial/3dabdb74146e378e768c/graun.standalone.commercial.js?http3=true. The function will be executed if you accept the consent to to track scroll depth.
var Qc = function() {
var n, r = (n = function*() {
var n, r = yield(0, e.B4)();
"tcfv2" == r.framework && null !== (n = r.tcfv2) && void 0 !== n && n.consents[8] || r.canTarget ? ((() => {
var e = document.body.offsetHeight,
n = window.innerHeight,
r = Math.floor(e / n),
i = p.get();
i.setProperty("pageHeightVH", r);
for (var o = new IntersectionObserver((e => {
e.forEach((e => {
if (e.isIntersecting) {
var n = String(e.target.getAttribute("data-depth"));
(0, t.c)("commercial", "current scroll depth ".concat(n)), i.mark("scroll-depth-vh-".concat(n)), o.unobserve(e.target)
}
}))
})), a = 1; a <= r; a++) {
var s = document.createElement("div");
s.dataset.depth = String(a), s.style.top = String(100 * a) + "%", s.style.position = "absolute", s.className = "scroll-depth-marker", document.body.appendChild(s), o.observe(s)
}
})(), (0, t.c)("commercial", "tracking scroll depth")) : (0, t.c)("commercial", "No consent to track scroll depth")
}, function() {
var e = this,
t = arguments;
return new Promise((function(r, i) {
var o = n.apply(e, t);
function a(e) {
Xc(o, r, i, a, s, "next", e)
}
function s(e) {
Xc(o, r, i, a, s, "throw", e)
}
a(void 0)
}))
});
return function() {
return r.apply(this, arguments)
}
}();
Since theguardian provides source map. Above function resolves to
webpack://guardian/commercial/src/core/track-scroll-depth.ts
import { log } from '@guardian/libs';
import { EventTimer } from './event-timer';
/**
* Collect commercial metrics on scroll depth
* Insert hidden elements at intervals of 1 viewport height
* then use an intersection observer to mark the time when the viewport intersects with these elements.
* Approach inspired by https://gist.github.com/bgreater/2412517f5a3f9c6fc4cafeb1ca71384f
*/
const initTrackScrollDepth = () => {
const pageHeight = document.body.offsetHeight;
const intViewportHeight = window.innerHeight;
// how many viewports tall is the page?
const pageHeightVH = Math.floor(pageHeight / intViewportHeight);
const eventTimer = EventTimer.get();
eventTimer.setProperty('pageHeightVH', pageHeightVH);
const observer = new IntersectionObserver(
/* istanbul ignore next */
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const currentDepthVH = String(entry.target.getAttribute('data-depth'));
log('commercial', `current scroll depth ${currentDepthVH}`);
eventTimer.mark(`scroll-depth-vh-${currentDepthVH}`);
observer.unobserve(entry.target);
}
});
});
for (let depth = 1; depth <= pageHeightVH; depth++) {
const div = document.createElement('div');
div.dataset.depth = String(depth);
div.style.top = String(100 * depth) + '%';
div.style.position = 'absolute';
div.className = 'scroll-depth-marker';
document.body.appendChild(div);
observer.observe(div);
}
};
export { initTrackScrollDepth };
and
webpack://guardian/commercial/src/lib/track-scroll-depth.ts
import { onConsent } from '@guardian/consent-management-platform';
import { log } from '@guardian/libs';
import { initTrackScrollDepth } from 'core/track-scroll-depth';
/**
* Initialise scroll depth / velocity tracking if user has consented to relevant purposes.
* @returns Promise
*/
export const init = async () => {
const state = await onConsent();
if (
// Purpose 8 - Measure content performance
(state.framework == 'tcfv2' && state.tcfv2?.consents[8]) ||
state.canTarget) {
initTrackScrollDepth();
log('commercial', 'tracking scroll depth');
}
else {
log('commercial', 'No consent to track scroll depth');
}
};
So if there's an infinite loop , pageHeightVH
(aka `document.body.offsetHeight / window.innerHeight) is the most suspicious value.
I made a simple test html. See attachment index.html , page2.html .
The result is ,
- if you click the link directly , windows.innerHeight have value , 770 on my device.
- if you long click the link and then choose "open link in new tab" and then switch to the new opened tab , Oooops windows.innerHeight is 0 ,which will definitely cause infinite loop
I'm not familiar with GeckoView 's internal mechanism. So i could only dig to here.
Besides , document.body.offsetHeight is different too , in 1) is 1245 and in 2) is 4112 . (Based on my device)
Comment 10•9 months ago
|
||
Thank you jackyzy823 for the excellent sleuthing!
Botond, is this something you could advise on? I don't think this is something that falls in the GeckoView side.
Comment 11•9 months ago
|
||
Thanks Jon for the heads up, and thank you Jacky for the reduced testcase!
It looks like the issue described in comment 9 is a compat issue where Firefox and Chrome have different behaviour in their handling of innerHeight
in a background tab. I filed bug 1853078 for this, with a hosted version of the reduced testcase so the issue can be tested live.
I marked this bug as depending on bug 1853078, so that once bug 1853078 is fixed, we can confirm that the fix resolves the original issue on the Guardian website.
Updated•8 months ago
|
Updated•8 months ago
|
Updated•8 months ago
|
Updated•8 months ago
|
Comment hidden (spam) |
Updated•2 months ago
|
Updated•2 months ago
|
Description
•