Welcome to the MacNN Forums.

If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

You are here: MacNN Forums > Software - Troubleshooting and Discussion > Developer Center > Framerate counter for JavaScript?

Framerate counter for JavaScript?
Thread Tools
Millennium
Clinically Insane
Join Date: Nov 1999
Status: Offline
Reply With Quote
Sep 12, 2005, 10:44 PM
 
In my quest to master a few Stupid JavaScript Tricks (tm), I'm working on implementing a scrolling parallax starfield using Safari/WHAT-WG's <canvas> element to render it. I've figured out how to get some basic control over frames per second using setInterval() and this is a Good Thing, but I'd like to try and find a way to calculate how many frames per second I'm actually getting.

I'm developing this script on a Ti/400, in part to force me to learn more about JavaScript optimization techniques. My goal is to get it to handle 100 stars at a sustained 20fps on this machine if I can. I think I've just about got it, but I want to be sure, hence the framerate counter. I can think up some fairly naive ways of doing this, but I'm hoping someone's come up with a version that has minimal overhead already.
You are in Soviet Russia. It is dark. Grue is likely to be eaten by YOU!
     
Millennium  (op)
Clinically Insane
Join Date: Nov 1999
Status: Offline
Reply With Quote
Sep 12, 2005, 11:07 PM
 
You know, scratch what I said about almost being at 20fps on this machine. I've tried using one of my more naive ideas for an FPS counter, and I seem to be hovering closer to 10fps. I'm still interested in any tested, proven FPS methods people might know about, though.

UPDATE: I've now got it running over 17fps sustained, so I've decided to go for the gusto again. Profilers and better FPS counters would be very much appreciated.
( Last edited by Millennium; Sep 13, 2005 at 10:56 AM. )
You are in Soviet Russia. It is dark. Grue is likely to be eaten by YOU!
     
Millennium  (op)
Clinically Insane
Join Date: Nov 1999
Status: Offline
Reply With Quote
Sep 13, 2005, 07:34 AM
 
As I delve deeper into the black art of JavaScript debugging and tuning, I've become frustrated by the fact that Venkman, Mozilla.org's JavaScript debugger and profiler, doesn't work on the Firefox 1.5 betas. It would be a wonderful tool for tooling my code, but it only works on Firefox 1.0.6 right now. Firefox 1.0.6 doesn't support the <canvas> tag, so even though I can run Venkman there I can't run my script.

Does anyone know of any other JavaScript profiling tools that will work in either Safari or the Firefox 1.5 betas? Alternatively, is there some super-secret Venkman build that will run on the 1.5 betas?
You are in Soviet Russia. It is dark. Grue is likely to be eaten by YOU!
     
Chris O'Brien
Grizzled Veteran
Join Date: Nov 2003
Location: Hebburn, UK
Status: Offline
Reply With Quote
Sep 13, 2005, 11:41 AM
 
Interesting problem. I imagine you'll just have to roll your own, though. Not sure there's any great profiling apps, although something in /Developer/Applications/Performance Tools/ might work, I suppose.

I imagine the easiest way would be to just append a new Date object to an array on each draw of the canvas. Then, when you stop the drawing after however many seconds you can peruse the data at your own leisure. It should be lightweight enough to not affect performance. Something to be aware of though is that the drawing to the canvas can sometimes be in it's own thread, so to speak, so you might want to use a setTimeout(func, 0); after the drawing is done to append the date. The 0 is for 'do this when you can (i.e. caught up with itself)' rather than 0 milliseconds as you may expect. This is for webcore, by the way, not so sure about gecko.

I might knock something up myself and have a look at how well the games I've written perform.
Just who are Britain? What do they? Who is them? And why?

Formerly Black Book
     
Millennium  (op)
Clinically Insane
Join Date: Nov 1999
Status: Offline
Reply With Quote
Sep 13, 2005, 01:20 PM
 
I've now got 17-18fps sustained in Firefox. Safari has cleared the 20fps benchmark, but just barely; almost any other system activity at all causes the framerate to drop. This is fun.
You are in Soviet Russia. It is dark. Grue is likely to be eaten by YOU!
     
Millennium  (op)
Clinically Insane
Join Date: Nov 1999
Status: Offline
Reply With Quote
Sep 13, 2005, 03:18 PM
 
Maybe I should start a blog for this or something.

