James Polanco of DevelopmentArc has a great post on Flash Player internals. Worth a read.
Firebug is your friend
In my mind, there are really three ways to a significant dent in performance:
- Find bad algorithms and replace them with fast ones
- Find code that doesn’t actually have to be called and skip it.
- Optimize the code that gets called most often
And you really can’t do any of the three without a profiler. You might think you know what the problem is, but you won’t know until you profile it. In my case, I started out thinking that I had event listeners hanging around that weren’t letting go of their events, but the profiler (in this case, Firebug) told me I was completely wrong.
To get started profiling in Firebug, go to the console tab, press the ‘profile’ button, do some stuff, and hit the ‘profile’ button again. That’s it.
You’ll then be presented with data that looks like this:
For my money, the two most important columns are ‘own time’ and ‘time’. ‘time’ is the total time spent in a function including any functions that are called by that function, and ‘own time’ is the same thing minus the time taken up by other functions.
Problem: $$(‘.class’) can be SLOW!
I created a test where I did the same UI gesture 8 times, and this is what I discovered. Looking at ‘own time’ told me that most of my time was going to DOM traversal via the $$ function.
Looking at ‘time’ told me that the methods responsible for calling $$ were all central functions that were called in many places throughout my code, so it was worth making them as efficient as possible before figuring out whether there was a way to avoid calling some of them altogether.
Phase 1 — replacing traversals of the entire DOM tree (via $$) with smaller traversals
Roughly speaking, this corresponds to strategy (3).
|Replace $$(‘.class’) by $(‘section’).getElements(‘.class’) in critical sections||2345ms||20%||20%|
|Chage getElements(‘.class’) to getElements(‘div.class’) in critical sections||2094ms||12%||34%|
|Found more places to do the above optimizations||1723ms||22%||63%|
|Replaced getElements() with getChildren() where possible||1641ms||5%||71%|
Along the way, I tried all sorts of other optimizations, but none of them yielded much benefit. Now that I was reaching the point of diminishing returns, it was time to see if there were chunks of code I could safely skip.
Phase 2 — skipping handler functions when possible
I knew that there was almost certainly code I was running that could be skipped (strategy 2). Why?
I find that when writing UI code, it is often easier to use brute force to make sure that everything is working consistently. For example, if an AJAX call updates a certain part of the screen, it is often easier to blow away all event handlers from everything and re-add them where needed, rather than just patching up event handlers for the portion of the screen that was updating.
My rationale is that you can always fix this at the end. And well, it was now time to pay the piper.
My test case involved doing the same UI gesture 8 times. And most of the time was going to the following functions:
add_panel_handlers_if_needed(): 8 times
add_content_handlers(): 16 times
add_panel_handlers(): 8 times
actually_do_drag_cleanup(): 8 times
remove_content_handlers(): 24 times
fix_detail_handlers(): 8 times
handle_click(): 8 times
fix_toggle_rte_handlers(): 8 times
add_drag_handlers_and_start(): 8 times
add_insert_handlers(): 8 times
You can see that some functions are being called 8 times and some were being called 24 times. As it turns out, this was just due to programmer laziness. By adding a few checks, some of those redundant calls could be safely avoided.
The other thing that was causing extra work is that only certain interactions caused screen updates that needed event handlers to be reattached. By writing some code to check for that, I was able to avoid many of these calls altogether.
|End of phase 1||1641ms||71%||71%|
|Remove redundant calls to remove_content_handlers and add_content_handlers||1389ms||18%||102%|
|Skip certain fixup calls when content is determined not to have changed||1073ms||29%||162%|
(P.S. there is some small part of my brain that tells me that instead of manually worrying about these event handlers, I should just bite the bullet and switch to JQuery. But I’m not there yet.)
So, what’s the moral? First off, doing $$(‘.class’) is slow. Second, large performance boosts usually come from a combination of skipping code that doesn’t have to run and optimizing the code that does. This was no exception.
One more thing. I just have to say that Firebug is amazing. I expected it to have trouble giving useful timings in the face of inconsistent UI gestures and garbage collection, but it did the “right thing”, which many desktop profilers don’t manage to do. If I had one wish, I wish I could get it to bundle up calls from specified library files and allocate the time spent in them to the calling function.
Ok. Back to more optimizing.
Ok. So now I’ve seen the Watchmen movie. It’s about as good as I could imagine the movie being, and I followed Scott Knaster’s advice: I enjoyed it for what it is.
Yes, the movie had faults, but it’s hard to imagine how those faults could have been corrected without major departures from the source material, which would have been devastating in its own way. Rock, meet hard place.
Now, for my take. I’ll try not to cover ground that has been beaten to death elsewhere. (mild spoilers ahead)
I’m going to see Watchmen this afternoon, and I’m nervous. The issue isn’t whether the movie will suck, or whether it will be faithful to the comic, or whether something will be lost in translation to movie format.
The issue for me is that the Watchmen was a moment in time, and that moment can’t ever be recaptured.
For me, reading the Watchmen was an intensely social experience, much like watching the first season of Twin Peaks or the first season of Lost. As each issue came out, friends would gather and pore over every frame, trying to find clues to what was “really going on.” As the pace of the issues slowed down toward the end, the wait was agonizing.
My memory of Watchmen has much more to do with how I felt as each issue came out and much less to do with the actual story.
For those youngsters (or late adopters) who read the Watchmen as a single graphic novel, the experience must have been very different. I’m sure that the latecomers can still appreciate it, but there is just no way that the experience of reading the whole thing from end to end is in any way similar to the experience of waiting a month between each issue. And the experience of watching the movie will be even less like my memory of the experience of reading the comic.
So that’s it in a nutshell. In fact, I’m so afraid of seeing this movie that I even considered not seeing it. We’ll see if I made the right choice.
Just checked out the Safari 4 beta. Overall, it looks promising.
Tabbed browsing. The weird tab/title bar doesn’t appeal to me, but I can see its value. To me, the window needs to feel like it’s a container, and the tabs just screw that up for me. But the space savings is nice.
Better keyboard navigation. Greatly appreciated by those of us who fill out forms on the web. Which is to say everyone. turns out they had this in Safari 3.
Better hints for location bar. Much better! The hints now work kind of like spotlight. Type stuff into the URL bar, and Safari will do its best to find a matching URL from any source it can think of (history, bookmarks, etc). The best guess is shown first (like Spotlight) and the rest are categorized. Problems: The location bar doesn’t seem to handle page titles, which is a shame. Also, if you mistype a URL and get a 404 or other error, it still shows up in history and can end up as the “top hit”. Uh… whoops!
Embedded web fonts. It’s great that Safari is doing this. However, to be realistic (a) more browsers need to support this, and (b) someone needs to sort through all the legal issues having to do with font embedding.
CSS animations. Back in 97, I was one of the folks working on the first version of Dreamweaver. At that point in time, the Netscape folks were coming up with new tags all the time.
When we told the Netscape folks that we were going to add a timeline to Dreamweaver to take advantage of the <layer> tag, they were surprised and happy. You see, the inspiration for the <layer> tag was this question: “how can we have the browser do the things that the Shockwave plugin does?” Fast forward to 2009 and replace “layer” with “CSS animations” or “canvas” and replace “Shockwave” with “Flash”.
My opinion on all this? Meh. If you want to do everything that Flash does, use Flash. Or invent something radically new that blows HTML out of the water. Don’t bother bolting that stuff onto HTML/CSS.
In fact, if you’re going to bolt stuff onto CSS, focus on getting the basics of static presentation right. CSS layout is still incredibly difficult (way harder than tables were). You have to do hours of Google research just to get a usable two column layout.
Top Sites. The top sites UI feels overly glitzy to me, and for no good reason. The slightly curved appearance implies (to my eye) that I should be able to rotate my view to the left and the right to see more sites. Which you can’t do, as far as I can tell.
Bookmark Sidebar / Cover Flow. I like Cover Flow, but it’s getting to the point where I can’t tell the Apple apps apart. iTunes has a sidebar on the left, a list of stuff on the right, which can include a Cover Flow view and a list below. Same with the Finder. Same with the browser. Same with…
Maybe I’m just thinking about this too abstractly, but it bothers me that so many of the Apple apps are starting to feel the same as each other. Not so long ago, iTunes was different than the Finder, which was different than iPhoto. Now, you have cover flow in the Finder and with Quick Look, you can play the song right from there.
So I don’t know. I’m kind of torn. Consistency is nice, but too much consistency leads to every single thing looking exactly the same. It feels a little bit like MS Windows UI right around when XP came out. Tree views were pretty general, and a lot of applications fit into the pattern of “tree view on left, detail view on right”, so that’s what everyone did.
Maybe it will grow on me. Or maybe they’ll iron out the kinks. (single clicking on a bookmark in the sidebar doesn’t navigate you to the page. It shows you a “category” with a single bookmark in it. Double clicking on the bookmark in the sidebar lets you rename the bookmark. The only way to navigate to that bookmark, as far as I can tell, is to click on the bookmark, and then click on the image of the website in cover flow, or else double click on the bookmark in the bottom pane below cover flow. I mean… cover flow is pretty, but isn’t single clicking a bookmark more important?)
Color profile support. They claim to be the
first only one to support this, but doesn’t Firefox already do this? Is the issue that it is turned off by default? Or does Safari handle colors in a significantly better way than Firefox?