Cloud9IDE's CPU usage
Thursday, May 12, 2011 12:29:38 AM
The high CPU usage is because they use a postMessage() based hack to avoid the default 4-10ms delay for setTimeout(). Have a look at this code (linewrapped by me):
apf.setZeroTimeout=(apf.isIE&&apf.isIE<9)||apf.isO3||apf.isAIR?setTimeout:(function(){
var timeouts=[];
var messageName="zero-timeout-message";
function setZeroTimeout(fn){
timeouts.push(fn);
window.postMessage(messageName,"*");
}
function handleMessage(e){
if(!e){
e=event;
}
if(e.source==window&&e.data==messageName){
apf.stopPropagation(e);
if(timeouts.length>0){
var fn=timeouts.shift();
fn();
}
}
}
apf.addListener(window,"message",handleMessage,true);
return setZeroTimeout;
}
)();
Whoever came up with this hack knew about setTimeout()'s minimum delay, and realised that a message event thread as opposed to a setTimeout() thread will run immediately after the script calling postMessage(). So, rather than calling setTimeout() they add the function to run to a queue and call window.postMessage('zero-timeout-message', '*'). The message thread picks up the queue and runs any pending functions.
There are probably interesting uses for this, if you're into performance optimisation. (Aside: is this tested in browsers without postMessage() support? The browser sniffing isn't exactly good-looking, and setTimeout() would likely throw a "wrong this object" error when setZeroTimeout() is called in browsers that do not run the fancy postMessage() code). Interesting use cases are things like animations and games that require a high frame rate. However, while the site is loading, the method(s) they are queuing will simply check if XHR requests are finished, and immediately queue the same check again if they are not..
Bypassing the browser's setTimeout() throttling and making the CPU spin at 100% in order to check that 4 files are done loading, may not be the best performance tradeoff after all. So basically, the fancy hack is used to keep the CPU usage high while waiting for XHR requests to finish
.