I've now got four different "renderers" for the starfield: one which just draws basic rectangles, one which draws the stars at different sizes, one which draws the stars at different sizes and different colors ("further" stars are faded out), and one which draws little flapping birds in homage to Mega Man 2. I've been running tests with the latest release of Safari and the latest Firefox nightly. Some findings:
  • Safari gets better framerates than Firefox with all four four renderers. I assumed this is at least in part due to platform-specific optimizations which Safari can make but Firefox cannot. However, if such optimizations exist they are not simply a set of compiler flags; G4-optimized Firefox builds do not help it.
  • It comes as no surprise that framerates drop when the birds come out to play (bird droppings? ) However, they drop much more in Firefox than they do in Safari, which is really strange since a Firefox bug seems to prevent the birds from actually drawing anyway. I'm not sure why this is the case.
  • Oddly, Safari seems to have real trouble with the grayscale-star renderer. Even the birds ran more smoothly on Safari, which I find really strange. I'm guessing it has to do with setting context.fillStyle for a canvas, though I didn't expect the overhead of that to be so high.
  • Conversely, Safari seemed to show no appreciable difference between the one-size and multi-size renderers. Both held 20fps pretty consistently, only dipping to 19.8fps occasionally. By the end, I was even able to make the birds hold 20fps.
Bottom line: Firefox's <canvas> implementation, while probably fast enough for modern machines, still has a lot of room for improvement. However, if you're not trying to strain your processor, it should get the job done.
( Last edited by Millennium; Sep 13, 2005 at 05:02 PM. )
You are in Soviet Russia. It is dark. Grue is likely to be eaten by YOU!
     
Millennium  (op)
Clinically Insane
Join Date: Nov 1999
Status: Offline
Reply With Quote
Sep 14, 2005, 08:54 AM
 
Well, Safari certainly has no shortage of mysteries.

I tried upping the "desired" framerate to 30fps, to see if I could get a little more information about my renderers. In this case the basic renderer got up to 22fps sustained, and the multi-size renderer got sustained rates of 21fps. I didn't bother testing the multi-color render since it was always slower than 20fps anyway. What surprised me was that the birds renderer got noticeable slower, being able to sustain only about 15fps when the throttle was released. Putting the throttle back at 20fps got it working at 20fps again. This one has me stumped. Why would releasing the throttle on a function like this make it slower?

I've also done some experimenting with the canvas transformation functions (scale, rotate, and so on). It should be fairly obvious that these functions cause a performance hit, however this is an area where Firefox does better: the hit seems to be smaller. That said, the hits are definitely noticeable in both cases. I would recommend against using these functions in animation if you can. If all you need to do is scale images, you can do this in the drawImage() function by specifying a height and width; this scales the image automatically, and it is much faster than scaling the context.
( Last edited by Millennium; Sep 14, 2005 at 09:14 AM. )
You are in Soviet Russia. It is dark. Grue is likely to be eaten by YOU!
     
Millennium  (op)
Clinically Insane
Join Date: Nov 1999
Status: Offline
Reply With Quote
Sep 14, 2005, 09:07 PM
 
A profiler, a profiler; my kingdom for a profiler!

Ahem. I reimplemented the starfield using the new Array() methods from the Firefox betas -in particular, Array.forEach()- and a small library to emulate those methods in Safari. The results were, to say the least, a little surprising: no difference in any of the tests except for the birds, which took a whopping 7fps hit in Safari (which may not seem like much, but 7/20 is a 35% speed hit). I suspect I may be having some algorithm issues with my reimplementation, though, and that could affect things. 13fps in Safari is still better than not drawing any images at all in Firefox.

In any case, I find the lack of speed changes in the other three renderers strange for two reasons. One, of course, is that the loops got pushed into native code in Firefox, and so one would expect there to be a speed boost. The emulator library for Safari, however, has its own issues. The implementation is pretty naive performance-wise -less optimized than the loops in my original code, at any rate- and so I would have expected a significant drop in framerate, but there wasn't one (except with the birds, of course).

This leads me to believe that the bottleneck is in the <canvas> implementation, rather than my JavaScript code. This would explain why performance drops so much for bigger canvas sizes even with otherwise-identical code. It may also explain why Firefox has yet to catch up: its <canvas> is implemented in Cairo -a cross-platform Quartz-like library which basically wraps around Quartz in OSX- and so its performance should be close if not identical to Safari's- but every draw operation has to go not only through Cairo but also through gfx (Gecko's cross-platform imaging library) and then into QuickDraw (not Quartz) before being drawn in OSX. That would certainly cause framerate problems. Gecko is switching all of its graphics to use Cairo in the 1.9 (Firefox 2.0) timeframe, and this should bring framerates back into line with Safari, given that it would eliminate all the translations: straight Cairo/Quartz as opposed to Cairo/Quartz -> gfx -> QuickDraw.

