10

Are there standard optimization tricks for Objective-C to make for faster execution along the lines of "inlining" frequent methods as in C++ or the "g++ -fast" tag?

Edit: Does anyone have a short example using SEL and IMP when theMethod has two (or more) integers for input?

Ken
  • 30,811
  • 34
  • 116
  • 155
  • This topic is discussed in great detail here: http://www.mulle-kybernetik.com/artikel/Optimization/ – codewarrior Mar 30 '10 at 00:20
  • 1
    In a high-level framework like Cocoa, most small optimizations like this are a waste of time (other than changing compiler settings), since a lot of foundational classes are already heavily optimized. You should only optimize if profiling shows that something is taking a lot of extra time. – shosti Apr 16 '10 at 03:38

2 Answers2

13

Here's a small optimisation that may not really be worth the time to implement, and one that I never use personally, but I guess still good to know about. Rather than repeatedly sending the same message to the same object over and over, you can bypass repeated method dispatch by directly using the method implementation. For example, instead of:

for (int i = 0; i < 100000000; i++)
    [someObject messageWithInt:i];

You could try:

SEL theSelector = @selector(messageWithInt:);
IMP theMethod = [someObject methodForSelector:theSelector];

for (int i = 0; i < 100000000; i++)
    theMethod (someObject, theSelector, i);

This means that the method lookup is only done once and you can invoke the method directly through the returned IMP value. All Objective-C method implementations take at least two arguments, the first argument is the receiving object of type id, which becomes self within the method implementation, and the second argument is the selector [of type SEL] that was used to determine the method implementation, and becomes _cmd in the method implementation.

This approach can quickly turn sour if you don't use the correct “function definition” (I can't remember the proper term). IMP is a typedef for a function that returns void* and takes (id,SEL,...) as arguments. This can make it troublesome to use if the method actually returns something else like float. To help with this matter, you can cast the return value of -methodForSelector:, like this:

typedef float (*MyMethodIMP)(id,SEL,int);

SEL theSel = @selector(messageWithInt:);
MyMethodIMP theMethod = (MyMethodIMP)[someObject methodForSelector:theSel];
float result = 0.0;

for (int i = 0; i < 100000000; i++)
    result += theMethod (someObject, theSel, i);

With some care, you can save the theMethod and you may be able to use it for all instances of a particular class, not just one instance, but tread carefully.

dreamlax
  • 93,976
  • 29
  • 161
  • 209
  • 6
    As with most performance items, you should run Instruments on your code to see where the bottlenecks are. The items above are great... if you need them. If you don't, it just makes the code hard to read. – nall Mar 29 '10 at 05:24
  • 2
    @nall: Absolutely. I did some basic benchmarking, and in tight loops like the above, bypassing dispatch resulted in about half the execution time (`theMethod` did some basic maths). If a lot of time is spent in `objc_msgSend` (or whatever the method is called these days), then bypassing dispatch may be an option, otherwise, as you say, it'll be more of an obfuscation than an optimisation. – dreamlax Mar 29 '10 at 05:30
  • That's a really interesting optimization, but wouldn't it be easier to just make a C function instead of getting the IMP from a method? – shosti Apr 16 '10 at 03:45
  • @eman: Sure, if you're able to do so; you may not be able to do so if you're using an object from a closed-source framework. – dreamlax Apr 16 '10 at 07:25
9

Optimization is best handled by the compiler. Macs use GCC, so the standard optimization GCC flag (-Olevel) should work. In XCode, you can set the optimization level in the project settings. If you're not using GCC, check you compiler documentation for how to enable optimization.

Update: XCode 4 uses the LLVM backend by default. Both the GCC and clang frontends use "-On" optimization flags. For GCC, n is an integer from 0 through 3, or "s" or (Apple only) "z". For clang, n is an integer from 0 through 4, or "s".

Community
  • 1
  • 1
outis
  • 75,655
  • 22
  • 151
  • 221
  • Many thanks all for your suggestions and time! If you're willing, can you give a short example using SEL and IMP when theMethod takes two (or more) integers as its input. – Ken Apr 13 '10 at 06:34
  • @SpecialK: a short example of *what*? Did you mean to comment on dreamlax's answer? – outis Apr 14 '10 at 01:50