Cocoa/Objective-C: how much optimization should I do myself? - objective-c

I recently found myself writing a piece of code that executed a Core Data fetch, then allocated two mutable arrays with the initial capacity being equal to the number of results returned from the fetch:
// Have some existing context, request, and error objects
NSArray *results = [context executeFetchRequest:request error:&error];
NSMutableArray *firstArray = [[[NSMutableArray alloc]
initWithCapacity:[results count]] autorelease];
NSMutableArray *secondArray = [[[NSMutableArray alloc]
initWithCapacity:[results count]] autorelease];
I looked this over again once I'd written it, and something struck me as odd: I was calling [results count] twice. The resultset is potentially pretty large (hundreds, maybe a thousand, objects).
My first instict was to break out [results count] into a separate NSUInteger, then use that integer for the capacity of each of the arrays. My question: is this kind of by-hand optimization necessary? Will the compiler recognize it's running [results count] twice and just hold the value without me having to explicitly specify that behavior? Or will it run the method twice - a potentially costly operation?
In a similar vein, what other optimizations should programmers (especially iPhone programmers, where there's a limited amount of memory/processing power available) do by hand, as opposed to trusting the compiler?

To answer the actual question: no, an Objective-C compiler cannot optimize away method sends, ever. (Well, actually, there’s one possible case: if it knows for certain that the receiver is nil.)
There is no way for a class to provide guarantees about method behaviour (in particular, you can’t use gcc’s __attribute__((const)) and such with a method), and there is no way for the compiler to tell what method implementation will be called because of Objective-C’s dynamic nature. For example, results could actually be a proxy object which forwards the count method to a random object each time it’s called. There’s no particular reason for Core Data to do that, but the compiler doesn’t know that.
All that aside, the cost of calling -[NSArray count] is trivial, and there’s absolutely no way that particular method will be a bottleneck in anything but extremely contrived code. The habit of avoiding double calls can reasonably be argued to be worthwhile, but actually worrying about the cost or going back to “correct” it for performance reasons would be a waste of time, quite likely more time than your program will spend calling -[NSArray count] throughout its useful lifetime.

First rule of optimization: never optimize without benchmarks verifying what needs optimizing. Otherwise you're suffering from 'premature optimization', and a lot of (potentially) wasted effort.
Now, if you know that something takes 2s to run,and you're running in 4 times when you could be running it once - that would be justifiable. but it sounds like you're not sure in this case, so the answer is "benchmark it"

The short answer: none. At least not right now.
I don't think the compiler will recognize that you're running [results count] twice, BUT that shouldn't matter. The usual quote on this subject is that "premature optimization is the root of all evil". Write your code however you want to; think about readability first. Then, after you've finished, and you've actually noticed that your code is slow, then go back and find optimizations if necessary.
So the rule is: write sensible, readable code, and optimize afterwards if problems are discovered.

The compiler will not pick up the fact that you already ran it.
Fixing this is not an optimization, it's simply programming correctly. There are a few things that you just have to be aware of that go beyond optimization.. most of them involve unnecessary looping of one sort or another.
Would it be really hard to just pull it out into a separate variable?
NSArray *results = [context executeFetchRequest:request error:&error];
NSUInteger count=[results count];
NSMutableArray *firstArray = [[[NSMutableArray alloc] initWithCapacity:count] autorelease];
NSMutableArray *secondArray = [[[NSMutableArray alloc] initWithCapacity:count] autorelease];
Which is absolutely no less clear (possibly more clear).
Anyway, executing unbounded unnecessary loops need to be avoided, it's not optimization, it's just wrong.
And please don't think I don't understand the cons of premature optimization, I've ranted about it repeatedly in replies to other questions...
As for your other question, never "optimize" without a test or spec showing that your code is running too slow, but DON'T code poorly. Always be aware of inner loops and things that might cause inner loops--these are the most critical.
An insertion sort into an array list causes an inner loop, an insertion sort into a linked list does not...
iterating over a linked list causes an inner loop (assuming you are using the loop index to retrieve the "Next" value instead of holding onto the node and referencing .next which would be fine), iterating over an array list does not.
Comparing two lists often requires an inner loop and it's often worth looking over your data to try to figure out a way that an inner loop is not required (for instance, if they are both sorted you can code such that you won't get an inner loop.

Related

Does an auxiliary variable with a pointer have any performance/memory impact?

Does it?
I would normally pick this,
NSArray * monthsForChosenYear = [self monthsForYear:newChosenYear];
[self setMonths: monthsForChosenYear];
Over this,
[self setMonths: [self monthsForYear:newChosenYear]];
Mostly because it's easy to understand at a first glance. Where the second approach, not so much.
But what are really the implications of this? monthsForChosenYear, is just a pointer, but it must be stored somehow.
I'm not asking if the impact is so small that I wouldn't need to worry about it. But I am very curious about this.
Even a redirect to some document explaining in better detail would be nice.
Thank you in advance!
Nuno
A long answer to hopefully assuage your curiosity, and having curiosity is good! The performance & memory impact is either zero or miniscule. You wonder how the pointer is stored. When you type:
NSArray * monthsForChosenYear;
You are asking for a box (variable), to be referred to by the name monthsForChosenYear, to be allocated in local storage. This box will be automatically reclaimed when the enclosing method exits, and possibly earlier than that if the compiler figures out it is no longer needed. This box can hold a value of type NSArray *.
When you type:
NSArray * monthsForChosenYear = [self monthsForYear:newChosenYear];
You are asking for two things, it is just a shorthand for:
NSArray * monthsForChosenYear;
monthsForChosenYear = [self monthsForYear:newChosenYear];
and the second line calls a method and stores the returned value in your box named monthsForChosenYear. Finally when you type:
[self setMonths: monthsForChosenYear];
the value stored in the your box monthsForChosenYear is passed to a method. If you no longer use the box monthsForChosenYear the compiler may reclaim it, or it may wait till the end of the enclosing method or some other suitable point.
Compilers analyze the usage of boxes and optimise, sometimes they will not even allocate a box if it is determined one is not needed. The cost of allocating a box is infinitesimal.
*[Note: there are actually usually two kinds of local boxes. The second, often called a register, has an allocation cost which is usually even smaller than infinitesimal. Which kind of box is used is decided by the compiler.]*
When you type:
[self setMonths: [self monthsForYear:newChosenYear]];
You are asking for two methods to be called in one line and the value returned from the inner call ([self monthsForYear:newChosenYear]) has to be passed to the outer call. Where does the compiler store this result? The compiler in effect translates the above into:
NSArray *compilerTemporaryBox = [self monthsForYear:newChosenYear];
[self setMonths:compilerTemporaryBox];
and from the above you know how that goes. There is a small advantage to the compiler in that it knows how long compilerTemporaryBox is needed, so it doesn't need to figure it out, but that will not effect the compiled code.
So after all that the overall answer is it doesn't matter how you write it.
Furthermore the type of memory management you use: MRC, ARC or GC; will not effect the answer - the compiler will end up treating both your variants the same.
So go for the style you find best for you. HTH.
Clang is almost certainly smart enough to compile those two pieces of code to the same resulting machine code. There is no difference in terms of speed or memory issues.
Are you using ARC? Without ARC, with decent optimizer it will have no difference, but with ARC it might use additional retain/release.

Which is a better way of reusing an array: instantiating an array, releasing it, and reinstantiating, or just clearing the array's objects?

For a quiz app, I have a class that stores data in arrays that are related to a specific question. When the user moves on to the next question, I need empty data arrays.
Is it better if I did something like
[class release]; //assume that I properly release the arrays and their objects
[class alloc] init];
or
[arrays removeAllObjects];
or an alternate approach not mentioned?
I feel that my code would be simpler if I use the first solution, but I'm worried that I would be taking up too much memory, since the process would be done multiple times.
Go with the simple solution. After you encounter (measure!) problems start to optimize, not before.
There's really no point in wondering what is more efficient if you don't see any inefficiency.