I need a blog for this, don't I?
You are in Soviet Russia. It is dark. Grue is likely to be eaten by YOU!
     
Chris O'Brien
Grizzled Veteran
Join Date: Nov 2003
Location: Hebburn, UK
Status: Offline
Reply With Quote
Sep 15, 2005, 07:03 AM
 
Yeah, I think you need a blog for this

Also, everything you've been saying is rather obvious to anyone who's used the <canvas> on both platforms, so you could've just asked Although, where's the fun in that, I suppose. There's always going to be a maximum frame rate you'll get, and the <canvas> isn't the best place for high performance drawing, especially on gecko in it's current incarnation.

For example, a couple of things I wrote a few months back show how very simple things can run really slow, especially as the <canvas> gets larger (of course). Example 1 and example 2. I should really finish that second one someday.

And I imagine the Array.forEach() is just a syntactical nicety allowing a bit more flexibility rather than something that will give a performance boost. The JS parser will likely interpret rolling your own and using that in a very similar manner.

Anyway, when are you going to let us take a peek at this project? After reading all about it, I want to have a look!
Just who are Britain? What do they? Who is them? And why?

Formerly Black Book
     
Millennium  (op)
Clinically Insane
Join Date: Nov 1999
Status: Offline
Reply With Quote
Sep 15, 2005, 07:18 AM
 
Originally Posted by Black Book
Yeah, I think you need a blog for this

Also, everything you've been saying is rather obvious to anyone who's used the <canvas> on both platforms, so you could've just asked Although, where's the fun in that, I suppose. There's always going to be a maximum frame rate you'll get, and the <canvas> isn't the best place for high performance drawing, especially on gecko in it's current incarnation.
Points well taken, but I hadn't found all that much on <canvas> out there yet, and this really started as just an exercise in learning some more JavaScript. Exploring JS performance optimization kind of came by accident.
And I imagine the Array.forEach() is just a syntactical nicety allowing a bit more flexibility rather than something that will give a performance boost. The JS parser will likely interpret rolling your own and using that in a very similar manner.
The thing is, using Array.forEach() pushes the loop code into C (or whatever the language is written in, which I think is actually C++ for both SpiderMonkey and JavaScriptCore). That should remove most of the JavaScript loop overhead. Python has had functions very similar to this for a long time, and using them is considered an important part of optimizing performance in that language. It was my hope that something similar would hold true for JavaScript.
Anyway, when are you going to let us take a peek at this project? After reading all about it, I want to have a look!
It's going to be a couple of days yet, but I'll get you something soon.

By the way, do you happen to know anything about this strange bug with Firefox and context.drawImage()? It's driving me up the wall, but I don't see any mention of it in bugzilla. I may just end up putting my starfield online and then filing a bug, linking to the starfield as a testcase.
You are in Soviet Russia. It is dark. Grue is likely to be eaten by YOU!
     
Chris O'Brien
Grizzled Veteran
Join Date: Nov 2003
Location: Hebburn, UK
Status: Offline
Reply With Quote
Sep 15, 2005, 09:35 AM
 
Are you waiting until the image has loaded before calling drawImage()? Since all images are loaded asynchronously, you're Image object might not have any data (or not full data) when you're trying to draw it to the <canvas> context. Just add the drawing to an onload event handler.
Just who are Britain? What do they? Who is them? And why?

Formerly Black Book
     
Millennium  (op)
Clinically Insane
Join Date: Nov 1999
Status: Offline
Reply With Quote
Sep 15, 2005, 11:16 AM
 
Originally Posted by Black Book
Are you waiting until the image has loaded before calling drawImage()? Since all images are loaded asynchronously, you're Image object might not have any data (or not full data) when you're trying to draw it to the <canvas> context. Just add the drawing to an onload event handler.
I load the images in the script, as part of initializing the starfield.

In other news, I finally got my hands on a profiler. Venkman doesn't work with the latest Firefox betas, but it does work with (and in fact comes with) the latest 1.0 alpha release candidates of SeaMonkey. SeaMonkey -the new name for the old Mozilla suite- isn't very fast or pretty or stable, but it does let you profile your JavaScript. One thing that I do find strange, though, is that the birds renderer actually works in the SeaMonkey alpha, even though it doesn't work in Firefox.

Unfortunately, it can't profile JavaScript calls to native functions, so I can't directly measure the overhead of <canvas> calls. However, it's giving me ideas of where I can improve my code, and this is a Good Thing.
You are in Soviet Russia. It is dark. Grue is likely to be eaten by YOU!
     
