wine, wine, wine. My inline asm blocks look the same regardless of which language I use.

Seriously, though, peek at /usr/include/objc/runtime.h and Behold that ObjC is ... uhm, well, C with a custom front end and some nice structs a library maintains for me. Okay, really very nice library. I try not to laugh at people who tell me they can't use ObjC because it's too slow and they're going to use C instead.

More constructively, I've noticed a few things in performance tuning over the years. Fundamentally, these are in style and idioms derived from what the syntax encourages. As such, some of these micro- optimizations do accumulate to become frictionally systemic as part of common patterns. I don't use C++ anymore, but credit where credit is due.

(1) polymorphism, or not. The default C++ method is monomorphic, and just a function. You need to tag it 'virtual' to get link time binding. ObjC methods default to runtime binding. It'd be awesome to get earlier binding in ObjC.

Several work arounds exist. The easiest is to create a static C member function (yes, ObjC has member *functions* which most people overlook). The public method can just call the static function, and if it's in the same compilation unit, the compiler will inline it. Optimized code that doesn't mind losing polymorphism can just call the function directly. ObjC member functions + custom CF callbacks = mega- nifty. Alas, toll free bridging of the Foundation classes with custom CF callbacks is not supported. Member functions don't have to be static, so they can be performance SPI as well. And for the times when it's important to send the very best, a non-static member function can call the inlined static version just like the method, having a single factored implementation with 3 different performance characteristics.

I've suggested tagging methods to be private to the link unit (app, framework, etc) since typically one wants to be able to inline accessor method invocations across compilation units. Which leads to ...

(2) inlining. There really isn't any disputing that C++ is friendlier to compile time optimizations like inlining and code movement. It does so by avoiding features that enable technologies like KVC & KVO. Template metaprogramming is in many ways focused toward shifting optimization complexity onto the compiler. And who wouldn't want to outsource, for free, hard work onto those very smart folks ? Many simple C++ methods are declared in header files. ObjC doesn't have a good definition of a monomorphic method, so people who need to opt into that have to jump through hoops.

For example, there's no way to declare an inline member function in a ObjC header file. Back to #define.

(3) object allocation. C++ is much friendlier to temporary objects including idioms for stack objects. Since most objects are ephemeral, avoiding heap churn entirely is handy. Less locking, less fragmentation, way faster. Also easy to screw up. It's possible to use stack objects in ObjC, with CFAllocator, but there's no syntax or idiomatic support, so it's extremely dangerous. Personally, I'd love to see syntax, perhaps like DO annotations, for stating that an object you pass out or receive is only valid for that stack's scope.

C++ also prefers = operator overloading to enhance retain counting instead of -autorelease. This leads to the compiler maintaining the scope of the temp object's lifetime instead of the programmer guessing (invariably badly, as code evolves) where to put NSAutoreleasePool. No extra memory to implement the NSAutoreleasePool, no extraneous extension of object lifetimes, no unnecessary increase in heap high watermark. Compiler does a way better job. And a number of very interesting idioms have developed around the construction and destruction of stack objects, such that C++ effectively allows delegate hooks at each lexical scope.

(4) autorelease Jihad! Jihad! It averages about 13x slower due to additional memory pressure and heap fragmentation. It's also, imo, impossible to correctly maintain NSAutoreleasePools as code evolves. Especially with other people's libraries and frameworks (e.g. my loop was fine, and then in version 10.++ you leaked an object into my autorelease pool and shafted me. Not bitter). Controlling & debugging the performance characteristics of code built around autorelease has just been a waste of my time. Now, I only use autorelease when (a) coerced or (b) it's the lesser evil compared to a @try block.

(5) exceptions. The idioms for both languages have been shaped by their error handling styles. This also impacts how to ref count expensive resources and delegates at lexical boundaries. Finally, on the 64 bit runtime, we have modern exceptions. Modern exceptions are very expensive to actually throw, in both languages, however.

(6) libraries. All these things interplay to shape the different features and performance characteristics of the frameworks and libraries. C++ doesn't do KVC or KVO. It's pretty easy to ask the Cocoa frameworks to do a huge amount of work in one or two lines of code. If you understand and expect that asking the framework to solve a hard problem for you in 1 line of code may be slow, then this is really really cool. If you have no idea what's going on or why using a 14 part keypath with a @sum on an NSArray of NSManagedObjects is doing a 13 table database join and lazily faulting in individual rows, you're probably both confused and unhappy. Rewriting the 13 table join in C++ isn't going to help, this is all I/O bound, but it may make the developer feel better. There's no substitute for understanding. That's also true for complex templates.

Similarly, the STL does light & fast rather well, frequently avoiding object types entirely. Using the STL algorithms as though they were just another C library of prepackaged stuff can make sense.

Yet, despite these areas for improvement, I haven't needed to use C++ for performance for many years. Doing less I/O and choosing a smarter algorithm are the best 80% of optimization.

The default tilt of ObjC is to more powerful, dynamic, and expensive features. C++ skews the other way. Typically, I personally want to selectively add performance not universally add features. This requirement to add features is an explicit design goal of C++, frequently stated by Stroustrup, as I can attest to first hand. In that sense, C++ is very successful. But the flip side is that the dynamism of Objective-C is extremely powerful, and supports optimization techniques generally infeasible in C++. People overlook the fact that Objective-C classes are mutable.

On top of all that, you don't have to choose. With C linkage, it's easy to build projects that uses both ObjC and C++. Or there's ObjC++ glue. Or asm. And both python and ruby integrate easily with ObjC. There's a right tool for the job, somewhere.

Shark is amazingly useful, and you can configure the sampling granularity down to 20us; good enough to catch a 3ms hiccup. I'd wager the original problem was a page fault or context switch, but since we don't have any meaningful data that's a WAG. To catch one of those in Shark, you'd need to use Time Sample (All Thread States)

Finally, no cocoa-dev discussion would be complete without calling you all out on your lazy *** bugreport.apple.com ways. *I* filed bugs about making all these performance techniques in Objective-C easier or syntactically supported. Have you ? It's rather difficult to justify adding features to the Entire tool chain just because one person, who has already worked around these issues, thinks it'd be cool.

It would help immensely for everyone who either switches to C++, or implements a particular hotspot in C++, to file bugs explaining why. Similarly, for the people annoyed by having to work around these issues in ObjC. Bonus kudos for attaching Shark samples.

- Ben

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to