Jeff WaldenWaldo # Thursday, May 12, 2011 3:25:40 AM
Unregistered user # Thursday, May 12, 2011 8:08:39 AM
MyOpera team, please fix this!fearphage # Thursday, May 12, 2011 12:39:17 PM
Originally posted by hallvors:
setTimeout will default to executing in the global scope... where it always executes. No problem really.Almost related: Here's an oddity with Opera's postMessage implementation not really being async:
http://dl.dropbox.com/u/2400/tc/postmessage-async.htm
Not sure if I filed this one. I couldn't find a spec to support or disprove my expectations.
Charles SchlossChas4 # Thursday, May 12, 2011 1:33:47 PM
Hallvord R. M. Steenhallvors # Thursday, May 12, 2011 1:56:56 PM
Originally posted by fearphage:
Not quite sure if I follow you. If I do
var x={}; x.sTo=window.setTimeout; x.sTo(function(){}, 10);The (few) browsers I tested do indeed throw an error about an unexpected this object for setTimeout(). I don't think the Cloud9 code as-is will work in older browsers.
Charles SchlossChas4 # Thursday, May 12, 2011 3:06:01 PM
Cutting Spoonhellspork # Friday, May 13, 2011 1:18:37 AM
Of course if more browsers >.> had proper support for workers, this probably could have been avoided entirely? Or is there a worker context switch or something else that again slows it all down?
edvakf # Friday, May 13, 2011 6:30:53 AM
I wrote a blog post in Japanese, but the table is language-free.
http://javascript.g.hatena.ne.jp/edvakf/20100227/1267246371
I haven't tested much but I have run into a case where Opera seems to run postMessage'ed async code parallel with normal code?
For animation purpose, I would recommend using img.onerror hack for standard browsers and script.onreadystatechange for IE. Of course, there is an option to use mozRequestAnimationFrame and webkitRequestAnimationFrame too (vendor specific, but better than hacks I guess).
edvakf # Friday, May 13, 2011 6:43:07 AM
I was wrong. That wasn't the case as long as I tested.
MyOpera team, please fix this!fearphage # Saturday, May 14, 2011 8:05:37 AM
Originally posted by hallvors:
Whoops, i didn't see the namespacing. I thought they were just essentially renaming it. You're 100% correct.Mike de Boermikedeboer # Thursday, May 19, 2011 10:30:32 AM
First of all: thanks for pointing us to this Opera issue!
We made a few changes to the code that might fix it for you, but at least gets rid of the ugly browser sniffing: https://github.com/ajaxorg/apf/commit/eb9d01fa51c9c14ca61e5ce378de814441a57507
This is not in production just yet, but will be very soon.
Our setZeroTimeout function has some definite use cases, otherwise it wouldn't be in the APF codebase. However, it's mainly used inside the core of the framework and is not advocated to be used outside of it by developers who use APF to create applications, like Cloud9. It is best practice to use feature detection over browser sniffing and over the years (the project is already over 8 years old) we were able to get rid of most of the browser sniffing code. But not everywhere, as this example illustrates.
At the moment we do not officially support Opera and Internet Explorer 9, unfortunately. We would, however, like to fix this issue, if possible with your help. First of all I'm having difficulties reproducing this issue on the latest Opera version... how are you able to reproduce this issue?
Thank you for the time you are spending on this, I'm an absolute fan of Opera!
Cheers, on behalf of the Cloud9 team,
Mike de Boer
Lead Developer - Ajax.org
Hallvord R. M. Steenhallvors # Saturday, May 21, 2011 8:02:17 AM
I've spent some time looking at Cloud9 issues recently, so I can give you some hints on where to fix things. The big problem is that you rely on CSS3 FlexBox which Opera doesn't support yet. However, there is some code (guarded by some more browser sniffing
To reproduce I simply try logging in to Cloud9.com in Opera 11.10ish (I use random internal builds). Usually I get into a state where the site hangs and Opera uses 100% CPU - the hang is caused by some XHR-never-finishes bug, the CPU usage by your postMessage(). When I sometimes get out of this state, I get an exception: "Uncaught exception: TypeError: 'apf.n' is not a function" and we go down that path because this: means hasFlexibleBox is false.
Hallvord R. M. Steenhallvors # Monday, May 23, 2011 1:44:17 PM
on whether Cloud9's code is something we should worry about in the WebIDL standardisation process
Garrett Smithdhtmlkitchen # Tuesday, June 28, 2011 5:10:54 AM
I have a hard time believing that setZeroTimeout has a bona fide use case, per se.
I suspect that you're using this for a "do this when X is done". That approach -- if that is in fact what you are doing -- relies on unspecified behavior. Such approaches are doomed to fail. They'll make it seem like keeping up with browser updates is hard, when it's actually easy.
Thinger.blang = function() { _blang() Thinger.blangDone(); };Not officially supporting Opera and Internet Explorer 9 may be an indicator that the cloud9 application is badly designed, as those are two very good browsers. Especially IE9. All of the scripts aimed at addressing specific browser sets failed when IE9 came out while scripts that used proper capability checks and fallbacks fared much better, having little to no needed changes, even as different paths were used in an IE that passed tests like `if(document.addEventListener)`.
And your github patch exacerbates the very problem Hallvord described in this very post! Look here, from your fresh github patch:
That says that if window.postMessage is falsey, then apf.setZeroTimeout is setTimeout, and so when you call apf.setZeroTimeout in one of those environments then setTimeout is called with the base object being `apf` which will result in the errors that have been carefully described in this blog.
Now what I'd rather look at is not how to fix this function, but why you're using it in the first place. If you're using it to set up a queue call, as Hallvord said you were, then that's easy to fix.
Instead, use "I'm done" type of notifications. The object performing the action notifies when it is don. This obviates the need for the bad solution. Whatever situation or problem that your setZeroTimeout approach was used.
I'm available for such consultations, BTW. I don't work full time but I save a lot of time.
Martin KadlecBS-Harou # Wednesday, August 10, 2011 2:45:40 PM