Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Looping Too Fast with postMessage

44 views
Skip to first unread message

secretrobotron

unread,
Nov 23, 2011, 4:57:28 PM11/23/11
to
In the Paladin group, we're creating a game engine called Gladius, and
we're actively discussing how to implement very fundamental things
like schedulers.

Currently, we're able to circumvent the limit imposed on traditional
looping techniques (setTimeout, setInterval, requestAnimationFrame) by
using a trick with postMessage we discovered in the great ether of the
internet.

If a handler is setup to listen for "message" events on the window, it
will receive messages from a call to "postMessage( 'anythingYouWant',
'*' );". If that handler in turn calls the same (or similar)
postMessage, the handler will be called again, giving us a loop.

The problem is that this loop actually runs pretty quick -- a lot
quicker than "setTimeout( 0 )". Moreover, it's not quite the same as
simply doing "while(true) {}", because the browser tries to handle the
messaging done with postMessage. So, you do get some responsiveness
from the browser. However, whichever core on which this code is run is
quickly consumed and, frequently, my window manager starts to implode.

I suppose my question is what's a game developer to do? I'm certainly
not convinced that this technique makes any sense because it's
actually a hack and, for the sake of the web, it should probably be
stopped by browser vendors (or else say goodbye to your laptop
battery). Using setTimeout is always an option, but from the
standpoint of a traditional game developer, it's less optimal than a
main game loop that runs as fast as possible. In JS, we just don't
have a way to yield to the browser afaik (like yielding to the OS in
the traditional game dev sense).

You can check out an example here:
http://jsfiddle.net/4GxNh/14/

Click the "Slow" button to run a traditional loop. The timer reads
about 3 or 4 on my machine running Chromium. Click the "Fast" button
to run the postMessage hack and the timer should read 0 or 1, and your
CPU usage will go through the roof (p.s. SAVE YOUR WORK FIRST).

Kyle Huey

unread,
Nov 23, 2011, 5:33:50 PM11/23/11
to secretrobotron, dev-pl...@lists.mozilla.org
> _______________________________________________
> dev-platform mailing list
> dev-pl...@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-platform
>

We haven't applied the same throttling to postMessage that we have to
setTimeout because it hasn't been abused yet on the web. I fully expect
that we will need to do that in the relatively near future.

I'm not sure what your actual question is here, beyond "can I rely on this
postMessage behavior?" to which the answer is no.

- Kyle

secretrobotron

unread,
Nov 23, 2011, 5:43:26 PM11/23/11
to
On Nov 23, 5:33 pm, Kyle Huey <m...@kylehuey.com> wrote:
> > dev-platf...@lists.mozilla.org
> >https://lists.mozilla.org/listinfo/dev-platform
>
> We haven't applied the same throttling to postMessage that we have to
> setTimeout because it hasn't been abused yet on the web.  I fully expect
> that we will need to do that in the relatively near future.
>
> I'm not sure what your actual question is here, beyond "can I rely on this
> postMessage behavior?" to which the answer is no.
>
> - Kyle

I think my question has several parts, and that's definitely one of
them. I appreciate the answer and obviously, we shouldn't rely on this
trick.

But, really, should this be a bug that I file?

My broader question is what else is there, or does it really matter? I
had a bit of a discussion with a gfx engineer here about framebuffers
and flipping, and it's probably not necessary to think about since the
browser handles it for us (compositing, etc). In a similar vein,
should we even attempt to get around looping limitations to run
simulations faster than graphics processing? Are there more uses for
letting a developer demand most of the processing power of the brower
(and the machine), yielding when necessary, perhaps with proper
acknowledgement from the user (e.g. "This page wants to run a game.
Will you let it consume your computer?")?

Robert O'Callahan

unread,
Nov 23, 2011, 6:40:14 PM11/23/11
to secretrobotron, dev-pl...@lists.mozilla.org
It's not clear to me what you're trying to do.

If you need to run multiple simulation steps per rendered frame, why not
use requestAnimationFrame and run multiple simulation steps all at once
before you render the frame? You can monitor Date.now(), or the rate at
which you're getting requestAnimationFrame, to make sure you're not using
too much time in your simulation.

Rob
--
"If we claim to be without sin, we deceive ourselves and the truth is not
in us. If we confess our sins, he is faithful and just and will forgive us
our sins and purify us from all unrighteousness. If we claim we have not
sinned, we make him out to be a liar and his word is not in us." [1 John
1:8-10]

Boris Zbarsky

unread,
Nov 24, 2011, 12:39:00 PM11/24/11
to
On 11/23/11 4:57 PM, secretrobotron wrote:
> The problem is that this loop actually runs pretty quick -- a lot
> quicker than "setTimeout( 0 )".

Well, yes. Nested setTimeout(0) is clamped to 4ms. postMessage is not
clamped, so it's processed as fast as we can spin the event loop.

> Moreover, it's not quite the same as simply doing "while(true) {}"

Yes, because it goes through the event loop. Presumably this is a
desired feature from your point of view.

> I suppose my question is what's a game developer to do?

That depends on what you're _trying_ to do. What's the goal?

> Using setTimeout is always an option, but from the
> standpoint of a traditional game developer, it's less optimal than a
> main game loop that runs as fast as possible.

Why does this main loop need to run more than once per display frame?
Is there a short explanation for the non-game-developers among us?
Understanding that will give us a better idea of the answer to your
question...

> In JS, we just don't have a way to yield to the browser afaik

Well, postMessage certainly yields.

> (like yielding to the OS in the traditional game dev sense).

On desktop OSes, at least, you don't yield to the OS; the OS just
preempts you.... Not sure what you mean here.

-Boris

Benoit Jacob

