Robby from Cue here: we've found a ton of non-trivial performance wins for the Cue app by using this. Let me know if there are things we can do to make it useful for you too.
A lot of the inspiration for how to actually make this work came from Mike Ash's awesome NSBlog:
A post like this is begging and screaming for concrete numbers. I want to see - initial perf, perf with Apple sampling, perf with hookshot instrumentation, perf after fixing issues found via hookshot.
Fair point! It's hard to assign numbers to perf for something like an entire application - a lot of the wins we found were places where the main screen was locked (causing app un-responsiveness) or where we were able to change the order of some actions to get the app to render quicker.
I'd say the app takes around 2-3x less time to load than when we started our most recent performance quest, largely due to issues we found using hookshot. We did find some performance critical inner loops in our rendering code where we were able to achieve something like 10x speed-ups.
Apple's profiler has significantly lower overhead than hookshot - which makes sense given the relative amounts of information collected. Our app runs noticeably slower when hookshot is enabled, but when it is disabled, hookshot introduces exactly 0 overhead. We only enable it when we're specifically debugging performance issues.
One example that comes to mind: we have a networking layer that prioritizes some HTTP requests over others. For example, we seed our cache by firing off requests for the next 30 days, but at a low priority. There was a bug in this layer where request initiation could block the main thread while unrelated work was finishing.
Another example: we used the "HOOKSHOT_TAG" macro to tag objects related to rendering different days in Cue (today, yesterday, tomorrow). This makes the thread activity graph use different colors for time spent on those objects. This helped make obvious a few edge cases where some rendering/processing for a day that was not on screen was done before the day that was.
This kind of stuff is awesome. I made a profiler for ObjC that did a similar thing, but by programmatically creating a new subclass and only profiling certain instances.
On your prevent instrumentation proxy methods; if the original method references ivars without using self.x or [self x] do you notice weird results?
Seems to work fine since we're dropping in the exact same implementation instructions as would have been there otherwise, and using the same object too. That way, any ivar references still correspond to the same positions in memory.
I misread you as running the original method on the proxy object. But if you don't, aren't you missing methods you do want to track called from methods you don't?
The trick is that we use the same original object at the same address in memory and overwrite what class it thinks it is (as opposed to wrapping it). So in a way it becomes a proxy to itself.
I see, I thought you were using the proxy as normal and had programmatically made new classes also. But you are creating an object and then setting its class to the proxy. Neat.
Off topic: The reason I closed my Cue account was two fold, because I would get notifications for calendar events sometimes _days_ after they had occurred, and because even though I linked everything under the sun to it, I would more often then not be presented with a day that has just sunrise and sunset on it. App just provided no real value, and I really wanted it to work and work well.
Sorry to hear it! About two weeks ago we closed the last of our known push bugs. There is one that's left where iOS itself will re-send an old push along with new notifications which is fixed by a phone restart. (this happens with all apps, not just ours)
If you have time, email me at [email protected] - I'd love to talk about what things you wanted to see and let you know if any of them are on the roadmap.
I've run into that iOS push re-send bug a few times, but I've had trouble finding any information about the bug online. It seems to only happen to me for scheduled push notifications, but not immediate push notifications. Do you have any online resources that talk about this bug?
We haven't been able to reliably reproduce the problem and haven't found much about it online. I've filed a bug report here if you'd like to add your two cents:
A lot of the inspiration for how to actually make this work came from Mike Ash's awesome NSBlog:
http://mikeash.com/pyblog/