Will my iPhone app take a performance hit if I use Objective-C for low level code?

45,649

Solution 1

Mike Ash has some hard numbers for performance of various Objective-C method calls versus C and C++ in his post "Performance Comparisons of Common Operations". Also, this post by Savoy Software is an interesting read when it comes to tuning the performance of an iPhone application by using Objective-C++.

I tend to prefer the clean, descriptive syntax of Objective-C over Objective-C++, and have not found the language itself to be the source of my performance bottlenecks. I even tend to do things that I know sacrifice a little bit of performance if they make my code much more maintainable.

Solution 2

Yes, well written C++ is considerably faster. If you're writing performance critical programs and your C++ is not as fast as C (or within a few percent), something's wrong. If your ObjC implementation is as fast as C, then something's usually wrong -- i.e. the program is likely a bad example of ObjC OOD because it probably uses some 'dirty' tricks to step below the abstraction layer it is operating within, such as direct ivar accesses.

The Mike Ash 'comparison' is very misleading -- I would never recommend the approach to compare execution times of programs you have written, or recommend it to compare C vs C++ vs ObjC. The results presented are provided from a test with compiler optimizations disabled. A program compiled with optimizations disabled is rarely relevant when you are measuring execution times. To view it as a benchmark which compares C++ against Objective-C is flawed. The test also compares individual features, rather than entire, real world optimized implementations -- individual features are combined in very different ways with both languages. This is far from a realistic performance benchmark for optimized implementations. Examples: With optimizations enabled, IMP cache is as slow as virtual function calls. Static dispatch (as opposed to dynamic dispatch, e.g. using virtual) and calls to known C++ types (where dynamic dispatch may be bypassed) may be optimized aggressively. This process is called devirtualization, and when it is used, a member function which is declared virtual may even be inlined. In the case of the Mike Ash test where many calls are made to member functions which have been declared virtual and have empty bodies: these calls are optimized away entirely when the type is known because the compiler sees the implementation and is able to determine dynamic dispatch is unnecessary. The compiler can also eliminate calls to malloc in optimized builds (favoring stack storage). So, enabling compiler optimizations in any of C, C++, or Objective-C can produce dramatic differences in execution times.

That's not to say the presented results are entirely useless. You could get some useful information about external APIs if you want to determine if there are measurable differences between the times they spend in pthread_create or +[NSObject alloc] on one platform or architecture versus another. Of course, these two examples will be using optimized implementations in your test (unless you happen to be developing them). But for comparing one language to another in programs you compile… the presented results are useless with optimizations disabled.

Object Creation

Consider also object creation in ObjC - every object is allocated dynamically (e.g. on the heap). With C++, objects may be created on the stack (e.g. approximately as fast as creating a C struct and calling a simple function in many cases), on the heap, or as elements of abstract data types. Each time you allocate and free (e.g. via malloc/free), you may introduce a lock. When you create a C struct or C++ object on the stack, no lock is required (although interior members may use heap allocations) and it often costs just a few instructions or a few instructions plus a function call.

As well, ObjC objects are reference counted instances. The actual need for an object to be a std::shared_ptr in performance critical C++ is very rare. It's not necessary or desirable in C++ to make every instance a shared, reference counted instance. You have much more control over ownership and lifetime with C++.

Arrays and Collections

Arrays and many collections in C and C++ also use strongly typed containers and contiguous memory. Since the address of the next element's members are often known, the optimizer can do much more, and you have great cache and memory locality. With ObjC, that's far from reality for standard objects (e.g. NSObject).

Dispatch

Regarding methods, many C++ implementations use few virtual/dynamic calls, particularly in highly optimized programs. These are static method calls and fodder for the optimizers.

With ObjC methods, each method call (objc message send) is dynamic, and is consequently a firewall for the optimizer. Ultimately, that results in many restrictions or inconveniences regarding what you can and cannot do to keep performance at a minimum when writing performance critical ObjC. This may result in larger methods, IMP caching, frequent use of C.

Some realtime applications cannot use any ObjC messaging in their render paths. None -- audio rendering is a good example of this. ObjC dispatch is simply not designed for realtime purposes; Allocations and locks may happen behind the scenes when messaging objects, making the complexity/time of objc messaging unpredictable enough that the audio rendering may miss its deadline.

Other Features

C++ also provides generics/template implementations for many of its libraries. These optimize very well. They are typesafe, and a lot of inlining and optimizations may be made with templates (consider it polymorphism, optimization, and specialization which takes place at compilation). C++ adds several features which just are not available or comparable in strict ObjC. Trying to directly compare langs, objects, and libraries which are very different is not so useful -- it's a very small subset of actual realizations. It's better to expand the question to a library/framework or real program, considering many aspects of design and implementation.

Other Points