unread,
Nov 24, 2011, 1:36:00 PM11/24/11
to Boris Zbarsky, dev-pl...@lists.mozilla.org
I've just had a chat with Bobby, and if I understand correctly,
ideally, he just wants a way to do as much work as possible in JS
without blocking the browser for too long.

It seems that his need would be addressed if there was a way to say,
in JS, "this section of JS code is safe for the browser to preempt".
Something like BEGIN_PREEMPTIBLE, END_PREEMPTIBLE. Has that been
discussed already? A typical use case would be when running a big
mathematical computation. A typical NON-use case would be during the
rendering of a WebGL scene (preempting that would result in broken
rendering). It would be the JS programmer's responsibility to put
these keywords only where they're safe to use.

Sounds reasonable?

Benoit

2011/11/24 Boris Zbarsky <bzba...@mit.edu>:

Boris Zbarsky

unread,
Nov 24, 2011, 2:08:39 PM11/24/11
to
On 11/24/11 1:36 PM, Benoit Jacob wrote:
> I've just had a chat with Bobby, and if I understand correctly,
> ideally, he just wants a way to do as much work as possible in JS
> without blocking the browser for too long.

And he wants the browser to define "too long"? And he can't do it in a
worker?

> A typical use case would be when running a big
> mathematical computation.

That use case is what workers are for, imo.

-Boris

Ehsan Akhgari

unread,
Nov 24, 2011, 2:09:49 PM11/24/11
to Benoit Jacob, Boris Zbarsky, dev-pl...@lists.mozilla.org
The browser does preempt the execution already if it takes too long (by
aborting the execution and showing the slow script dialog). But that's not
too useful to web developers. ;-)

As I suggested this in person, I think the best solution at least on the
existing web platform is to use workers.

Cheers,
--
Ehsan
<http://ehsanakhgari.org/>


On Thu, Nov 24, 2011 at 1:36 PM, Benoit Jacob <jacob.b...@gmail.com>wrote:

> I've just had a chat with Bobby, and if I understand correctly,
> ideally, he just wants a way to do as much work as possible in JS
> without blocking the browser for too long.
>
> It seems that his need would be addressed if there was a way to say,
> in JS, "this section of JS code is safe for the browser to preempt".
> Something like BEGIN_PREEMPTIBLE, END_PREEMPTIBLE. Has that been
> discussed already? A typical use case would be when running a big
> mathematical computation. A typical NON-use case would be during the
> rendering of a WebGL scene (preempting that would result in broken
> rendering). It would be the JS programmer's responsibility to put
> these keywords only where they're safe to use.
>
> Sounds reasonable?
>
> Benoit
>
> 2011/11/24 Boris Zbarsky <bzba...@mit.edu>:

secretrobotron

unread,
Nov 25, 2011, 10:53:14 AM11/25/11
to
On Nov 24, 2:09 pm, Ehsan Akhgari <ehsan.akhg...@gmail.com> wrote:
> The browser does preempt the execution already if it takes too long (by
> aborting the execution and showing the slow script dialog).  But that's not
> too useful to web developers.  ;-)
>
> As I suggested this in person, I think the best solution at least on the
> existing web platform is to use workers.
>
> Cheers,
> --
> Ehsan
> <http://ehsanakhgari.org/>
>
> On Thu, Nov 24, 2011 at 1:36 PM, Benoit Jacob <jacob.benoi...@gmail.com>wrote:
>
>
>
>
>
>
>
> > I've just had a chat with Bobby, and if I understand correctly,
> > ideally, he just wants a way to do as much work as possible in JS
> > without blocking the browser for too long.
>
> > It seems that his need would be addressed if there was a way to say,
> > in JS, "this section of JS code is safe for the browser to preempt".
> > Something like BEGIN_PREEMPTIBLE, END_PREEMPTIBLE. Has that been
> > discussed already? A typical use case would be when running a big
> > mathematical computation. A typical NON-use case would be during the
> > rendering of a WebGL scene (preempting that would result in broken
> > rendering). It would be the JS programmer's responsibility to put
> > these keywords only where they're safe to use.
>
> > Sounds reasonable?
>
> > Benoit
>
> > 2011/11/24 Boris Zbarsky <bzbar...@mit.edu>:
> > > dev-platf...@lists.mozilla.org
> > >https://lists.mozilla.org/listinfo/dev-platform
>
> > _______________________________________________
> > dev-platform mailing list
> > dev-platf...@lists.mozilla.org
> >https://lists.mozilla.org/listinfo/dev-platform

As an engine developer, it's desirable to provide high-resolution
timers to game developers. It's understandable that the browser wants
to do a bunch of stuff in the 4ms delay after calling setTimeout(0),
like IO, rendering, clean up, etc. But, if it doesn't need the entire
4ms, we'd love to have context back to do more processing. Ehsan was
quick to tell me that the delay is necessary to keep the browser
responsive regardless of what you're doing, especially if you have
lots of apps open in different tabs.

That said, we're thinking pretty deeply about how to use Ehsan and
Boris' advice. Most of our engine can be inside of a worker, which is
interesting, because we can probably just run an actual game-loop
there, which feels a lot more like a traditional game environment.

Boris, would you say that the postMessage approach *should* be clamped
anyway?

If we can get that working smoothly, our problems are more-or-less
solved, because we can rely on the main thread to do our rendering. Of
course, we'll just have to make sure the data transfer from the worker
thread to the render thread is quick and small.

Boris Zbarsky

unread,
Nov 25, 2011, 10:58:46 PM11/25/11
to
On 11/25/11 10:53 AM, secretrobotron wrote:
> Boris, would you say that the postMessage approach *should* be clamped
> anyway?

I'd rather not do that there unless sites start commonly
abusing/misusing it (as they have setTimeout(0) because it started out
being clamped in browsers), because it would cripple some use completely
sane use cases.

-Boris
0 new messages