Re: optimizing compilers
Re: optimizing compilers
- Subject: Re: optimizing compilers
- From: Rainer Brockerhoff <email@hidden>
- Date: Sun, 3 Feb 2002 13:38:20 -0200
>
Date: Sat, 2 Feb 2002 13:34:09 -0800
>
From: email@hidden
>
>
> And if Quartz is no factor, what are the relevant factors ?
>
...
>
A similar area I'd implicate would be NSArray and NSDictionary. Not
>
because they are slow in themselves (I think they're very fast,
>
actually), but simply because they're objects at all, and because it's
>
very easy to get lazy and use them more often than necessary. I would
>
be interested to see how many of the allocated NSArrays and
>
NSDictionaries instantiated at any given time contain either zero or one
>
item. Optimizing these cases can pay off in spades. If your collection
>
contains no objects, it should not have been allocated at all. If it
>
contains only one object, and that's common in your app, you may want to
>
special-case that to avoid the object allocation.
>
Another similar area is autorelease. It's very easy to get into the
>
habit of using autorelease; in fact, in some cases, it's hard to avoid.
>
But the speed penalty is *huge*. You really *never* want to use
>
autorelease unless good API design makes it necessary (and sometimes not
>
even then). Many Obj-C programmers don't realize this, though, and in
>
any case it's easy to fall into this pattern, and often hard to
>
eliminate it (especially when using Cocoa APIs geared around always
>
returning autoreleased objects, a design decision I would implicate
>
fairly heavily in the overall system performance). Learn to avoid it,
>
though, especially in cases where you're handling many objects (it
>
obviously doesn't matter when you're talking about autoreleasing a
>
document window or an app delegate or something :->).
I agree that it's very easy to use Cocoa's wonderful convenience methods in situations where they get nested, or put into an inner loop, or simply used on a too-large data set (or sometimes all of these) and performance goes way down.
For instance, some time ago I was benchmarking my own application (XRay) against competitors and the Finder when calculating folder sizes. This means looping recursively over nested folders and getting each file's attributes and fork sizes.
Initially I used NSFileEnumerator to loop over the folders and NSFileManager to get file sizes and attributes. It was like 3 or 4 times slower than the Finder, for large folders! Then I changed to using Carbon calls, and got times comparable to the Finder. Finally I changed to BSD calls like opendir() and readdir(), and now get nearly double the Finder's speed...
I understood why when I looked at the SimpleBrowser sample code a couple of weeks ago. Obviously, to simplify things, many convenience methods are called. The same information is asked for again and again, and much of is thrown away immediately... for instance, an NSArray containing all names in a given folder is created repeatedly, only to get the number of contained files. Even if some of those calls use internal caches, you have some overhead to create and search them... those calls may create hundreds or thousands of autoreleased objects, and so the event loop gets slowed down.
The outcome is that things often get surprisingly slow, even when no drawing at all is involved. The first time the user asks for my browser's contextual menu it takes anything from 5 to 10 seconds (with the rainbow cursor spinning) for the menu to appear - it seems to get cached afterwards, but that seems excessive to me, and I have yet to find out how to pre-load it without bogging down application initialization.
--
Rainer Brockerhoff <email@hidden>
Belo Horizonte, Brazil
"I love deadlines. I love the whooshing noise they make as they go by" (Douglas Adams)
http://www.brockerhoff.net/ (updated Jan. 2002)