Re: ObjC in time-critical parts of the code
Re: ObjC in time-critical parts of the code
- Subject: Re: ObjC in time-critical parts of the code
- From: Justin Carlson <email@hidden>
- Date: Sat, 17 Jan 2009 01:02:53 -0600
Michael Ash wrote:
Note that dispatch is not mandatory in ObjC either. It is possible
(you get little help from the compiler, but it's not hard) to use
either a vtable approach or a straight function call for method
invocation, as long as you don't mind the loss in functionality that
this implies.
Hi Michael,
If you prefer that route, that is your choice. Given the choice, I
would (personally) rather avoid caching selectors and debugging/
maintaining a program that used that behaviour when a well tested
alternatives are built into another language's model. Regarding the
model, I would not want to reinvent the messaging within my sources.
Typical objc class design significantly reduces an optimizer's
abilities to do its job.
I must object to this on two points.
First of all, the speed difference is only in messaging and in object
allocation (ObjC not having stack objects means more reliance on the
heap allocator). There is absolutely nothing else to it. If you are
finding differences in speeds for similar operations it's almost
certainly because of differences in the implementations of the
libraries. For example, you'll find that std::string blows the pants
off NSString. It's not because NSString is hobbled by Objective-C,
it's because NSString is vastly more complex and capable. As another
example, a std::vector<int> will blow the pants off an NSMutableArray
of NSNumber. Nothing to do with messaging (or allocation), and
everything to do with the fact that the C++ version is working with
primitives while the ObjC version is not.
This is not actually the case. Foundation -> CoreFoundation types were
one significant category of changes. In the aforementioned rewrites,
Foundation types were replaced with CoreFoundation types as opposed to
std types. Specifically, this _does_ mean that autorelease overhead
was reduced in the process, though I consider that a part of the
language that cannot be avoided (in using Apple's implementation/
libraries) and thus valid to include in the differences. I never tried
to hide that fact when I said "when converting class families/
libraries to C++ for standard application code". GC was not used,
figures came from optimized builds. In fact, the stl was rarely used.
There *is* more to it, and much of that difference takes place during
compilation.
Second, I disagree that C/C++ will be slower only in exceptional
circumstances. Each language has its strengths and weaknesses, and
ObjC's strength is having a wicked fast general dispatcher.
(Considering the decisions going on behind the scenes to figure out
what to invoke, the ~12 CPU cycles spent on each dispatch is a
ridiculously small number.) If your problem happens to map to dispatch
well, then ObjC will be faster for you.
Now, I'm certainly not going to argue that you want to involve ObjC
dispatch in intensive numerical code or anything of the sort. C or C++
clearly win there.
So we are in agreement on that. When I was speaking of 'exceptional
circumstances', I was speaking of performance critical code (i.e.
numerical) specifically.
But at the same time, I believe that a lot of the problems in a
typical GUI application map better to "dispatch" than to anything
provided in C or C++. I'm sure you're familiar with Greenspun's Tenth
Rule which states, "Any sufficiently complicated C or Fortran program
contains an ad hoc, informally-specified, bug-ridden, slow
implementation of half of Common Lisp." Well I'd like to propose a
parallel rule: "Any sufficiently complicated C or C++ GUI application
contains an ad-hoc, informally-specified, bug-ridden, slow
implementation of a more generalized OO dispatcher."
Amusing. Not always true, but frighteningly common.
Note that I don't mean to criticize C or C++ over this.
I wouldn't mind if you were. Optimization and understanding their
targeted runtime is a topic that I believe programmers overlook too
frequently, or simply don't care to understand because they can use
any of numerous cliches to excuse themselves from writing optimal
code. I have put in enough time in both environments to have a
_pretty_ good idea of which I would use to implement a class based on
the object's intended requirements/duty.
It's simply that they're not good at it, which is fine, they're not
supposed to be.
I'd say: Not good at it as a general byproduct of implementation or
poor design choices and careless maintenance/evolution, but not
specifically due to the underlying runtime/dispatcher. In other words,
the improper implementation of some form of an 'intermediate'
dispatcher within the libraries used. We already know that C++
dispatch is faster than Objective C (correct?).
But GUI apps tend to need a lot of dispatch, and at ~12 cycles each,
it's a bargain in ObjC.
Considering the dynamism of on objc object, 12 cycles is short.
Unfortunately, optimization possibilities are reduced, often
significantly. There *is* more to this than dispatch, and that really
is a portion of the equation that cannot be overlooked. Hopefully I am
not coming across as saying C++ is ideal in every program, each
language/runtime has its own strengths and weaknesses - it's really
the programmer's job to determine which is the right tool to use for
their program (and be able to justify their choice). There are too
many variables/runtime restrictions that Objective C classes cannot
use when an optimization pass occurs that have a significant impact on
performance.
When I've seen C/C++ code try to
replicate this kind of decision-making, it tends to involve a lot of C
strings, tons of linear searches, binary searches, or maybe a nice
hash table, and you're lucky to get within a couple orders of
magnitude of objc_msgSend.
Returning to my stance that they (C/C++/Objective-C) are very
different tools with different mechanisms, and inherent pros and cons.
Again, I would rather leave this task to Apple (in the case of
implementing the ObjC runtime/dispatch), who have invested more energy
into it than I ever could.
I've written a lot of performance-critical code over the years, both
in ObjC and in other languages, and I have never once found
objc_msgSend to be a critical path in anything. Certainly it *can* be
with a sufficiently perverse or specialized design, but it's rare.
It's not even that a good programmer will avoid it when he gets down
to a certain level, but rather the opposite: you really have to *work*
at using enough messages to make their impact significant.
And one final note, I want to reinforce the fact that this discussion
is 100% unrelated to the original post, which claimed not only that
ObjC was "slow" but that it was slow to the point that a single ObjC
message was glitching his video playback, a statement which simply
does not have any basis in reality no matter how slow the language
might actually be for your purposes.
Mike
Respectfully, there is clearly more than dispatch involved. I would
agree that this is unrelated to the original post. It *is* (IMO)
related to the observation Jens had along the way, that changing the
implementation to plain C solved the issue.
Best,
J
_______________________________________________
Cocoa-dev mailing list (email@hidden)
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:
This email sent to email@hidden