Worth converting NSMutable<T> to NS<T>

I know the basics of memory management, but not the internals of how iOS handles the different datatypes. Something always nags me that it's best to use an NSData vs NSMutableData or NSString rather than an NSMutableString. Is there really any performance difference unless the code's going to be running in a 10k loop or am I wasting my time?
Use the mutable types where you want to be able to change the contents in place. Use the immutable types otherwise.
In some cases you don't have a choice - such as the data object that holds the returned data from an NSURLRequest: Using a mutable data object is a lot easier than creating a lot of immutable data types and joining them up at the end.
After that, run your code through the profiler and see whether you should do anything differently. i.e. whether the overhead of creating new immutable types to hold objects is more efficient than using a mutable type. Anything else is a premature optimisation.
Like you said its only worth if you call use Mutable many times. But if you call it only a few times this isnt any Problem.
You should think about alternatives, e.g. in a larger TableViews cellForRowAtIndexPath: method. Use [NSString stringWithFormat:#"%#%#", fristString, secondString], Instead of *foo = [[NSMutableString alloc] init] and [foo append:firstString] and so on.

Performance of factory methods in Objective-C

Is there any difference performance-wise in the following 2 snippets of code?
NSString* str = [[NSString alloc] initWithFormat:#"%i", 10];
// Do something with |str|.
[str release];
NSAutorelasePool* pool = [[NSAutreleasePool alloc] init];
NSString* str = [NSString stringWithFormat:#"%i", 10];
// Do something with |str|.
[pool drain];
I see people trying to suggest using factory methods whenever possible.
Isn't it better to release objects as soon as possible rather than when a pool is drained.
I would see the first type being very efficient in certain cases such as in tight-loops.
I see people trying to suggest using
factory methods possible.
I'd guess that's because it's basically the same thing, but you don't have to remember to release the object. Some might say that using the convenience method is a little more readable, too, especially since you don't have to end every method with a sequence of -release messages.
Isn't it better to release objects as
soon as possible rather than when a
pool is drained.
You can make that case in some situations, such as inside a loop. That's often not an important consideration, though... many methods don't loop at all and only create a handful of objects.
I would see the first type being very
efficient in certain cases such as in
tight-loops.
Sure. So you should know when it is and when it isn't appropriate to autorelease objects, and you should write your code accordingly. But it doesn't follow that you should always try to avoid autoreleasing objects any more than it makes sense to always try to use convenience methods.
BTW, if you're writing loops that iterate many times, you should consider creating an autorelease pool. Chances are, you'll be using other methods inside your loop, and those methods might create autoreleased objects. Using your own pool and draining it periodically prevents those objects from piling up. If you do that, though, it takes a great deal of wind out of the the idea that you shouldn't use autoreleased objects in your loop.
Yes it is. First one is better memory management, worth it if you are doing it, like you said, in a loop to avoid allocating a lot before the next pool drain.

Cocoa NSArray/NSSet: -makeObjectsPerformSelector: vs. fast enumeration

I want to perform the same action over several objects stored in a NSSet.
My first attempt was using a fast enumeration:
for (id item in mySetOfObjects)
[item action];
which works pretty fine. Then I thought of:
[mySetOfObjects makeObjectsPerformSelector:#selector(action)];
And now, I don't know what is the best choice. As far as I understand, the two solutions are equivalent. But are there arguments for preferring one solution over the other?
I would argue for using makeObjectsPerformSelector, since it allows the NSSet object to take care of its own indexing, looping and message dispatching. The people who wrote the NSSet code are most likely to know the best way to implement that particular loop.
At worst, they would simply implement the exact same loop, and all you gain is slightly cleaner code (no need for the enclosing loop). At best, they made some internal optimizations and the code will actually run faster.
The topic is briefly mentioned in Apple's Code Speed Performance document, in the section titled "Unrolling Loops".
If you're concerned about performance, the best thing to do is set up a quick program which performs some selector on the objects in a set. Have it run several million times, and time the difference between the two different cases.
I too was presented with this question. I find in the Apple docs "Collections Programming Topics" under "Sets: Unordered Collections of Objects" the following:
The NSSet method objectEnumerator lets
you traverse elements of the set one
by one. And
themakeObjectsPerformSelector: and
makeObjectsPerformSelector:withObject:
methods provide for sending messages
to individual objects in the set. In
most cases, fast enumeration should be
used because it is faster and more
flexible than using an NSEnumerator or
the makeObjectsPerformSelector:
method. For more on enumeration, see
“Enumeration: Traversing a
Collection’s Elements.”
This leads me to believe that Fast Enumeration is still the most efficient means for this application.
I would not use makeObjectsPerformSelector for the simple reason that it is the kind of call that you don't see all that often. Here is why for example - I need to add debugging code as the array is enumerated, and you really can't do that with makeObjectsPerformSelector unless you change how the code works in Release mode which is a real no no.
for (id item in mySetOfObjects)
{
#if MY_DEBUG_BUILD
if ([item isAllMessedUp])
NSLog(#"we found that wily bug that has been haunting us");
#endif
[item action];
}
--Tom
makeObjectsPerformSelector: might be slightly faster, but I doubt there's going to be any practical difference 99% of the time. It is a bit more concise and readable though, I would use it for that reason.
If pure speed is the only issue (i.e. you're creating some rendering engine where every tiny CPU cycle counts), the fastest possible way to iterate through any of the NSCollection objects (as of iOS 5.0 ~ 6.0) is the various "enumerateObjectsUsingBlock" methods. I have no idea why this is, but I tested it and this seems to be the case...
I wrote small test creating collections of hundreds of thousands of objects that each have a method which sums a simple array of ints. Each of those collections were forced to perform the various types of iteration (for loop, fast enumeration, makeObjectsPerformSelector, and enumerateObjectsUsingBlock) millions of times, and in almost every case the "enumerateObjectsUsingBlock" methods won handily over the course of the tests.
The only time when this wasn't true was when memory began to fill up (when I began to run it with millions of objects), after which it began to lose to "makeObjectsPerformSelector".
I'm sorry I didn't take a snapshot of the code, but it's a very simple test to run, I highly recommend giving it a try and see for yourself. :)