Bug 26641 - Safari consumes 100% CPU after leaving GMail open (gmail is installing a billion timers)
Summary: Safari consumes 100% CPU after leaving GMail open (gmail is installing a bill...
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: New Bugs (show other bugs)
Version: 528+ (Nightly build)
Hardware: Mac OS X 10.5
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-06-22 22:16 PDT by Eric Seidel (no email)
Modified: 2011-06-24 10:45 PDT (History)
8 users (show)

See Also:


Attachments
sample of the hang (207.81 KB, text/plain)
2009-06-22 22:17 PDT, Eric Seidel (no email)
no flags Details
Same hang, again today (291.46 KB, text/plain)
2009-06-23 12:53 PDT, Eric Seidel (no email)
no flags Details
Sample from 8/25/09 (96.40 KB, text/plain)
2009-08-25 12:25 PDT, Eric Seidel (no email)
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Eric Seidel (no email) 2009-06-22 22:16:56 PDT
Safari hung at 100% CPU marking gmail objects

This is the second day in a row I've come back to my personal laptop to find it hung on gmail.com.  This is likely gmail.com's fault, but we shouldn't hang the browser like this... i don't think.
Comment 1 Eric Seidel (no email) 2009-06-22 22:17:33 PDT
Created attachment 31704 [details]
sample of the hang
Comment 2 Eric Seidel (no email) 2009-06-23 12:53:56 PDT
Created attachment 31728 [details]
Same hang, again today
Comment 3 Eric Seidel (no email) 2009-06-23 12:54:49 PDT
Safari Version 4.0 (5530.17).  I'm not running TOT WebKit, or a nightly.  Just the standard install.
Comment 4 Eric Seidel (no email) 2009-06-23 12:56:30 PDT
Today google.com's gmail was open as well.  When I closed the gmail.com tab Safari's CPU usage dropped from 100% to 10%, so I suspect that whatever this hang is may only affect production gmail.
Comment 5 Eric Seidel (no email) 2009-06-23 22:42:44 PDT
Maciej asked for repro steps:

I just leave my gmail tab open.  I think it's using more and more cpu over time, i'm not sure.
I tend to have gmail chat "windows" open as well.  Or at least I have when I've noticed the 100% CPU usage.
Comment 6 Eric Seidel (no email) 2009-08-25 12:24:31 PDT
I took another sample today.  Seems that Gmail is scheduling a bajillion timers.  I've filed http://b/2077633 with the gmail team.
Comment 7 Eric Seidel (no email) 2009-08-25 12:25:09 PDT
Created attachment 38562 [details]
Sample from 8/25/09
Comment 8 Eric Seidel (no email) 2009-08-25 12:38:09 PDT
I wonder if we should have some sort of limit to the number of installed timers a webpage can have.  Maybe we already do?
Comment 9 Dmitry Titov 2009-08-25 14:14:51 PDT
Probably similar to Bug 23865 (at least from WebKit perspective).

There are 2 issues with timer queue:

1. if there are enough (not bazillion) timers that total time of their processing becomes larger then the typical 'next time firing' set in the application, the page starts to consume 100% CPU, not necessarily growing the number of timers. It's a bad application, not sure browser can help here, limit won't work because all you need is 10 timers with 100ms work each rescheduling itself to repeat in 1000ms.

2. the number of timers can explode, caused by non-trivial problems like a fixed-interval timer that schedules a web of short-delay timers to do the pieces of work (avoiding UI block), and unfortunate conditions when all those timers have too much work as in #2 - the total number of timers grows then. Or it can be just a plain bug, something like a timer creating 2 timers recursively.

In case #2, when the number of timers grows, the user input can be starved pretty quickly to the point that it'll be hard to even close the page. The fix for that is attached to bug 23865.

It's not clear to me how to limit the number of timers. Obviously it has to be per-DOMWindow, but what's the limit? Too much depends on what actually is done inside the timer's callback and how often timers are scheduled, so some constant could be too small or too big. Doing some dynamic limit based on measuring processing times may cause applications to randomly stop working for reasons like occasional swapping... JS in general allows resources to be allocated while there are resources, provided user is always in control (can close or reload the window).
Comment 10 Iain Merrick 2011-06-24 07:51:32 PDT
Any progress on this?

I'm seeing the same thing happening on techcrunch.com on low-end hardware. The site installs thousands of timers and sometimes the browser just can't keep up.

It looks like the minimum timer interval logic in DOMTimer.cpp doesn't have any effect, because it's only applied to individual timers. If a site makes 1000 separate setTimeout() calls, they will all try to run at once.

I think all JS timers for a given ScriptExecutionContext should be throttled together. If I call setTimeout() 1000 times, we should stagger their start times by minimumTimerInterval().

We may also want to dynamically increase minimumTimerInterval() if timers are regularly missing their deadlines.

I'm happy to pick up this task, if nobody else is working on it.
Comment 11 Dmitry Titov 2011-06-24 10:45:24 PDT
(In reply to comment #10)

> I'm seeing the same thing happening on techcrunch.com on low-end hardware. The site installs thousands of timers and sometimes the browser just can't keep up.

Isn't it the site issue?

> It looks like the minimum timer interval logic in DOMTimer.cpp doesn't have any effect, because it's only applied to individual timers. If a site makes 1000 separate setTimeout() calls, they will all try to run at once.

That logic is not intended to fix the 1000 timers issue. setTimout(foo, 0) is surprisingly popular pattern for doing work on the next JS invokation, 'yield' of sort. Sites often do it in a loop - do some work, schedule another portion etc, so without that logic many sites would go into 100% CPU even with a single timer. There were attempt to remove it and it broke a part of the Web :-)

> I think all JS timers for a given ScriptExecutionContext should be throttled together. If I call setTimeout() 1000 times, we should stagger their start times by minimumTimerInterval().

I don't see how it can fix the #1 from my list above. If each timer has at least minimumTimerInterval of work, they will still consume 100% cpu. If you meant to have a fixed interval between finishing of a timer callback  and any other timer starting the callback, this will unnecessary slow down pages that could otherwise benefit from better hardware. 

> We may also want to dynamically increase minimumTimerInterval() if timers are regularly missing their deadlines.

What exactly is that you are trying to find a solution for? Is it browser responsiveness to user input, so user still can close offending page? Fairness in CPU allocation between pages? Slowing effect of 'busy' page which is in a background tab on the page that is in the foreground tab? Effect all of this has on other applications in the system? Battery life being eaten w/o user realizing that?

The solution probably depends on the goal here. For example, "slow script" dialog is sometimes used in similar situations to let user close the resource-hogging page.