Closed Bug 123273 Opened 22 years ago Closed 22 years ago

setTimeout(something, 0) causes 100% CPU constant

Categories

(Core :: DOM: Core & HTML, defect, P2)

defect

Tracking

()

VERIFIED FIXED
mozilla1.1beta

People

(Reporter: jmd, Assigned: jst)

References

()

Details

(Whiteboard: [HAVE FIX])

Attachments

(2 files)

I'm guessing javascript... with that menu that follows the scroll.

100% CPU use remains even when the browser tab or window doesn't have focus.
this page contains the following JavaScript:
function makeStatic() {
 if (ie4) {...}
  else if (ns6) {...}
  else if (ns4) {...}
 setTimeout("makeStatic()",0);
}

the function is intended to reposition the menu when you scroll, but it
basically runs continuously.
Confirming with Mozilla trunk builds 20020125xx WinNT
OS: Linux ---> All. Here is a larger excerpt from the site:

/*
Static menu script II (By maXimus, maximus@nsimail.com, 
http://maximus.ravecore.com/)
Modified slightly/ permission granted to Dynamic Drive
to feature script in archive For full source, usage terms,
and 100's more DHTML scripts, visit http://dynamicdrive.com
*/

//configure below variable for menu width, position on page
var menuwidth=115
var offsetleft=645
var offsettop=40

var ns4=document.layers?1:0
var ie4=document.all?1:0
var ns6=document.getElementById&&!document.all?1:0

function makeStatic() {
  if (ie4) {
    object1.style.pixelTop=document.body.scrollTop+offsettop
  }else if (ns6) { 
    document.getElementById("object1").style.top=window.pageYOffset+offsettop
  }else if (ns4) {
    eval(document.object1.top=eval(window.pageYOffset+offsettop));
  }

  setTimeout("makeStatic()",0);
}



if (ie4||ns6) {
  document.write('<span ALIGN="CENTER" ID="object1" STYLE="Position:absolute;   
Top:20; Left:'+offsetleft+';   
Z-Index:5;cursor:hand;background-color:black;"><TABLE BORDER="1"   
width="'+menuwidth+'" CELLPADDING="0" CELLSPACING="0" BORDERCOLOR="black"   
bgcolor="white">')

}else if (ns4){ 
  document.write('<LAYER top="20" name="object1" left="'+offsetleft+'"   
BGCOLOR=black><TABLE BORDER="0" CELLPADDING="0" CELLSPACING="1"><TR><TD>
  <TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" width="'+menuwidth+'">')
}
Status: UNCONFIRMED → NEW
Ever confirmed: true
OS: Linux → All
Hardware: PC → All
And farther down, here is what starts the cycle:

window.onload=menu3;

function menu3()
{
  if (ns6||ie4||ns4)
  makeStatic()
}
I don't know why this use of setTimeout('something', 0) pins the CPU
in Mozilla, but not NN4.x or IE6. Reassigning to DOM Level 0 to find out.
This simple script, which I will attach below, is enough to do it:


<HTML><HEAD><TITLE>Bug 123273</TITLE><SCRIPT>

window.onload= makeStatic;

function makeStatic()
{  
 setTimeout("makeStatic()",0);
}

</SCRIPT></HEAD><BODY></BODY></HMTL>
Assignee: rogerl → jst
Component: JavaScript Engine → DOM Level 0
QA Contact: pschwartau → desale
Perhaps NS4 and IE have a minimum timeout.  If Mozilla actually attempts to do a
0 timeout, it *should* use 100% of the CPU.  It's really just an infinite loop.
Netscape4 uses 100% on your testcase.  In fact, NS4 uses 100% for the URL also
for me.

I tested how often it called.  On one machine, it called ~1000 times per second,
but on another it did ~5600 calls per second.  Netscape did ~1300 calls/sec on
the first machine, and ~6000 calls/sec on the second.

IE does not exhibit this "bug" because (on one machine at least) it only does
~18 calls/sec!
Severity = HIGH [Using 100% cpu is as good as crash, Severe functional failure, 
No Cosmetic failure]
Visibility = MEDIUM [Real world website usage, Gets one point of 
compatibility with other browsers since it works better on IE. gets one 
more point on compliance with adopted techonology, that is JS] 

Priority = Visibility * Severity

Priority = p2

adding word "qawanted" because I'm setting this priority on available data & if 
someone feels otherwise then please investigate this more & feel free to change 
this priority.
Keywords: qawanted
Priority: -- → P2
It seems Mozilla should have a reasonable minimum timeout value, or this should
be WONTFIX (or moved to Evang, setting 0 timeout is a bit silly).  FWIW, my vote
would be for WONTFIX/Evang.
I've found another URL where the CPU gets pegged in Mozilla. Figuring it's 
probably not cool to file another bug, I'll just add comments here. The bug is:

http://www.attws.com/mobileinternet/

Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0rc1) Gecko/20020415
Dameon:  the site works fine for me, but if it is banging the CPU for you, it's
probably a different (possibly new) bug.
Okay, will file a different bug
> Perhaps NS4 and IE have a minimum timeout.  If Mozilla actually
> attempts to do a 0 timeout, it *should* use 100% of the CPU.
> It's really just an infinite loop.


Based on Andrew's comment, as I understand things, there are
two possible ways to resolve this bug:

1) Defend against setTimeout(something, 0) by establishing
   an effective minimum timeout value. A developer could 
   write setTimeout(something, 0) without causing an error,
   but effectively it wouldn't have that meaning.

