81: Profiling
00:00:00
◼
►
Welcome to Under the Radar, a show about independent iOS app development.
00:00:04
◼
►
I'm Marco Armet.
00:00:05
◼
►
And I'm David Smith.
00:00:06
◼
►
Under the Radar is never longer than 30 minutes, so let's get started.
00:00:11
◼
►
So as a follow-up in some ways to what we were talking about last week with debugging,
00:00:14
◼
►
it seemed only right to this week talk about profiling and to talk about sort of that next
00:00:20
◼
►
step beyond just making your app work correctly, which is largely what debugging is focused
00:00:25
◼
►
on, and instead to make it work in a performant way, to work not just correctly, but to work
00:00:34
◼
►
well as well.
00:00:35
◼
►
And there are some parts of profiling that are also kind of debugging and digging out
00:00:41
◼
►
kind of more subtle bugs, but a lot of what I've—when I turn to profiling, you know,
00:00:45
◼
►
when I'm in Xcode, you know, I can run, I can build and run, I can build and test,
00:00:50
◼
►
build and profile, build and analyze.
00:00:51
◼
►
Like, those are kind of the core things before I archive the build and send it off to iTunes
00:00:57
◼
►
And profiling tends to come towards the end of the process.
00:01:00
◼
►
And profiling generally in, you know, in this context is running Xcode, running your build
00:01:06
◼
►
while attached to instruments on your Mac, where instruments is this tremendously powerful
00:01:13
◼
►
tool that does way more things than I could possibly really understand.
00:01:18
◼
►
But the things that I do understand it does is just amazing, because it can give you insight
00:01:22
◼
►
into what is happening inside your application in a way that you can't really measure any
00:01:28
◼
►
other way, because it's kind of doing this—it's this interesting combination of measuring
00:01:32
◼
►
external things about your app, but it's doing it in a context where it is aware of
00:01:38
◼
►
your source code and aware of your app in a way that can give you great insight into
00:01:43
◼
►
what's going on.
00:01:45
◼
►
And there's a whole bunch of areas that we'll dive into from where profiling is
00:01:49
◼
►
really useful.
00:01:50
◼
►
But I will also mention that the one thing I always do before I go into profiling—you
00:01:54
◼
►
know what I mean—at the point in building an app where I hit the point where I feel
00:01:59
◼
►
like now I need to start tuning things down, which is largely what profiling gets into.
00:02:04
◼
►
Like, just earlier today, I was dealing with something with big data import, and I got
00:02:08
◼
►
it working correctly, but the import was taking about a minute.
00:02:11
◼
►
And I was like, "Mm, let me see if I can make this faster."
00:02:14
◼
►
And so that's when I turned to the profiler, and I work to make it faster.
00:02:19
◼
►
I want to make no changes to its functionality, I just want to make it faster.
00:02:22
◼
►
But the first thing I always do is I also, before I go into profiling, I always run build
00:02:26
◼
►
and analyze.
00:02:27
◼
►
And build and analyze in Xcode is a tool that—it's static analysis of your application.
00:02:33
◼
►
So it's looking for kind of structural problems or issues that you may not be aware of, like
00:02:40
◼
►
things where you're assigning to a value and never reading from it, or wasted work
00:02:45
◼
►
or structural problems.
00:02:46
◼
►
And I will say, it catches fewer things now than it used to for me, because I think a
00:02:51
◼
►
lot of this has been rolled into the compiler itself.
00:02:54
◼
►
And so as I'm typing out these issues, they're being lit up inside of my source editor.
00:03:01
◼
►
But it's still, every now and then, it will catch something that is one of these things
00:03:05
◼
►
that saves me a whole bunch of effort in the profiling phase, just by saying, "Hey, you're
00:03:11
◼
►
doing all this work and then throwing the value away without ever reading from it.
00:03:15
◼
►
Do you actually mean to do that?"
00:03:17
◼
►
So for me, I always run build and analyze first, but then I dive into the profiler.
00:03:22
◼
►
And that's kind of the flow that I find to work pretty well.
00:03:25
◼
►
Yeah, I mean, there's this whole discussion about whether you should even be optimizing
00:03:31
◼
►
things before it's really a problem.
00:03:33
◼
►
The concept of premature optimization.
00:03:36
◼
►
And I feel like there's, as with most things, there's a balance to be struck.
00:03:40
◼
►
I should have a bell for every time I say that.
00:03:43
◼
►
But there's a balance to be struck here.
00:03:45
◼
►
And the way you did it, in the example you decided was great, which is you didn't actually
00:03:51
◼
►
go looking for deep profiling information until there was something about your app that
00:03:56
◼
►
was noticeably slow.
00:03:58
◼
►
And that's when you decided, "Okay, I need to investigate this.
00:04:00
◼
►
I need to find this problem and fix it."
00:04:02
◼
►
That is a very healthy way to do things, as opposed to trying to micro-optimize every
00:04:10
◼
►
little possible step along the way, because usually if you try to do that, your code becomes
00:04:15
◼
►
less readable, less obvious, usually more bug-prone.
00:04:19
◼
►
And it's also just wasted effort a lot of the time.
00:04:21
◼
►
If you're going to go through and micro-optimize something, that ends up being such a tiny
00:04:26
◼
►
fraction of usage time that it's not even really worth having optimized.
00:04:32
◼
►
And so step one is try to avoid premature optimization.
00:04:36
◼
►
And it's arguable what counts as premature or unnecessary.
00:04:41
◼
►
But for the most part, if something is going to take a lot of work to make really fast,
00:04:48
◼
►
it's a good thing to first consider how necessary is this, and then to use the profiler to first
00:04:56
◼
►
profile it beforehand and see how fast or slow it is without any optimization that you
00:05:02
◼
►
And then as you try optimization methods, profile it and see, is this really helping?
00:05:08
◼
►
Because if it isn't, roll it back.
00:05:10
◼
►
Or sometimes you might think you're making something faster, or you might even be making
00:05:14
◼
►
And so you always have to not necessarily-- if you're a programmer, I feel like there's
00:05:19
◼
►
this instinct to make things what you think might be fast and clever and efficient and
00:05:26
◼
►
whatever else.
00:05:27
◼
►
But a lot of times, modern hardware is complicated.
00:05:30
◼
►
And a lot of times, things are not what you think they are in terms of relative performance.
00:05:35
◼
►
You might think that the more naive approach is super slow, and your clever possible optimization
00:05:42
◼
►
is super fast.
00:05:44
◼
►
But if you actually measure it with the profiler, you might find the opposite.
00:05:47
◼
►
You might find that, oh, it turns out the naive approach is being optimized by the compiler
00:05:52
◼
►
or hardware in a way that ends up making it faster than your custom optimization might
00:05:58
◼
►
be, or at least not substantially slower.
00:06:02
◼
►
There's been all sorts of optimizations over time to things like the Objective-C runtime
00:06:07
◼
►
and the compiler and the tools.
00:06:10
◼
►
And the hardware is so good now that a lot of things might seem like good candidates
00:06:15
◼
►
for optimization, but they actually aren't.
00:06:18
◼
►
And only the profiler running only on the device hardware that you're targeting can
00:06:24
◼
►
really tell you that a lot of the time.
00:06:26
◼
►
And I think, too, it's also a good point along those same lines of the importance of
00:06:30
◼
►
doing profiling in a quantitative approach, which is probably no surprise that that's
00:06:35
◼
►
what I love about profiling.
00:06:36
◼
►
Wow, I'm so surprised.
00:06:38
◼
►
But I love that you can-- and I think it's important to look at this thing from a sense
00:06:43
◼
►
of this operation is starting off taking this amount of time.
00:06:48
◼
►
Or depending on which part of the profiler you're working in, it'll be measured in
00:06:52
◼
►
seconds or frames per second or whatever it is.
00:06:55
◼
►
And having a number that you're trying to move, to affect.
00:07:01
◼
►
And be mindful about are you able to make substantial changes to that number.
00:07:07
◼
►
So in this case that I was working on this morning, I have an import that's taking
00:07:11
◼
►
a minute to run.
00:07:12
◼
►
So 60 seconds is my baseline.
00:07:14
◼
►
And how can I affect change to that?
00:07:18
◼
►
And the trap that I used to fall into a lot with profiling is feeling like I was going
00:07:25
◼
►
to be making progress as I was making these little improvements to that.
00:07:29
◼
►
Going from my 60 second target to 57 seconds by introducing some crazy convoluted scheme.
00:07:35
◼
►
And in theory, if you keep making these lots of small chunks into it, in theory you'll
00:07:42
◼
►
end up better.
00:07:43
◼
►
But in general, I think the thing that I've found more often is that my app is just worse
00:07:48
◼
►
as a result.
00:07:51
◼
►
When profiling works well, I'll start off with a big number, I'll find a bottleneck,
00:07:56
◼
►
I'll find some issue that if I can alleviate, we'll take that number and drop it in half.
00:08:02
◼
►
Or even better maybe.
00:08:04
◼
►
And if I can't find an optimization that will drop it in these big orders of magnitude
00:08:11
◼
►
changes, usually I just say, "That's as good as it's going to be."
00:08:14
◼
►
And I avoid the feeling of chasing down all these little micro-optimizations, because
00:08:21
◼
►
almost always they're going to reduce code readability, testability, understandability
00:08:26
◼
►
in the future.
00:08:27
◼
►
It's usually going to be something that I will regret and my future self will be very
00:08:31
◼
►
mad at my current self for doing.
00:08:34
◼
►
And it's just so much more bug prone too.
00:08:36
◼
►
I always have that bite me.
00:08:38
◼
►
Whenever I do any kind of clever optimization, it always introduces bugs that I didn't anticipate.
00:08:44
◼
►
And I'm working around those bugs forever from that point forward until I get rid of
00:08:49
◼
►
the optimization.
00:08:51
◼
►
And so it's vitally important to make sure that if this optimization you're doing has
00:08:55
◼
►
a measurable and dramatic impact, like half the time, a tenth of the time, whatever it
00:09:01
◼
►
is, then okay, maybe this trade-off is worth doing.
00:09:04
◼
►
But if you aren't measuring it, you'll have no way to know the magnitude of that impact.
00:09:10
◼
►
Because often I'll go down there in profile, I'll be like, "Ah, I don't think I can
00:09:14
◼
►
make this any better."
00:09:15
◼
►
And that's it.
00:09:16
◼
►
And sometimes things are just slow in apps and that's okay.
00:09:19
◼
►
It's better for it to work correctly and be slow than to work fast and break because
00:09:24
◼
►
that's not really working at all.
00:09:28
◼
►
And usually, I like what you said a minute ago, usually the correct number of optimizations
00:09:34
◼
►
to do to fix a certain problem is usually between zero and one.
00:09:39
◼
►
Because if, as you said, if you run a time profiler in instruments and you do the thing
00:09:46
◼
►
in your app that you think is slow, if there's not one big thing there that's taking up
00:09:52
◼
►
most of the time, it's probably not even worth doing optimization this way.
00:09:57
◼
►
It's probably instead, if this is a problem for your app, it's probably instead worth
00:10:00
◼
►
thinking like, "Okay, how can I either avoid doing this at all or how can I do it in a
00:10:05
◼
►
different way where it wouldn't be a problem?"
00:10:08
◼
►
And if you still have to do some kind of massive CPU intensive work, which I think very few
00:10:13
◼
►
apps do, then you look into things like, "Okay, well let me do this on a background thread
00:10:18
◼
►
and provide a progress UI to the user so that at least, if there's no way to make this
00:10:24
◼
►
fast, at least make it nice during use and make it clear what's going on."
00:10:29
◼
►
That's when you get into that kind of thing.
00:10:30
◼
►
But usually, that's not what we're dealing with in our apps.
00:10:33
◼
►
Usually we're dealing with more simple things.
00:10:36
◼
►
One example that I ran into is that in Overcast, there's this collection of podcasts and
00:10:43
◼
►
episodes and everything.
00:10:44
◼
►
And there's a lot of parts of the app that have to reload their data sources or update
00:10:50
◼
►
their data sources whenever the list of playable podcast episodes changes.
00:10:57
◼
►
This is like whenever a new episode comes in or if the user deletes or completes an
00:11:01
◼
►
episode or when a download completes in certain contexts where things can only be downloaded.
00:11:07
◼
►
So there's a few conditions here where whenever these things change, all these different parts
00:11:14
◼
►
of the app need to update themselves on the list of playable items for whatever reason
00:11:19
◼
►
that they need that list.
00:11:22
◼
►
This was a very, very heavy operation whenever this would happen because so many parts of
00:11:27
◼
►
the app need that.
00:11:28
◼
►
This is like the long shortcuts, the playable content manager for CarPlay, the playlist
00:11:32
◼
►
screen, the list of podcasts within each playlist.
00:11:36
◼
►
If any of these things are open and some of them are always running, like the CarPlay
00:11:38
◼
►
manager, you need to know when that changes.
00:11:42
◼
►
So whenever the playable content notification was fired, huge amounts of work had to be
00:11:48
◼
►
done in the app.
00:11:49
◼
►
This can be done in lots of apps like whenever you have a table view, reload data.
00:11:53
◼
►
This is a very common thing.
00:11:56
◼
►
Something in the data source changed, reload data.
00:11:58
◼
►
That's easiest most of the time than trying to do anything dynamic.
00:12:03
◼
►
And so it's a pretty common pattern.
00:12:05
◼
►
And what I was finding was that it was kind of behaving slowly.
00:12:09
◼
►
The app was kind of behaving slowly and people were complaining on certain phones, like the
00:12:12
◼
►
older ones, like the iPhone 5 or whatever else.
00:12:14
◼
►
So I loaded it up and I noticed on this old hardware, yeah, this is really slow.
00:12:19
◼
►
So I profiled it and saw it was all these table view reloads and everything from the
00:12:23
◼
►
playable content manager being updated.
00:12:26
◼
►
And so the solution here was just make that update less often.
00:12:30
◼
►
I was having an update on every change to the relevant tables in the database, like
00:12:37
◼
►
the episode table.
00:12:38
◼
►
Every time an episode was updated, refresh the playable content.
00:12:43
◼
►
But that's things like when the user listens to a few more seconds of the episode and it
00:12:47
◼
►
saves the progress to disk on how far they've listened.
00:12:50
◼
►
Well, I don't need to update it for that.
00:12:52
◼
►
It doesn't matter whether they've listened 30 seconds or 35 seconds in.
00:12:55
◼
►
So I added optimizations for things like, okay, well, don't even fire the playable content
00:13:00
◼
►
change notification unless certain fields have changed that actually matter.
00:13:06
◼
►
And I built an architecture in place for like whenever anything is listening for database
00:13:10
◼
►
changes in my FC model database layer class, which is open source if you want to use it,
00:13:14
◼
►
although I wouldn't recommend it, but if you do want to use it, go ahead.
00:13:19
◼
►
There's now things in there where like you can say like notify me if only these columns
00:13:24
◼
►
of this table change.
00:13:26
◼
►
And then so like I was able to build these optimizations that have pretty big impacts
00:13:30
◼
►
but are more in the realm of like reducing the amount of work that takes place and reducing
00:13:36
◼
►
the frequency of high needs operations rather than going super low level and trying to make
00:13:43
◼
►
like table view reloads substantially faster all over the app.
00:13:46
◼
►
Yeah, because I think then the big point there is it's like more often than not, the great
00:13:51
◼
►
thing that I find in profiling is that like the issue is something understandable.
00:13:57
◼
►
The optimization should likely be an obvious, tractable thing.
00:14:01
◼
►
Like you go through the time profiler, which is probably the one that I spend the most
00:14:04
◼
►
time using, and it's like, why am I calling this method 500 times?
00:14:08
◼
►
Oh, that's interesting.
00:14:10
◼
►
It's getting called 500 times a second because it's keyed into some other part of the app
00:14:15
◼
►
that is doing something that it really doesn't need to be communicating with it.
00:14:20
◼
►
It's like it's a big obvious change.
00:14:21
◼
►
Like, huh, that doesn't look right.
00:14:23
◼
►
And it's a very obvious change.
00:14:25
◼
►
And those are the things where if you see one of those, it's like, great, you just
00:14:28
◼
►
found like you can make a change that is very low risk.
00:14:31
◼
►
You're not kind of, it's not like, oh, no, I need to like dive into accelerate and
00:14:35
◼
►
do some crazy GPU version of my algorithm to avoid.
00:14:39
◼
►
Like, if that's what you're doing, like, that is very fun.
00:14:41
◼
►
I mean, that might be fun.
00:14:43
◼
►
That's super interesting.
00:14:44
◼
►
And like, see our previous episode on indulgences.
00:14:47
◼
►
Yeah, like, that's really cool if you if you can a do that and be if that's relevant
00:14:53
◼
►
to your application.
00:14:55
◼
►
But in the context of something like for most applications, like that's almost certainly
00:14:59
◼
►
not the answer.
00:15:00
◼
►
Like the right answer is just finding the methods that is being called too many times,
00:15:04
◼
►
you know, where it's like, it's your have a method that's called outside of an F where
00:15:07
◼
►
it should be called inside of an F, you know, it's just like, oh, you should really only
00:15:10
◼
►
be calling this method at the end, rather than every time you cycle through the loop
00:15:14
◼
►
or that kind of thing.
00:15:16
◼
►
And anytime you see one of those, you're like, perfect, like, like the profiler just
00:15:19
◼
►
saved me because it was this thing that I wouldn't see otherwise.
00:15:23
◼
►
Because it's hard to sometimes notice that kind of an issue.
00:15:26
◼
►
But when the profiler says, you call this method, you know, like, 98% of the execution
00:15:31
◼
►
time of your app is being called in this one method.
00:15:34
◼
►
You're like, huh?
00:15:36
◼
►
Well, that's interesting.
00:15:37
◼
►
And it's telling you it's giving you information that you just wouldn't know any other way.
00:15:42
◼
►
We are sponsored this week by Linode, fast, powerful web hosting for your projects that
00:15:47
◼
►
you can set up in just seconds with easy to understand tools that let you choose your
00:15:51
◼
►
resources and your Linux distribution, giving you the power and flexibility you need.
00:15:55
◼
►
All this starting at just $5 a month.
00:15:58
◼
►
And that includes right now Linux server with one gig of RAM in the Linode cloud.
00:16:02
◼
►
And they're always making their deals better as hardware allows.
00:16:04
◼
►
It's pretty awesome being a Linode customer.
00:16:06
◼
►
I mean, we've been Linode customers for years now, and I cannot recommend them enough.
00:16:12
◼
►
They don't, they're not paying me to say this.
00:16:13
◼
►
They're paying me to the rest of it, but this, they cannot pay me to say.
00:16:16
◼
►
I love Linode.
00:16:17
◼
►
I use Linode and I recommend Linode.
00:16:19
◼
►
Anyway, back to their script.
00:16:21
◼
►
They have over 400,000 customers, including me and David, who are all serviced by their
00:16:24
◼
►
friendly 24/7 support team.
00:16:27
◼
►
You can email them, call them, or even chat over IRC.
00:16:29
◼
►
If you need help, they're there for you.
00:16:31
◼
►
Linode has comprehensive guides also and support documentation to teach you everything you
00:16:36
◼
►
need to know for setting up and managing a Linux virtual server.
00:16:39
◼
►
And their control panel is very nicely designed with a focus on ease of use and simplicity.
00:16:44
◼
►
And believe me, I've seen a lot of web hosting panels over the years.
00:16:48
◼
►
I've never seen one as nice as Linode.
00:16:50
◼
►
It's not even close.
00:16:52
◼
►
You can deploy, boot, resize, and clone nodes in just a few clicks.
00:16:57
◼
►
They have two-factor authentication.
00:16:58
◼
►
It is the full package for your infrastructure needs.
00:17:01
◼
►
So they have awesome pricing options available.
00:17:04
◼
►
You can get a server with one gig of RAM for just five bucks a month, as I said earlier.
00:17:07
◼
►
And it scales all the way up to truly ridiculous resource levels at what I consider to be the
00:17:12
◼
►
best values in the business.
00:17:14
◼
►
For example, 16 gigs of RAM for just 60 bucks a month.
00:17:17
◼
►
Across the board, they're offering twice the amount of RAM that you get elsewhere most
00:17:21
◼
►
of the time.
00:17:22
◼
►
So as a listener of this show, if you sign up at linode.com/radar, you'll not only be
00:17:27
◼
►
supporting us, but you also get $20 towards any Linode plan.
00:17:30
◼
►
And they have a seven-day money-back guarantee, so there's nothing to lose.
00:17:33
◼
►
So check out linode.com/radar.
00:17:36
◼
►
To learn more, sign up and take advantage of that $20 credit.
00:17:39
◼
►
Or you can use promo code radar2017 at checkout.
00:17:43
◼
►
Thank you so much to Linode, my favorite web host, for sponsoring this show and all of
00:17:49
◼
►
So as we wind this up, I think the place that it seems reasonable to go is to dive into
00:17:55
◼
►
a little bit of the actual tools within instruments that we use the most.
00:18:01
◼
►
And I think for me, the one that I use, like probably 90% of my profiling, is the activity
00:18:06
◼
►
monitor, which is an instrument that essentially, its goal is-- I mean, I'm definitely oversimplifying
00:18:13
◼
►
it, but essentially it counts the number of times and the amount of time spent on each
00:18:17
◼
►
line of code in your app while the app is running.
00:18:20
◼
►
I believe you're thinking of the time profiler.
00:18:23
◼
►
Does that know what I said?
00:18:24
◼
►
You said activity monitor.
00:18:27
◼
►
Common mistake.
00:18:28
◼
►
The time profiler.
00:18:29
◼
►
You can run that one too.
00:18:30
◼
►
Does the activity monitor run at the same time profiler usually?
00:18:34
◼
►
I usually just use the built-in Xcode meters for general activity monitoring.
00:18:39
◼
►
Anyway, the time profiler is a tool that I use the most often, which counts the number
00:18:45
◼
►
of times and the duration of the time that is spent on each line of code in your app.
00:18:49
◼
►
And it's a tremendously powerful tool for just finding bottlenecks, because it will
00:18:52
◼
►
tell you-- what I usually do is you kick that off and running, and then you sit there in
00:18:58
◼
►
If it's an operation that you can do multiple times, you do it multiple times.
00:19:03
◼
►
Or if it's a long operation, you kick that off.
00:19:06
◼
►
And you can just get this great sense of where to go looking for the biggest impacts.
00:19:12
◼
►
Where are the biggest bottlenecks?
00:19:14
◼
►
And sometimes, honestly, I've even just run it-- when I'm finishing a big update, I will
00:19:18
◼
►
just run the time profiler and just use the app generally for five minutes, and then see
00:19:26
◼
►
where the biggest uses of code are.
00:19:29
◼
►
And sometimes you'll just discover things that you-- it's not necessarily performance
00:19:32
◼
►
issues, but you're like, huh, that's interesting, looking for inconsistencies or problems.
00:19:36
◼
►
But in general, it's just a very valuable tool to get that sense of where are the slow
00:19:42
◼
►
parts of my app, or where are the parts of the app where there's the biggest bottlenecks
00:19:46
◼
►
or the biggest use of code that is probably worth double-checking that it's as good as
00:19:52
◼
►
And it might not even be your code.
00:19:53
◼
►
It might be some of Apple's code.
00:19:55
◼
►
But that's still useful to know, and it still might help you avoid certain unnecessary work.
00:20:00
◼
►
And I would also say, in general, when you're running the app, use the built-in Xcode meters
00:20:07
◼
►
in all parts of development.
00:20:09
◼
►
Whenever you run the app, use those meters.
00:20:11
◼
►
Just glance at it, because it'll give you an idea of what kind of CPU usage, memory
00:20:16
◼
►
usage, energy usage-- it'll give you an idea of what's normal for your app.
00:20:21
◼
►
That way, if you make a change, you notice that.
00:20:23
◼
►
This is the same way why I love the Mac app iStat menus, because I can tell all the time
00:20:30
◼
►
what my Mac's CPU usage and stuff is so I know what's normal, so I can spot easily when
00:20:35
◼
►
something isn't normal.
00:20:36
◼
►
And so it's similar here when making your apps.
00:20:39
◼
►
Use the metering and the tools frequently, so that way you have a baseline knowledge
00:20:43
◼
►
of what's OK, so when you mess something up, you'll spot it quickly.
00:20:48
◼
►
I would also say, in instruments-- this is a little tip for me on instruments-- for some
00:20:52
◼
►
reason, it's a three-paned interface, kind of like Xcode's three panes, but for some
00:20:58
◼
►
reason the rightmost pane is off by default, and that makes it really hard to see the value
00:21:04
◼
►
of things like Time Profiler.
00:21:06
◼
►
For a long time, I could not figure this out until I saw that that pane was off and I turned
00:21:09
◼
►
it on, and it will show you the line of code that is on where all the work is happening,
00:21:14
◼
►
but it doesn't do that if you don't turn on the third pane, so please turn the third pane
00:21:19
◼
►
I would also say that there's also valuable tools in the simulator.
00:21:23
◼
►
Besides the stuff in instruments, just in the iOS simulator, you can see a lot of potential
00:21:30
◼
►
issues in Performance Bottleneck, especially in rendering, in visual rendering of things.
00:21:35
◼
►
They have modes where they will color in the interface various tint colors or overlay colors
00:21:42
◼
►
for things like alpha-blended layers, which are slower to render to screen than opaque
00:21:46
◼
►
layers, things like misaligned views, where you might have a view on a 0.3 pixel boundary
00:21:51
◼
►
instead of a 1.0 or a 0.5 pixel boundary, things like that.
00:21:56
◼
►
They're very, very helpful in the simulator, and there's a debug menu in the simulator,
00:21:59
◼
►
and it's all right there, color misaligned layers or whatever.
00:22:04
◼
►
Use these tools, and even if you don't use them every single day, I don't think anybody
00:22:08
◼
►
does, but use them maybe every major version or every couple of weeks or every couple of
00:22:14
◼
►
months, or whenever you make a big change to the interface or to the way images are
00:22:18
◼
►
handled or things like that, because frame rates of your app and the resource usage of
00:22:24
◼
►
your app can be dramatically affected by how much blending it's doing or how much off-screen
00:22:28
◼
►
rendering it's having to do.
00:22:30
◼
►
The simulator just makes it so incredibly easy to find these things, to spot these things,
00:22:35
◼
►
and then to verify that you fixed them.
00:22:38
◼
►
Use these tools.
00:22:40
◼
►
I am guilty of underusing instruments, because instruments is very complicated and can be
00:22:45
◼
►
very intimidating, and so I really only use it to a very shallow level.
00:22:50
◼
►
Like David, my most commonly used one by far is Time Profiler.
00:22:54
◼
►
There's lots of other things it can do.
00:22:57
◼
►
WBC sessions are usually pretty good about it.
00:22:59
◼
►
If you want to learn more about it, you can look through the archive of WBC videos, because
00:23:04
◼
►
almost every year they do one on instruments and advanced debugging and profiling and things
00:23:08
◼
►
So I highly recommend that you check those out, because there are tools here to do pretty
00:23:14
◼
►
remarkable things and to spot lots of possible areas for easy wins in your app.
00:23:20
◼
►
Like we mentioned earlier, you shouldn't go through and micro-optimize everything,
00:23:22
◼
►
but usually there's a couple of big things in an app that you can just make a small change
00:23:27
◼
►
here or there to have a really big impact.
00:23:30
◼
►
That's the kind of optimization that profiling is best at revealing to you, and that's what's
00:23:37
◼
►
the best use of your time to actually work on.
00:23:41
◼
►
And I think those are the kinds of things that...
00:23:43
◼
►
I mean, the number of times I've gone to a WBC session and I have some kind of performance
00:23:52
◼
►
issue, then they'll have labs where it makes sense to go and talk to somebody.
00:23:55
◼
►
The first thing they always do is they open up instruments and they go into the core animation
00:24:01
◼
►
instrument, which allows you to turn on all those cool blending color schemes for your
00:24:07
◼
►
app, but on device, so they'll run on your actual iPhone.
00:24:10
◼
►
They'll kick up the app, they'll have the time profiler running, the core animation
00:24:16
◼
►
instrument running with all of those different color keys turned on, and they just use the
00:24:20
◼
►
app and very quickly they can usually find things.
00:24:23
◼
►
You very quickly see, "Huh, why is the entire app...
00:24:26
◼
►
I can't remember what the bad color is, it's probably red."
00:24:29
◼
►
It's like if the whole app turns red when you're scrolling your table view, it's like,
00:24:33
◼
►
"Why are you doing that?
00:24:34
◼
►
Why do you have all of these semi-transparent things overlaid on each other?"
00:24:38
◼
►
You're doing all this work that you don't need to be doing.
00:24:41
◼
►
Or in the time profiler, similarly, they can find it.
00:24:45
◼
►
The core animation instrument is a great one too for just quantifying your graphical performance,
00:24:50
◼
►
which is really hard to do otherwise, I think, because it'll tell you the number of frames
00:24:54
◼
►
per second you're getting.
00:24:56
◼
►
Ideally, your goal is to be able to do operations at 60 frames a second, which is the maximum
00:25:02
◼
►
refresh rate of an iPhone.
00:25:03
◼
►
So if you aren't getting that, you can scroll your table view and see what your update rate
00:25:10
◼
►
And if it's not 60, then you're like, "Okay, now I know I have something to work with,"
00:25:13
◼
►
rather than just like, "It feels slow," or "It feels jerky."
00:25:17
◼
►
You can have these things that aren't really quite as quantifiable.
00:25:19
◼
►
And if it's not quantifiable, it's really hard to actually know if you're making progress
00:25:24
◼
►
as you're fixing things.
00:25:27
◼
►
We mentioned in passing a little while ago the Accelerate framework.
00:25:32
◼
►
This is something that a lot of developers, I don't think, know about, and most developers
00:25:36
◼
►
probably don't need it.
00:25:38
◼
►
But what this is is basically a collection of pretty low-level functions to do bulk operations
00:25:46
◼
►
on vectors, on a massive array of floating point numbers, or matrices, graphics operations,
00:25:54
◼
►
things like that.
00:25:57
◼
►
Most apps will never need this.
00:25:59
◼
►
- I've never needed it.
00:26:01
◼
►
I only needed it when I started working with sound, because a lot of the functions of working
00:26:05
◼
►
with sound are made very, very nice in Accelerate.
00:26:10
◼
►
The VDSP section of it is kind of amazing for working with sound.
00:26:13
◼
►
It's designed to do that, really.
00:26:15
◼
►
And I would say that if your app is spending a good amount of time doing math of any sort,
00:26:23
◼
►
doing any kind of math operations on very large numbers of values, so if you're having
00:26:28
◼
►
to add, subtract, multiply 500 numbers at once for some reason, look into the Accelerate
00:26:37
◼
►
It looks kind of intimidating at first.
00:26:39
◼
►
Again, there's good WBCC sessions on it.
00:26:41
◼
►
And once you figure out the crazy function naming scheme, it actually makes sense.
00:26:46
◼
►
So I would strongly recommend, if you're spending a meaningful amount of time on math, on large
00:26:52
◼
►
numbers of numbers, check out Accelerate.
00:26:55
◼
►
It's awesome.
00:26:56
◼
►
- Yeah, I've never had to dive into that myself, but that's just the nature of the apps that
00:27:00
◼
►
- Yeah, I mean, again, it's one of those optimizations where you would probably never, most apps
00:27:05
◼
►
would probably never need it, but again, it's like if you see in Time Profile, oh, this
00:27:10
◼
►
one function has to compute the square root of 400 values.
00:27:14
◼
►
That's actually taking a noticeable amount of time, because I'm calling it so often,
00:27:17
◼
►
or there's so many values, and it's a processor or whatever else.
00:27:20
◼
►
You could fix that with one line of code that might be 10 times faster.
00:27:23
◼
►
- Yeah, and I guess the last profile that's probably worth mentioning is the allocations
00:27:29
◼
►
and leaks and memory profiling tools that you have in Xcode.
00:27:33
◼
►
And I mean, these have gotten incredibly sophisticated compared to what they were years ago.
00:27:39
◼
►
I think you can now get these dynamic memory graphs showing you your retain cycles visually,
00:27:45
◼
►
and it's gotten very clever, but any time, and this is, I think, what you were mentioning
00:27:51
◼
►
earlier, the importance of checking your little build and debug graphs just within Xcode while
00:27:57
◼
►
you're running, any time I see the memory footprint of my app going up over time, especially,
00:28:06
◼
►
you'll see it jumps up and then it stabilizes and then it jumps up again.
00:28:09
◼
►
It's like, uh-oh, something, I'm doing something and then never getting rid of that memory.
00:28:14
◼
►
And the profiler is a tremendous tool for being able to show you what you're doing wrong.
00:28:19
◼
►
It's like, here you're creating lots of objects and then keeping a reference to them somewhere
00:28:26
◼
►
that you shouldn't be or something like that.
00:28:28
◼
►
Usually it's, you kind of get the sense of the different shapes of your memory structure
00:28:35
◼
►
and you get a sense for when it's a problem and when it's not.
00:28:37
◼
►
'Cause sometimes you do need to use more memory and that's fine, but if you have, you see
00:28:42
◼
►
this constantly growing or this stepwise function that just keeps, never comes back down to
00:28:48
◼
►
a stable state, it's probably time to open the allocations or the leaks tool and dig
00:28:53
◼
►
around and see what's wrong.
00:28:55
◼
►
- Yeah, and all of this also, the importance of all of this grows as the amount of time
00:29:01
◼
►
people tend to use your app goes up.
00:29:04
◼
►
It's really important for me, for a podcast player, 'cause that can be running in the
00:29:07
◼
►
background for hours, so it really has to be stable and performance and memory have
00:29:11
◼
►
to be stable.
00:29:12
◼
►
But if you're making a utility app that somebody opens up once to convert a unit and then closes
00:29:16
◼
►
and won't use again for three days, it's less important and you can spend this time on things
00:29:22
◼
►
that are better for your business rather than micro-optimizing everything.
00:29:26
◼
►
Anyway, we are out of time this week, so thank you very much for listening and we'll be back
00:29:30
◼
►
next week with our WWDC wish list, predictions, whatever it is, whatever makes sense, we'll
00:29:34
◼
►
do that next week.
00:29:35
◼
►
So thanks everybody and we'll talk to you then.
00:29:38
◼
►
[BLANK_AUDIO]