C and C++ symbols can be more easily removed and optimized away in various stages of the build (stripping, dead code elimination, inlining and early inlining, as well as Link Time Optimization). The benefits of this include reduced binary sizes, reduced launch/load times, reduced memory consumption, etc.. For a single app, that may not be such a big deal; but if you reuse a lot of code, and you should, then your shared libraries could add a lot of unnecessary weight to the program, if implemented ObjC -- unless you are prepared to jump through some flaming hoops. So scalability and reuse are also factors in medium/large projects, and groups where reuse is high.

Included Libraries

ObjC library implementors also optimize for the environment, so its library implementors can make use of some language and environment features to offer optimized implementations. Although there are some pretty significant restrictions when writing an optimized program in pure ObjC, some highly optimized implementations exist in Cocoa. This is one of Cocoa's strong points, although the C++ standard library (what some people call the STL) is no slouch either. Cocoa operates at a much higher level of abstraction than C++ -- if you don't know well what you're doing (or should be doing), operating closer to the metal can really cost you. Falling back on to a good library implementation if you are not an expert in some domain is a good thing, unless you are really prepared to learn. As well, Cocoa's environments are limited; you can find implementations/optimizations which make better use of the OS.

If you're writing optimized programs and have experience doing so in both C++ and ObjC, clean C++ implementations will often be twice as fast or faster than clean ObjC (yes, you can compare against Cocoa). If you know how to optimize, you can often do better than higher level, general purpose abstractions. Although, some optimized C++ implementations will be as fast as or slower than Cocoa's (e.g. my initial attempt at file I/O was slower than Cocoa's -- primarily because the C++ implementation initializes its memory).

A lot of it comes down to the language features you are familiar with. I use both langs, they both have different strengths and models/patterns. They complement each other quite well, and there are great libraries for both. If you're implementing a complex, performance critical program, correct use of C++'s features and libraries will give you much more control and provide significant advantages for optimization, such that in the right hands, "several times faster" is a good default expectation (don't expect to win every time, or without some work, however). Remember, it takes years to understand C++ well enough to really reach that point.

I keep the majority of my performance critical paths as C++, but also recognize that ObjC is also a very good solution for some problems, and that there are some very good libraries available.

Solution 3

It's very hard to collect "hard data" for this that's not misguiding.

The biggest problem with doing a feature-to-feature comparison like you suggest is that the two languages encourage very different coding styles. Objective-C is a dynamic language with duck typing, where typical C++ usage is static. The same object-oriented architecture problem would likely have very different ideal solutions using C++ or Objective-C.

My feeling (as I have programmed much in both languages, mostly on huge projects): To maximize Objective-C performance, it has to be written very close to C. Whereas with C++, it's possible to make much more use of the language without any performance penalty compared to C.

Which one is better? I don't know. For pure performance, C++ will always have the edge. But the OOP style of Objective-C definitely has its merits. I definitely think it is easier to keep a sane architecture with it.

Solution 4

This really isn't something that can be answered in general as it really depends on how you use the language features. Both languages will have things that they are fast at, things that they are slow at, and things that are sometimes fast and sometimes slow. It really depends on what you use and how you use it. The only way to be certain is to profile your code.

In Objective C you can also write c++ code, so it might be easier to code in Objective C for the most part, and if you find something that doesn't perform well in it, then you can have a go at writting a c++ version of it and seeing if that helps (C++ tends to optimize better at compile time). Objective C will be easier to use if APIs you are interfacing with are also written in it, plus you might find it's style of OOP is easier or more flexible.

In the end, you should go with what you know you can write safe, robust code in and if you find an area that needs special attention from the other language, then you can swap to that. X-Code does allow you to compile both in the same project.

Solution 5

I have a couple of tests I did on an iPhone 3G almost 2 years ago, there was no documentation or hard numbers around in those days. Not sure how valid they still are but the source code is posted and attached.

This isn't a very extensive test, I was mainly interested in NSArray vs C Array for iterating a large number of objects.

http://memo.tv/nsarray_vs_c_array_performance_comparison

http://memo.tv/nsarray_vs_c_array_performance_comparison_part_ii_makeobjectsperformselector

You can see the C Array is much faster at high iterations. Since then I've realized that the bottleneck is probably not the iteration of the NSArray but the sending of the message. I wanted to try methodForSelector and calling the methods directly to see how big the difference would be but never got round to it. According to Mike Ash's benchmarks it's just over 5x faster.

Share:
45,649
slf
Author by

slf

"When the going gets tough, the tough get empirical" -- Jon Carroll

Updated on July 05, 2022

Comments

  • slf
    slf almost 2 years

    When programming a CPU intensive or GPU intensive application on the iPhone or other portable hardware, you have to make wise algorithmic decisions to make your code fast.

    But even great algorithm choices can be slow if the language you're using performs more poorly than another.

    Is there any hard data comparing Objective-C to C++, specifically on the iPhone but maybe just on the Mac desktop, for performance of various similar language aspects? I am very familiar with this article comparing C and Objective-C, but this is a larger question of comparing two object oriented languages to each other.

    For example, is a C++ vtable lookup really faster than an Obj-C message? How much faster? Threading, polymorphism, sorting, etc. Before I go on a quest to build a project with duplicate object models and various test code, I want to know if anybody has already done this and what the results where. This type of testing and comparison is a project in and of itself and can take a considerable amount of time. Maybe this isn't one project, but two and only the outputs can be compared.

    I'm looking for hard data, not evangelism. Like many of you I love and hate both languages for various reasons. Furthermore, if there is someone out there actively pursuing this same thing I'd be interesting in pitching in some code to see the end results, and I'm sure others would help out too. My guess is that they both have strengths and weaknesses, my goal is to find out precisely what they are so that they can be avoided/exploited in real-world scenarios.

  • slf
    slf almost 15 years
    I'm not really looking for 'better', but I understand your point. Still, having some numbers to back it up when I walk around the office screaming "c++ is faster" makes me sound like less of an evangelist and more like a pragmatist.
  • slf
    slf almost 15 years
    Excellent point. For the record we do not currently have any performance bottlenecks, or are we blaming things on ObjC, quite the contrary. I guess at the end of the day this question is simply to satisfy my lust for scientific fact.
  • Johan Kotlinski
    Johan Kotlinski almost 15 years
    I understand. I think the best idea to make an impact at the office would be to pick some typical code from your app, that is likely ot take a lot of time. Write one C++ and one Objective-C version. Measure, compare, discuss.
  • TechZen
    TechZen almost 14 years
    Objective-C does not use duck typing. Objects either have a specific type or they are of type id. With duck typing, the runtime assigns a type depending on context. The Objective-C runtime does not assign types.
  • PD1978US
    PD1978US over 13 years
    In C# (.net) not all functions are virtual. That is one of the differences between java and .net. You have to explicitly mark each method you want to have as virtual with the virtual or the abstract keywords.
  • Arafangion
    Arafangion almost 13 years
    Well, accessing a C array is literally nothing more than adding the offset to the pointer, and then dereferencing the resulting pointer. It is hard to get much faster than that.
  • Jimmy Hoffa
    Jimmy Hoffa almost 12 years
    The first link you mentioned has performance numbers for ObjC, but does not have any comparison numbers from other languages (You suggested it compared them to C, but it does not.), so it lacks a control to give the numbers meaning.
  • bobobobo
    bobobobo over 11 years
    STOP. "Performance Comparisons" is incredibly bad. A 'performance comparison' should have something to compare Objective-C to: namely plain C and C++. This isn't a comparison. It's a listing of completely meaningless runtimes for common operations (completely meaningless because it's on some dude's specific hardware set up).
  • bobobobo
    bobobobo over 11 years
    The second article says "When I was workin' with arrays, I got a 4x performance enhancement by switching to C-arrays". Contradiction. The article says for max performance you must use C, but your answer here says "Eah just use Objective C"
  • Brad Larson
    Brad Larson over 11 years
    @bobobobo - COLLABORATE AND LISTEN. Seriously, I don't understand your problem with Mike's benchmarks. He ran common low-level operations and compared them with what Objective-C layers on C, namely message sending, object allocation / deallocation and the like. They were all run on a single piece of hardware, and are relative measures. He makes the benchmark available for you to run on your hardware, and has performed similar benchmarks on iOS devices, with comparable results. You want to add function calling, C++ object allocation, etc. to your own benchmark, feel free to do so.
  • Brad Larson
    Brad Larson over 11 years
    @bobobobo - As for your second argument, what is inconsistent about what I wrote above? I fully admit that object allocation overhead for dealing with objects in an NSArray is slower than a C array, but I still choose to use the higher-level structures most of the time. I do so because this leads to simpler and clearer code, and the performance differences are not noticeable in most circumstances. I wrote an iOS image processing framework that is 95% Objective-C and yet is faster than anything else in its class. I only drop down to C in select spots where I see a measurable benefit.
  • bobobobo
    bobobobo over 11 years
    @memo Links are dead, but here's part i, and part ii
  • bobobobo
    bobobobo over 11 years
    Actually this is a great answer if you can see the links. To summarize he finds C arrays at least 100x faster than NSArray
  • echristopherson
    echristopherson over 11 years
    @TechZen: That contradicts the understanding of the term "duck typing" at least in the Ruby community. Ruby is universally seen as duck typed, but each object actually has a specific type (class; it can also have singleton methods further specializing it). Duck typing is understood to be the way you can send a message to an object assuming a certain kind of behavior in response but not assuming a certain type.
  • Jasper
    Jasper over 11 years
    The comparison data linked to in this post is missing one incredibly important thing: how much subclassing is going on. The thing is that this has no performance impact on C++, while it does have performance impact on Objective-C
  • Chris Devereux
    Chris Devereux over 10 years
    Sounds like evangelism to me
  • Greg M. Krsak
    Greg M. Krsak about 10 years
    In Mike Ash's defense, he does state "As always, code for correctness and clarity first, then profile if necessary, and only when you have identified a critical bottleneck should you optimize."