I have a critical method in an Objective-C application that I need to optimize as much as possible. I first need to take some easy benchmarks on this one single method so I can compare my progress as I optimize.
What is the easiest way to track the execution time of a given method in, say, milliseconds, and print that to console.
CFAbsoluteTimeGetCurrent() (about 6 microseconds) or mach_absolute_time() from mach/mach_time.h (somewhat faster, but you need to call mach_timebase_info() and do some conversions). You can then print to stdout or use NSLog; note that NSLog takes ages (50 ms?) so you want to do it after taking the measurements. stdout is a bit faster, I think, but doesn't go to syslog (i.e. the Xcode Organizer/iPhone Configuration Utility console).
One thing the others haven't mentioned... when you're performance-checking with Instruments or Shark, be running your app on a device rather than the simulator. The device much slower than the simulator for many things, but sometimes actually faster for some things which it's hardware accelerated for but the simulator isn't, so checking on the device is the only way to get an accurate picture.
Also, be aware that NSLogs can slow it down lots.
There are quite a few ways to instrument your code, but running it through Instruments and/or Shark should give you enough information to see where your code is slow. But remember premature optimization is the root of all evil.
Instruments
Related
I need to measure the performance of a couple of lines of code in my iPhone app. I have a macro that does the job well, but it writes the output to NSLog afterwards (with a delay to make sure that NSLog does not affect the actual performance measurement), so I always have to attach the debugger to the device to get the results.
Now I am wondering if and how the debugger affects performance of the App, eg. I imagine it doesn't affect disk reading/writing commands but probably eats up some CPU time. Are there any docs on this topic? What tools are out there to get performance measurements of apps without the effect of the debugger?
In addition to David's answer, I would say, why don't you try it?
In Xcode 4, go to Product > Edit Scheme... > Run action > Info tab and choose Debugger "None". This way the debugger is disabled and you can test the way you like.
From what I have experienced, other than a jump in RAM there's no difference at all.
However, if you debug using NSZombieEnabled, you can experience some lags.
I need to debug a certain ViewController I have and I can't seem to pinpoint exactly what is causing my lag time for the view to show.
IS there any debugger tool in Xcode that will show me how long my methods are taking to run so i can at least find the right place to start?
Instruments has a profiler built into it ever since iOS 4.0 (before which you used a stand-alone profiler tool called Shark).
Here's a quick little tutorial that will get you started: http://blancer.com/tutorials/flex/78335/apple-profiling-tools-shark-is-out-instruments-is-in/
If you don't know about Instruments, you should. It's how you know what's really going on inside your code while it runs.
Apart from Time Profiler as suggested by Dan you can also use Sampler instrument which generally stops a program at prescribed intervals and records the stack trace information for each of the program’s threads. You can use this information to determine where execution time is being spent in your program and improve your code to reduce running time.
The main difference between sampler & Time profiler :
Sampler instrument operates upon a single process but Time Profiler operates upon a single/All processes.
After a while I figured out I could bind Shark to the process of my executable in the simulator. Not on the device though. Well, anyways, here is something that makes absolutely zero sense, but looks bad:
42.2% 42.2% QuartzCore sw_scanline(int, int, int, ogl_poly_vert*, ogl_poly_vert*, ogl_poly_vert*, ogl_poly_vert*, unsigned int, void*)
That was the topmost entry in the List of Evil. What does Shark try to say here? And how can I fix a performance problem now, with this information? Any idea what that means? Or is there a hidden feature that will give me more useful data?
More likely than not, that is an implementation detail of the Simulator. Probably the bit that does whatever is necessary to make the UIKit drawing show up in a window.
Use the Sampler Instrument against your application running on the device. If that particular function is consuming as much CPU on the device, Instruments will show it.
There is only so much low level optimization you can do in the simulator; anything architecture specific or device specific can't be done, for example. This may be an environment specific difference and, thus, not something to worry about.
My app crashes after about 20 minutes with status 101 (Out of Memory, I believe)
Debugging using Instruments - ObjectAlloc and Leaks gives me no clues. The ObjectAlloc graph stays at a nice constant level of around 1 million bytes (1MB), as does the Net # of allocations. I have got rid of all leaks.
I thought it could be something to do with number of threads, but graphing these in ObjectAlloc also shows them to be constant.
Can anyone point me in the direction of another tool, or another avenue of investigation?
Fix everything Clang finds. LLVM Clang Static Analysis
Remember that objects allocated by the system (and that includes things like images and sounds) don't get tracked in Instruments (although the top level retain counts do, of course). So it's feasable that you're loading images, say, which won't contribute much to your memory usage as show, but can drain a lot of actual memory!
If none of this strikes any chords, you could try the subtractive debugging approach - (take a copy of your project) cut out chunks of functionality until the problem goes away or you get the smallest possible thing that reproduces it. That should at least help you to find where the bottleneck is. Admittedly this will be hard (a) because you'll have to wait 20 minutes or so every time you test (but if you make this a background procedure it's not so bad) and (b) because the nature of memory problems is that there may not be one single cause, but a critical mass of smaller causes.
Good luck!
My experiences with Object Alloc have not been that great. It does not always give you the actual memory used by your application.
Instead, use Object Alloc with Activity Monitor. Make sure you use the "Physical Memory Free" and "Physical Memory used" options in the activity monitor. That will tell you exactly how much memory your application is using.
What do you mean by "nice level". It does not rise over time, at all? How much memory total - it could just be the phone needs some memory for some other app and yours is a little too big to stay up.
The error code 101 means that iPhone OS force quit your app. If you're using UIImageViews in your application, be sure to manage the memory on them. I've found that once my application goes over 10/12 MB, the iPhone terminates it.
If you're not using any image views (or large images), then your backend code is eating up too much space.
All I can say is you need to look at your allocation more carefully and manage what views you keep in memory at any one time.
Run your application in Instruments (Run -> Start with Performamce Tool -> Leaks) to see where your memory is getting allocated.
Hope this helps!
Need advice on how to debug this. I'm new with limited environments and have no previous embedded or smart phone programming experience so I could use some clues.
Already aware of:
Instruments, Clanger Static Analysis, manual code review, etc. Instruments seems to be very helpful in general but quite time consuming and freezes up a lot of the time! Clanger has also helped me a lot as well. It seems like I'm just consuming too much memory in general and I'm wondering what a good strategy is. Do I release some top-level objects? Is there a 'preferred strategy'?
Just wondering if anyone has tackled this successfully and if they have any other suggestions? Thanks all.
There are a lot of good articles for memory management in an iPhone app. Here are some useful links.
http://iosdevelopertips.com/objective-c/memory-management.html
http://kosmaczewski.net/2009/01/28/10-iphone-memory-management-tips/
https://cocoa-touch.blogspot.com/2008/09/memory-management-on-iphone.html
Things you should in general take care of
Release any variables which you do not need
Always handle didReceiveMemoryWarning and release any variables not in use
Stop any memory-heavy processes in applicationDidReceiveMemoryWarning like audio/video playing, UIImagePickerController etc
EDIT
This does not apply any more. imageNamed: had caching issues prior to 3.x OS versions. The issue does not exist any more and you should use imageNamed: (makes implementing retina display easier)
Do NOT use imageNamed: to create UIImage objects.
Basically you're receiving this warning because (unsurprisingly) the iPhone is dangerously low on memory. This can generally be for one of two reasons;
You have a memory leak.
You are allocating far too many objects and need to revisit your design.
For the first one you should run instruments and examine your memory allocations. This can really slow down your app (and requires additional memory) so try testing areas of your app one at a time. E.g. if you have multiple views switch between them a couple of times.
For the second you will have to examine things you are doing that could result in large memory allocations. For example if you're writing a Flickr browser you might need to cut down the number of images you have loaded at anyone time, or free up some unused ones when you receive this warning.
These are about the only general rules I can suggest without knowing more about your app.
Unfortunately there's no real way (that I know of) to get figures for current memory allocation from the iPhone OS. This makes it really difficult to isolate the areas of your application that are inadvertently memory hungry.