The debugger can cause webpage lagging
Categories
(Core :: JavaScript Engine, defect, P3)
Tracking
()
Performance Impact | low |
People
(Reporter: yjbrowserjyt, Unassigned)
References
(Depends on 1 open bug, )
Details
(Keywords: perf:animation, reproducible)
Attachments
(1 file)
642.74 KB,
video/mp4
|
Details |
User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.183
Firefox for Android
Steps to reproduce:
To prevent web pages from being debugged, the industry typically employs a timer to enter the debugger loop.
just like:
setInterval(function(){
check();
}, 2000);
var check = function(){
function doCheck(a){
if (('' + a / a)['length'] !== 1 || a % 20 === 0){
(function() {}'constructor'());
} else {
(function() {}'constructor'());
}
doCheck(++a);
}
try {
doCheck(0);
}catch(err){}
};
check();
In Firefox browser on Android, there may be lags or slowdowns when the page is scrolling or when there are canvas drawings present.
Actual results:
I have created a test website to test for you. When you click the button in the top-left corner, the yellow ball rotation becomes laggy.
https://www.yjllq.com/fpstest.html
Expected results:
I believe that the Android version of Firefox (GeckoView) should have a master switch. When the device is connected for debugging, this master switch would be turned on, and the debugger would take effect. At other times, the debugger should be an empty implementation and not cause any lag.
Comment 1•1 year ago
|
||
The Bugbug bot thinks this bug should belong to the 'DevTools::Debugger' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.
Comment 3•1 year ago
|
||
Actual snippet from the example with debugger keywords:
let check = function(){
function doCheck(a){
if (('' + a / a)['length'] !== 1 || a % 20 === 0){
(function() {}['constructor']('debugger')());
} else {
(function() {}['constructor']('debugger')());
}
doCheck(++a);
}
try {
doCheck(0);
}catch(err){}
};
function start(){
setInterval(function(){
check();
}, 1000);
Comment 4•1 year ago
|
||
Looks like the STRs do not involve starting devtools or trying to debug the page. Simply having this script with debugger statements slows down the page on geckoview?
(In reply to Julian Descottes [:jdescottes] from comment #4)
Looks like the STRs do not involve starting devtools or trying to debug the page. Simply having this script with debugger statements slows down the page on geckoview?
Yes, as long as this statement is executed, it will cause the page to stall and there is no need to run devtool. But this statement will be frequently applied to prevent web pages from being debugged. Running this statement in Chrome does not cause stuttering. I think geckoview should fix this issue.
Comment 6•1 year ago
|
||
The severity field is not set for this bug.
:owlish, could you have a look please?
For more information, please visit BugBot documentation.
Comment 7•1 year ago
|
||
Reproduces for me on desktop as well
Comment 8•9 months ago
|
||
Verified this issue and it's still reproducible on Firefox versions 123 and 125.
Environment:
Operating system: Windows 10 / OnePlus 6 A6000 (Android 11)
Browsers: Firefox Nightly 125.0a1 (2024-02-20) / Firefox Release 123 / Chrome 121.0.6167.185
Notes:
- Not reproducible on Chrome
- Same behaviour on android
Updated•9 months ago
|
Updated•7 months ago
|
Comment 9•7 months ago
|
||
Leaving a ni myself to capture a perf profile
Comment 10•7 months ago
|
||
There are a few separate issues going on here:
-
The testcase is spamming
new Function(...)
in a loop that can cause performance problems without any debugger attached or debugger statement included. This is a performance issue that we can compare with chrome and see if it could be sped up slightly. Theif
statement is simply trying to confuse JITs so they don't optimize away things. I don't know if current versions of Firefox or Chrome optimize through this or not. -
This testcase recurses until an exception is thrown, so it is also sensitive to stack limits of different browsers. In the past (eg. Bug 1537609) we found some cases in the wild affected by this but have since set a reasonable limit.
-
When a debugger is attached in Firefox, it fires a hook on every new script (including those generated by
new Function
) which slows the page down further. This is independent of whether a debugger statement is present. We could consider ignoring / speeding-up scripts that are dynamically injected if we thought this anti-debugger technique was actually a concern (noting that without the debugger, there is already performance problems on the page from spamming new functions). -
Actually running code in a loop with 'debugger' statement is a classic evil-trap, but firefox debugger does have the easy ability to turn off breaking on these statements already.
Realistically, only point 1 is worth doing much about and that is just a general performance matter (mostly GC performance of functions is poorer in Firefox than Chrome). I don't think the assumption of Comment 0 that this is due to debugger is correct.
Comment 11•7 months ago
|
||
Since we think this is a perf issue, I'm going to move this into the perf component.
Comment 12•7 months ago
|
||
This bug was moved into the Performance component.
:yjbrowserjyt, could you make sure the following information is on this bug?
- For slowness or high CPU usage, capture a profile with http://profiler.firefox.com/, upload it and share the link here.
- For memory usage issues, capture a memory dump from
about:memory
and attach it to this bug. - Troubleshooting information: Go to
about:support
, click "Copy raw data to clipboard", paste it into a file, save it, and attach the file here.
If the requested information is already in the bug, please confirm it is recent.
Thank you.
Comment 13•7 months ago
|
||
Profile from Nightly 126.0a1 on Android device: https://share.firefox.dev/3U68vdS
Updated•7 months ago
|
Updated•7 months ago
|
Comment 14•7 months ago
|
||
Moving to the JS engine component.
(In reply to Ted Campbell [:tcampbell] from comment #10)
- The testcase is spamming
new Function(...)
in a loop that can cause performance problems without any debugger attached or debugger statement included. This is a performance issue that we can compare with chrome and see if it could be sped up slightly. Theif
statement is simply trying to confuse JITs so they don't optimize away things. I don't know if current versions of Firefox or Chrome optimize through this or not.[...]
Realistically, only point 1 is worth doing much about and that is just a general performance matter (mostly GC performance of functions is poorer in Firefox than Chrome). I don't think the assumption of Comment 0 that this is due to debugger is correct.
Comment 15•7 months ago
|
||
Without digging into what any other engines are doing here, the key piece here is this line:
(function() {}['constructor']('debugger')());
This is a roundabout way of writing (new Function("debugger"))()
. We end up parsing the input and creating a new script on every invocation. In a stripped down microbenchmark, we spend ~90% of our time inside CreateDynamicFunction. The fact that we create a new script each time also prevents us from (eg) inlining.
We have an eval cache to help us reuse scripts between eval statements. If we wanted to make this case faster, we would presumably have to add a similar cache for the Function constructor.
Bug 1420440 is open to track this.
Comment 16•6 months ago
|
||
The Performance Impact Calculator has determined this bug's performance impact to be low. If you'd like to request re-triage, you can reset the Performance Impact flag to "?" or needinfo the triage sheriff.
Platforms: [x] Windows [x] macOS [x] Linux [x] Android
Websites affected: Rare
[x] Affects animation smoothness
[x] Able to reproduce locally
Description
•