

Cue's hookshot: hacking the iOS runtime for fun and profiles - rwalker
http://tech.blog.cueup.com/hookshot-hacking-the-objective-c-runtime-for

======
rwalker
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:

<http://mikeash.com/pyblog/>

~~~
forrestthewoods
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.

~~~
rwalker
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.

~~~
zmitri
Would love to see a concrete example of where this helped out. What's going on
that's so complex under the hood?

~~~
rwalker
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.

------
krickle
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?

~~~
rwalker
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.

~~~
krickle
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?

~~~
rwalker
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.

~~~
krickle
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.

------
dinedal
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.

~~~
rwalker
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 robbyw@cueup.com - I'd love to talk about what
things you wanted to see and let you know if any of them are on the roadmap.

~~~
dreadpirateryan
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?

~~~
kevinclark
Engineer at Cue here.

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:

[https://bugreport.apple.com/cgi-
bin/WebObjects/RadarWeb.woa/...](https://bugreport.apple.com/cgi-
bin/WebObjects/RadarWeb.woa/58/wo/OAdgWRVJFkGt1VRYohMeeg/5.83.28.0.9)

~~~
hboon
Radar's aren't public. File a dup at <http://openradar.appspot.com>?

------
fyolnish
Why/When is this better than Time Profiler?

~~~
rwalker
Time Profiler is a sampling profiler, this one is instrumenting. They're both
useful at different times - we find this one useful for

* Thread activity graphs with drill-in

* Seeing accurate counts of calls

* More precise per-call timings of messages

* Measurement of messages with highly variable performance