Millennium  (op)
Clinically Insane
Join Date: Nov 1999
Status: Offline
Reply With Quote
Sep 15, 2005, 11:42 AM
 
Even stranger; once the birds started working in SeaMonkey, they started working in Firefox. I don't remember changing any code to make this happen, and I don't think SeaMonkey and Firefox ever try to use the same libraries on disk. This is really bizarre.

By the way, the framerate for the birds is really bad in Firefox; I can barely get it to crack 10fps. Again, though, I suspect this is a <canvas> implementation detail. The latest Camino nightlies don't appear to support <canvas> at all, which is also a shame.
( Last edited by Millennium; Sep 15, 2005 at 01:40 PM. )
You are in Soviet Russia. It is dark. Grue is likely to be eaten by YOU!
     
Chris O'Brien
Grizzled Veteran
Join Date: Nov 2003
Location: Hebburn, UK
Status: Offline
Reply With Quote
Sep 16, 2005, 06:12 AM
 
That is odd. Maybe they share the same cache?

How exactly do you draw the birds? I assume they're animated, but do you draw every frame of the animations through multiple images, or are you transforming them somehow? It might just be simpler and faster to make some animated gifs and move them around above or below the <canvas>.
Just who are Britain? What do they? Who is them? And why?

Formerly Black Book
     
Millennium  (op)
Clinically Insane
Join Date: Nov 1999
Status: Offline
Reply With Quote
Sep 16, 2005, 06:40 AM
 
Originally Posted by Black Book
How exactly do you draw the birds? I assume they're animated, but do you draw every frame of the animations through multiple images, or are you transforming them somehow? It might just be simpler and faster to make some animated gifs and move them around above or below the <canvas>.
Right now I'm drawing frame-by-frame (the MM2 flapping birds are only two frames of animation anyway). I was under the impression that you couldn't transform parts of the canvas once you'd drawn them; only the canvas itself (though you could scale images you were about to draw). Am I mistaken in that?
You are in Soviet Russia. It is dark. Grue is likely to be eaten by YOU!
     
Millennium  (op)
Clinically Insane
Join Date: Nov 1999
Status: Offline
Reply With Quote
Sep 27, 2005, 06:11 AM
 
I'll post what I've got soon. I've been working on some other effects, including some of the classic old-school graphics demos when I could find (or recreate) algorithms to do them. I've got the starfield, a dot tunnel, a rotating 3-D dot cube, and I'm working on a Qix-type effect. Not that any of these are too terribly fast, but hey; it's JavaScript.

What I wouldn't give for some nice, fast matrix-multiplication functions built into JavaScript, though. I mean, I've implemented matrix multiplication and all -I needed it for the cube- but man would that ever make things go more smoothly...
You are in Soviet Russia. It is dark. Grue is likely to be eaten by YOU!
     
Millennium  (op)
Clinically Insane
Join Date: Nov 1999
Status: Offline
Reply With Quote
Sep 27, 2005, 06:58 AM
 
Dammit; someone seems to have beaten me to the punch with the next thing I wanted to try: a raycasting engine. I figured I'd take some time to learn graphics as well as JavaScript, but it seems I've been beaten on this
You are in Soviet Russia. It is dark. Grue is likely to be eaten by YOU!
     
Chris O'Brien
Grizzled Veteran
Join Date: Nov 2003
Location: Hebburn, UK
Status: Offline
Reply With Quote
Sep 29, 2005, 08:41 AM
 
I got inspired by your cube idea last night and knocked this up. It's got some very rudimentary controls - but the sliders only work in Safari.

The filling is absolutely rubbish, but I'll work on that. I've only been doing it for a few hours, so it's not the best it can be. I need to work out actual facets and put in proper 3d perspective instead of it being isometric (support is kind of in there at the moment if you take a look). Then I plan on having proper shading from a movable light source, and possibly collision detection. Grouping of objects would be nice - hence why it's all done from predefined points. This could turn into a nice wee project

The interesting thing is how much faster firefox 1.5 handles the drawing. Click on swivel and watch the difference in performance between it and Safari. I'll take out the reliance on cos/sine though - that slows things down a lot.

Oh, write your own raycasting engine! That one's horribly slow, maybe you can do better.
Just who are Britain? What do they? Who is them? And why?

Formerly Black Book
     
   
 
Forum Links
Forum Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Top
Privacy Policy
All times are GMT -4. The time now is 02:10 AM.
All contents of these forums © 1995-2017 MacNN. All rights reserved.
Branding + Design: www.gesamtbild.com
vBulletin v.3.8.8 © 2000-2017, Jelsoft Enterprises Ltd.,