2) Otherwise, this bug is a just a duplicate of bug 13350,
   "DOM needs to police JS infinite loops, schedule garbage collection"


Does that sound right?
Resummarizing; cc'ing Andrew -
Summary: Page uses 100% CPU constant... no animated images/plugins → setTimeout(something, 0) causes 100% CPU constant
yup.  Although, I don't know if the logic in bug 13350 would catch this because
the function is called repeatedly rather than one function never exiting.
*** Bug 137667 has been marked as a duplicate of this bug. ***
The simplified test case pins my CPU on Win2k, Moz 1.0RC1.

(Heh, this ended up being the right bug after all... :-)
*** Bug 134149 has been marked as a duplicate of this bug. ***
While looking at bug 134149 (a dupe of this bug), I was trying to figure out why
IE doesn't eat 100% CPU like Mozilla.  I wrote some JavaScript code with a
function that calls itself 200 times using setTimeout() with timeout = 0.  It
repeats this for all values of timeout up to 50 and displays the wall clock time
it took for each group of 200 calls.  I then imported the data into Excel and
created a graph showing runtime vs. delay/timeout value for IE, Mozilla, and
Opera.  The tests were run under NT4WS+SP6a on a dual PII/333 w/ 320 megs of
RAM, and even though they may be statistically worthless, I figured they might
provide some insight.

http://www.cs.wcu.edu/~rwg/moz/123273/ has the code and graph.  The .pdf
contains the graph, and the .txt and .html files contain the HTML and JavaScript
I used to generate the data -- the only difference is the Content-Type returned
by the server (text/plain vs. text/html).  [I'd upload these as attachments to
the bug, but I'm not sure they'd really belong there.  I'll make them
attachments if requested.]

At first glance, I thought IE must limit timeouts < 15 ms to 15 ms, but that
doesn't explain the other horizontal segments on the graph.  Opera shows the
same behavior except at timeout = 0.  (Bug?)  I'm not sure if IE and Opera round
the timeout value to the next highest multiple of 16 or if the weird graph is a
result of some interaction between the timeout value and the OS's timeslice
length.  Maybe Opera and IE use a timing mechanism that causes them to forfeit
the rest of their timeslice.  I just don't know. :)

At any rate, my vote would be to squash the bug by imposing a minimum timeout
for calls to setTimeout (unless there's JavaScript code used by Mozilla itself
that this would break, of course).  If nobody notices, it doesn't break
anything, and it makes the UI more responsive, that seems like a win-win to me.
This is basically the same conclusion I came to in bug 111982... we spend so
much time trying to service SetTimeout() callbacks, that everything else grinds
to a halt. I don't know if other browsers arbitrarily limit this frequency or
what...

Our ability to service the timer callback tends to be determined by what is
going on in the page... It would be nice if we could determine, on a per page
basis, our ability to service the timer callback and programatically adjust the
floor for callback servicing.
*** Bug 146983 has been marked as a duplicate of this bug. ***
*** Bug 152531 has been marked as a duplicate of this bug. ***
my two cents:

IE and Opera are probably using the Windows API SetTimer() call, which has an
average resolution of ~16ms (depending on how often the calling thread is being
scheduled, what other messages are being posted to the message queue, and
whether the message is to a foreground window. 10ms is minimum and 22ms is max).

IE/Opera behaviour could be emulated by making the timeout evenly divisible by 
16. Something like:

    #define TIMER_RES 0x10 //16ms

    if (interval >= ((~TIMER_RES)+1)) /* prolly should not do timer */
      timeout->interval = ((~TIMER_RES)+1); /* on overflow or < 0 */
    else if (interval < 1) /* catch negative values too */
      timeout->interval = TIMER_RES; 
    else
      timeout->interval = (PRInt32) interval;
    if (timeout->interval % TIMER_RES)
      timeout->interval += (TIMER_RES - (timeout->interval % TIMER_RES));


Do we really care about emulating timer resolution here? I agree that we should
put a minimum value on JS timeouts (16ms?) but other than that I don't really
see the need for emulating the not-precicely-predictable-anyway resolution of
windows timers when timers are never that precise anyways. I.e. IMO the attached
patch should be all we need.

bz, wanna review the attached patch? We could change the min value to 16ms tho...
Status: NEW → ASSIGNED
Whiteboard: [HAVE FIX]
Target Milestone: --- → mozilla1.1beta
Comment on attachment 84079 [details] [diff] [review]
Set 10ms as the min limit for JS timeouts

r=bzbarsky
Attachment #84079 - Flags: review+
Comment on attachment 84079 [details] [diff] [review]
Set 10ms as the min limit for JS timeouts

Rick says sr=rpotts
Attachment #84079 - Flags: superreview+
Fix checked in.
Status: ASSIGNED → RESOLVED
Closed: 22 years ago
Resolution: --- → FIXED
verified w/ linux 2002062004. Negligible CPU use. (course, when scrolling that
page, JS sucks 100%, but that's expected, since JS sucks for real-time movement).
Status: RESOLVED → VERIFIED
Keywords: qawanted
You need to log in before you can comment on or make changes to this bug.