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.
Related
I am developing an app for the iPhone and am encountering some memory management issues. During execution of the app the live bytes continuously increase without bound. I have tried to track down the issue within my code but cannot seem to find anything that would cause the live bytes to increase so dramatically. The one thing that I have noticed during execution is that the allocation for CFString(Immutable) increase the most rapidly and never decrease or stay constant. Does anyone have any idea why this may be happening? All that the app is doing during this execution is populating a table view from a local array or strings, then downloading another array of string objects and populating a different table view. I am using ARC.
Given the lack of anything concrete to go on, I'll give you somewhat general counsel:
See Finding leaks with Instruments for guidance on how to use Instruments to find leaks.
For specific advice how to go from you allocations, to a more meaningful analysis of the source of those allocations, see point #4 of this Stack Overflow answer. In short, highlight one of your unexplained jumps in allocations, set the bottom window to show you the call tree, hide system libraries, and see in which of your routines the memory is being consumed.
Also, don't overlook the static analyzer, which is especially important if you don't use ARC, or if you use any Core Foundation calls.
Are you doing anything with Core Foundation functions? If so, you obviously need to know that you either have to explicitly transfer ownership to ARC (with either CFBridgingRelease or __bridge_transfer) or manually call CFRelease. The static analyzer of my prior point would point this out to you, though.
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
I'm trying to port a game library over to the iPhone. Unlike SDL, this library doesn't take full control of your main() function, it's communicated with via quickly-returning functions from your own code. So, for example, obvious pseudocode:
int main() {
library_init();
// game init code here
while(we_have_not_quit_the_game) {
library_message_loop();
library_init_render();
// render stuff
library_end_render();
// update game state
}
library_shutdown();
}
iPhone makes this difficult, as it requires that you call a UIApplicationMain function that never returns. There's simply no way I could ever get back to the user code after library_init();.
I'm not convinced it's necessary - there's NSRunLoop which supposedly could be used to handle the events. I don't know if UIApplicationMain does anything else of importance, however. (Note that I have no plans to use .nib files, which is the only other thing I've found that UIApplicationMain does.)
I've got three real ideas that I can think of, but they're all a major implementation effort so I'd like to know if anyone has experience with this before I burn a day trying doomed ideas.
In Init, spawn a new thread, run UIApplicationMain in that thread. Either communicate all events across threads (ugh) or just put the UIApplicationMain thread to sleep and use a CFRunLoop in the main thread. I've heard UIApplicationMain does not like being run in a different thread, however.
Ignore UIApplicationMain entirely, just use NSRunLoop. Am I going to be missing important iPhone setup? Who knows!
Do something horrifying with longjmp() to leap out of the UIApplicationMain code after setup, pray that it doesn't do anything important during teardown.
Suggestions?
Looks like I'm answering my own question here! I'm not accepting my answer until I've been able to both test it on real hardware and get it into the app store. That said, I'll keep my Most Up-To-Date Info here, including which options didn't work.
Idea #1: It turns out that each NSRunLoop is thread-specific. If I create a UIApplicationMain in a separate thread, it doesn't get any messages. As a side effect this makes it impossible to determine when it's finished initializing, so if there's anything non-threadsafe it does, it just won't work. I may be able to send it a message across threads to figure out when it's finished initializing, but for now I'm calling this a dead end.
Idea #2: UIApplicationMain does a lot of subtle stuff. I'm not sure what it's restricted to, but I was unable to make anything work without involving UIApplicationMain. Idea #2 is right out.
Idea #3: Receiving the OS signals is important - you need to know if there's a phone-call overlay, or whether you're about to exit. On top of that, some of the setup messages seem vital in order to start the app properly. I was unable to find any method to keep messages being sent without being inside UIApplicationMain. The only options I came up with were NSRunLoop and CFRunLoop. Neither one worked - the messages didn't come in like I wanted. I may not be using these right, but in any case, Idea #3 is out.
Brand-new crazy Idea #4: It's possible to use setjmp/longjmp to fake coroutines in C/C++. The trick is to first set the stack pointer to some value that won't clobber anything important, then start your second routine, then jump back and forth, pretending like you have two stacks. Things get a tiny bit messy if your "second coroutine" decides to return from its main function, but luckily, UIApplicationMain never returns, so this isn't a problem.
I don't know if there's a way to set the stack pointer explicitly on real hardware, say, to a chunk of data that I allocated on the fly. Luckily, it doesn't matter. The iPhone has a 1MB stack by default, which is easily enough to fit a few coroutines in.
What I'm currently doing is using alloca() to push the stack pointer ahead by 768 kilobytes, then spawning UIApplicationMain, then using setjmp/longjmp to bounce back and forth between my "UI routine" and my "main routine". So far, this is working.
Caveats:
It's impossible to know when the "UI routine" has no messages to handle, and when it has no messages to handle, it will just block indefinitely until that's no longer the case. I'm solving this by making a timer that triggers every 0.1 milliseconds. Every time the timer triggers, I drop out to my "main routine", do a single game loop, then head back into the "UI routine" for another timer tick. Reading the documentation indicates that it won't stack up "timer calls" indefinitely. I do seem to get the "terminate" message appropriately, though I haven't managed to test it thoroughly yet, and I haven't tested any other important messages. (Luckily, there's only four messages total, and one of them is setup-related.)
Most modern OSes won't allocate the entire stack at once. The iPhone is probably one of these. What I don't know is whether bumping the stack pointer 3/4 of a meg forward will allocate everything "behind it", so to speak. If so, I may be effectively wasting 3/4 of a meg of RAM, which, on the iPhone, is significant. This could be handled by bumping the pointer forward a smaller amount, but this is really courting stack size disaster - it effectively limits your stack to however far you bump the pointer ahead, and you'll have to figure this out in advance. Some sentinel data in the stack, coupled with good monitoring and a logging system for stack size issues, can probably solve this, but it's a nontrivial issue. (Alternatively, if I can figure out how to muck with the stack pointer directly on the native hardware, I can just malloc()/new[] a few kilobytes, point the stack pointer at it, and use it as my new stack. I'll have to figure out how much space it needs but I doubt it'll be much, considering that it's not doing very much.)
This is currently untested on the actual hardware (give it a week or two, I got another project to finish first.)
I have no idea whether Apple will figure out what I'm doing and slap a giant REJECTED sticker on it when I try submitting to the app store. This is, shall we say, slightly outside their intentions for the API. Fingers crossed.
I'll keep this post updated, and officially accept it once I've verified that it, you know, works.
Late update: I got distracted by a variety of other things. Since then, I've had a few changes that make me far less interested in Apple development. My current approach showed no sign of not working, but I don't really have the motivation to keep fleshing it out. Sorry! If I ever change my mind I'll update this further, but Outlook Not So Good.
I know NSApplicationMain() reads Info.plist and does stuff to the app (like get the initial nib file) so I would guess that UIApplicationMain() does the same for iPhone (like get the initial status bar style, zoom the default.png image in etc.). That stuff isn't exposed anywhere else, so the functions it calls would still need to be run for the app to launch with out any side effects. You're only bet is to reverse engineer those and copy them (and hope that anything they do is in the public SDK).
Is the goal to take that main() function and have it work unmodified on the iPhone?
It would seem there's no way you're going to completely insulate the users of the library from thinking about the iPhone platform--they're going to have to deal with XCode for code signing and that sort of thing.
Given that, telling users they have to break their main() function up into a few pieces that you can call from applicationDidFinishLaunching and from an appropriate timer doesn't seem like it would inconvenience anybody much.
Why not start your game loop from within UIApplication? (Yes, you can't have it in main() but that shouldn't matter.) Some of the delegate messages are good candidates.
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!
I have an iPhone app that is running great in the simulator. It responds well to the memory warnings by getting rid of everything that is not absolutely essential. When I run it on the device, it runs well. But after a certain amount of usage it crashes with error code 101 - which, from what I can tell, is the OS killing it due to memory usage. I can see the memory warning (I'm logging it), and my app responds to it, but dies shortly thereafter.
If I look at the app in Instruments (either on the device or in sim), it doesn't find any leaks. In addition, the net memory usage is in the range of 600-700k bytes. Transitioning from the different views of my app increases memory usage (as expected), but when the views and controllers are released and dealloc'd, the memory usage never quite goes as low as it was. However, the addition is usually only something in the range of 1000-2000 bytes. So while Leaks shows me no leaks, I suspect there is an issue somewhere. I've also looked at all of the objects I'm allocating, and all of them seem to be reclaimed as expected. The only objects I see that keep increasing are GeneralBlock-N (where N is some number)
Should I not pay any attention to Instruments net usage figure? What would be the next steps in trying to diagnose the issue?
ADDED: I'm not making any calls to malloc() or any CoreFoundation libraries that would return a buffer that I'm responsible for. The only non-Obj-C calls I'm making are logging statements to NSLog.
One quick thing to try is running the Clang static analyzer. This will find some, but not all, issues in your code that you might be missing. It checks the code at compile time, so it's by no means infallible, but will almost certainly find most glaring problems.
You should also run your application with the memory monitor instruments to see overall system usage on the device.
Leaks only finds memory that is not referenced by anything, but still retained.
What you are seeing is that you have left memory retained, and still referenced by something.
One thing to look for especially, is that if you have passed a reference of a class to something else as a delegate that you free it in your dealloc method.
Similarly, if you have subscribed to any notifications you should unsubscribe in viewWillDisappear: (if you use the general unsubscription method in a view controller do not forget to re-subscribe to the memory warning notification.
Timers are the same way, deactivate them when a view goes away and re-enable them when the view comes back (unless of course you need a timer running the whole time your application is running).
Basically be suspicious of anything you give a reference of a class to, and try to figure out how you might eliminate that link whenever possible (either in dealloc or viewWillDisappear: or both).
Here's a summary of what I've learned (thanks to some excellent answers and comments):
Object Allocation is NOT the same as Memory usage. The answer to my question about ObjectAlloc's net bytes element is that you shouldn't be paying attention to it - at least not when determining issues with the amount of memory you are using or whats causing it to crash. It doesn't reflect the true memory usage of your application.
My amatuerish guess is that ObjectAlloc only shows you the memory taken up by the direct object itself. So if you have an UIImageView, it takes up just a handful of bytes to store the various properties, but it might be pointing to an image in memory taking up a bunch of space. Therefore, looking at ObjectAlloc is helpful only in making sure you're not creating and keeping objects around, it won't give you an idea of how much memory you're using or how much you can use before crashing.
MemoryMonitor will give you the total memory usage. You can constrain it to viewing only your app's usage by using the search tool in the bottom right of the Instruments window.
Both ObjectAlloc and Memory Monitor (as well as the Leaks tool) are plugins for Instruments - just in case thats not obvious to someone else. You can launch Instruments from within XCode by doing Run -> Start with Performance Tool. Once inside of Instruments, you can open the Library and add new plugins to monitor different aspects of performance.
One thing to look for is circular references.
(I don't want this to sound patronising - just want to make sure I'm being clear:) If object a refers to object b and object b refers to object a, there may not be a reported "leak" because all the memory is still referenced - but this may be an orphaned island of objects, seperated from your app and never reclaimable. Of course it may involve more objects ( a refers to b, b refers to c, c refers to a, etc).
If you're building up a graph of objects somewhere, and there are any back or cross references, be sure to break the circles if you release the root (there are different ways of doing this. The simplest is probably to make sure each class in question has a releaseAll method, or similar - which calls releaseAll on it's child objects, then releases the child objects - but this isn't always the best solution).