views:

702

answers:

4

Hi all,

I'm debugging slow startup of an iPhone application (Xcode, Objective C++). It's a tabbar-based app with three tabs. All three tabs are loaded in a single NIB - about 20 objects total.

The first round of significant initialization takes place in the viewDidLoad handler of the first tab's view controller. However, it takes about 1 second between main() and that method's start time - about 2/3 of the total loading time. Question - what is going on during that time, and how do I investigate that (short of stepping through the disassembly)? To the best of my knowledge, there's no my code in between the two moments - the delay happens entirely in the system code.

Maybe some kind of Instrument that can give me per-function time profile?

The bundle is ~4 MB total, but I'm loading the biggest file (~3.5 MB) later than that, in the applicationDidFinishLaunching handler. Removing that file from the bundle and commenting out the relevant code does nothing for that 1-second delay.

UPDATE: there was debug interference after all. If I run it on the device while watching the console, the startup time us considerably shorter, and the proportion of delay - system code to my code - is skewed, too. But still, there's a noticeable delay between main and viewDidLoad, and it's about 50% of total loading time.

By the way, of all ways of loading a largish file from the bundle completely into memory, the fastest one was direct memory-mapping (using POSIX mmap()).

+4  A: 

Hey,

There are two things that could be going on here. If you're debugging your app from within XCode, there's a good chance that the application is waiting at startup to attach to the GDB debugger. In my experience, that takes about a second. Try running your app without saying "Build and Go" in XCode and see if the results are any different. (Just click it from the home screen instead)

Your NIB file might also be the issue. 20 objects isn't too many, but you might consider breaking each tab into a separate NIB file if all else fails. The contents of NIB files referenced from your primary NIB file are lazily loaded, so the app will not load views for the two tabs that are invisible until they are selected. That might give you a performance boost at startup, though I don't think it could account for a full second.

Apple's got some great performance analysis tools in the iPhone SDK, but they're a bit hard to find. In the Run menu, select "Run with Performance Tool" -> "CPU Sampler." That will launch a separate application called Instruments which allows you to do all sorts of great runtime analysis. When you have the CPU instrument selected, the bottom half of the Instruments window provides a breakdown of what was taking CPU time in your app. You can double click functions to dive into them, and get a line by line breakdown of % of cycles used. It should give you more information about what specifically is causing your problem.

Ben Gotow
I'm counting time within the program, so debugger interference should be minimal. By the time main() gets control, the debugger should be already attached. I know they recommend separate NIBs for tabs, but I tried removing everything from the 2nd and 3rd tab - the delay was pretty much the same. I ran the CPU Monitor. Kinda hard to interpret. :( It says 72% of the time is spent under mach_msg_trap - but isn't that the system's generic "wait for event" function?
Seva Alekseyev
Actually, I've found that the debugger does cause significant interference, particularly when timing startup. My suggestion would be to have your code log the times to the console, start the application manually on the device, and read off the timings in the console log from your device in the Organizer.
Brad Larson
I'm already using NSLog() to record time. Will that appear in the Organizer?
Seva Alekseyev
Yes, NSLogs get dumped to the system log if you're not running the application through Xcode, and their results are visible in the Organizer (I've seen the Organizer lag a bit, so you might need to start your application a few times to have them all show up).
Brad Larson
Good grief, I can't believe this was the issue. There's a average 8 second pause while the debugger attaches to the iPhone (you can verify this using the Console log in the Organizer window). Thanks Ben!
Rob S.
A: 

If you found your xib files are too large, I advice you build your UI with pure code. large xib files will surely slow your startup time, and also slow your app when you frist use an object in your xib.

I don't use xib in my projects, cause when somebody changed the xib in svn, you can hardly find what is changed. That's to say, xib is not going well with SVN.

Xie Wei
A: 

I'd recommend splitting up your app into three NIBS; the tab bar and the tab bar controller displayed on launch in the first, then lazily load the other two the first time the user switches to them.

I believe you can use the File >> Decompose Interface function in Interface Builder to accomplish this.

Andrew Ebling
That's the official line. But see comment under Ben's answer.
Seva Alekseyev
+2  A: 

If you really are curious about what's executing during startup, and the relative times each method takes to run, you can create a custom DTrace script to track this. I describe how to do that towards the end of this article. This script will show you every method executed by your application in order from startup to the end of -applicationDidFinishLaunching:, along with the time spent in that method. You can run this script as a custom instrument in Instruments or as a standalone script (the standalone script tends to be more accurate on a system under load).

The major caveat of this approach is that it will only run in the Simulator, given the current lack of support for DTrace in the iPhone OS itself. However, you should be able to extract the order in which things are executed in your application's startup, as well as relative times that your application spends in each method. This will even show behind-the-scenes private API calls being made as your application starts, which might provide some additional clues as to what's going on.

For additional startup tuning suggestions, I'd recommend reading James Thomson's article "How To Make Your iPhone App Launch Faster".

Brad Larson