Debugging Energy Issues

Session 708 WWDC 2015

Learn how to debug energy issues in your app. See the energy debugging tools on iOS and walk through debugging common energy issues in a sample app.

ABHINAV PATHAK: Hello.

Hello, everyone.

Good morning.

Hope you are having a great WWDC so far.

I'm Abhinav Pathak, along with my colleague, Pai-Han Huang, we are going to talk about debugging energy issues.

We are going to show you the tools that we already have and the new tools we built this year specifically for iOS, using which you can find energy problems in your app and, two, fix them so that your customers really like your app.

Let's begin.

The red battery icon.

How much we all hate it when it happens to us.

Customers also hate this.

Having a good battery life is really important to having an awesome user experience.

Time and time again, it has come up that battery life is one of the most important feature that people want.

At Apple, we take great strides to ensure customers get a good battery life experience.

However, the apps the customer run have equal or usually more say in how the energy is drained from their device.

To help our customers understand which app is draining battery, which app is heavy in terms of energy, a couple of years ago on OS X side, we had an activity monitor monitor energy impact, where you can see, for each and every app, what is the instantaneous impact and what is the impact for a period of time so that users can get, hey, what happened on their device?

On iOS 8, last year we introduced battery usage UI, a customer-facing UI, where they can go and see in last 24 hours, and last 7 days, what is the proportion of energy breakdown in different application that is they have used.

An app coming at the top could have very legitimate reasons, hey, I love this app, I use it all the time.

To help customers understand what is the factor here, this year we have included a single toggle at the top of it where they can toggle and see how much usage there is, how much screen time the app got, and how much it ran in the background.

And then they can assess hey, I used it more, or hey, this app consumes a lot of energy.

This talk is about if your app is coming on the top of this list, how you can get it down while maintaining the same utilization or giving the same utility to your user.

This talk is also about people who usually come down, how they can further come down and get a good customer experience.

To give a high-level overview, we are going to quickly go through energy fundamentals and best practices.

We are going to summarize the talk we had in the morning.

We are going to show you the energy debugging workflow and the tools we have on how to debug energy.

We are going to have a demo where we will fix energy problems in a sample app that we have built specifically for this talk and show you how easy it is to go ahead and fix energy problems, and then we will close this talk.

Very simple.

Everybody knows this.

Energy 101.

Energy is equal to power times time.

What we are seeing here is a graph, X-axis is time, Y-axis is power.

It's a waveform of an application usage.

What happened?

Let's say a user launches an app, a bunch of activities, backgrounded the app, and the app got suspended.

The single most important point here is the entire area under the graph is the energy consumption of this particular app.

Energy is dictated by power and time, and to illustrate the point further, if we take two rectangles here, they are differing in terms of how much power they consume, differing in terms of how much time they consume, but they are equal energy wise.

Second concept, there's something called fixed cost, there's something called dynamic cost.

A lot of hardware components we have in our systems, if you have to use them, we have to first bring them into a state where they can start serving your requests.

These states are very high energy consumption in terms of compared to the sleep states.

Once they are brought up, they do the work that you asked it to do, and then we keep them in that state in anticipation of, you know, further work is going to come.

Once we see there's no work coming up, we quiet them down, let them go to sleep.

Fixed cost can be very, very expensive, and we will see throughout this talk how we will go after this fixed cost whenever it starts impacting your application.

When it comes down to reducing energy usage, there are very simple three rules that you need to follow.

First rule, do it never.

Does a customer really need that work to be done?

If you don't do it, fixed cost, dynamic cost, energy, power time all the things we have talked is a grand total of zero.

Awesome. If you need to do it, do it less.

What is the least amount of work to satisfy the customer's request?

Next thing, do it at a better time.

A customer is out in the wild, taking photographs.

Do I need to upload it to the server right now?

Have some tolerance, maybe when a user is connected to a power outlet.

Third, do it efficiently.

What is the best efficient algorithm or the best thing I can do to serve this request?

We will see how these things come back again and again in different parts of the talk.

To jump in the energy debugging workflow and tools we have, let's look at how does an energy debugging workflow look like?

It's very similar to normal software engineering practices.

What you do: you write code and build.

You run it on a very simple debugger which tries to show you what's the high-level problems in your code.

A lot of problems you can easily identify, fix, and you run it again.

Some of the problems, though, are hard, so you go ahead and say let me get a focused debugger, you know?

Hey, I have a memory issue.

Let me get a focused tool only on memory that can pinpoint in my app exact line of the code, where is the problem?

And once you are done with all this, you ship it to your customers and your customers use it.

On OS X side, we have Xcode, where we write and build your application.

As part of general debugger, within Xcode, there are energy debugging tools, which we are going to talk about.

These show primarily hints of how your app is behaving.

As part of instruments, we have focus tools.

Once you have identified, hey, this part of the system is a problem, let me go ahead and fix this.

And customers, as we talked about, they have energy impact, and they can go ahead and look at it.

Before we jump into the tools, let's look at energy debugging priorities on OS X.

The reason is the tools are very focused on energy debugging priority because they point you to exactly the location where you need to fix your problem.

Priorities on OS X are the CPU and GPU.

They have a very, very high fixed cost.

To bring it to a state where they can serve you or your request in the idle state, it is ten times the power consumption of as compared to when they are in the sleep state.

Once they are in the idle state, if you use CPU for 1 percent, that is 10 percent more on top of idle power consumption.

And from then on, it goes exponential.

10 percent CPU, two times idle; 100 percent CPU, 100 times idle.

Very simple rule here.

Do not wake the CPU up if you do not need to.

Let the giant bear sleep.

Don't poke it.

The tool we have in Xcode, I call it energy gauges, it prints you an energy report that looks something like this.

How do you get there?

You click once you are running your application, click on the debug analysis part.

Once you click there, you see a bunch of gauges.

Click on the energy impact gauge.

You will see the report.

What do you see in the report?

So primarily, you'll see if you are being a bad citizen of OS X, basically, you have if you are using high CPU.

If you are preventing your your application is in background, user is not looking at it, system will try to put you in App Nap, which is a kind of background suspend, and you are preventing system to do that.

You are not actively serving any request, but you are burning a lot of energy.

Idle prevention.

You are not letting the CPU to go to into idle state.

If it cannot go into idle, it cannot go into sleep state.

Once gone into sleep state, the CPU wake overhead says hey, you are responsible to bring this guy up.

Once you have figured out high level where the problem comes in, what you can do is just underneath the report, you have first of all the description of the things we just talked about, but you have these buttons which you can jump into instruments, and these tools are specifically designed for each and every area, and they can, you know, help you pinpoint, hey, which line of code is actually causing high CPU utilization?

Which line of code is causing the wake overhead?

You can go ahead and debug your app.

When it comes to principles of reducing energy on OS X, we come back to our three simple rules: do it never/do it less.

You want to coalesce all the timers.

You don't want to wake up the system again and again.

Minimize CPU wakes.

Do it at a better time.

Use the background activity scheduler APIs, where you can specify a lot of parameters and let the system choose the right time for you.

Do it efficiently, set the right work priorities, QoS work priorities, on your work queues.

Program a computer algorithm.

Moving on to iOS, CPU is still a dominant energy consumption.

But given the fact that these devices are different than OS X devices, a few other things come into play.

First of all, two of the peripheries, location and networking, can be equally costly as CPU if not more in some use cases.

Next, when an app runs in the background, your app consumes all these three hardware and it consumes a lot of energy.

You don't have the display energy, but still all the rest of components are huge in terms of energy consumption.

So let's look at each of these one by one.

Location energy usually acts like this.

It's not very high in power.

The power is data mined by which API you have called and what is the precision with which you are calling it.

The time component is big, and that is how the energy becomes really huge.

When it comes to fixing location issues, again, same principles: do it never, do continuous location only if you actually need it, it has actually been requested by the user.

And please stop once you are done with it.

Once you get the location, once your request is satisfied, just stop it.

Next, do it efficiently.

What is the best accuracy you need?

Do you need to know exactly within three feet where the user is standing on earth or the city is good enough in predicting weather for it?

What are you trying to do?

We have went ahead in the location site and we said hey, there are a set of use cases where people want to have and for each of the use cases, we have designed APIs that help serve better the developers, you.

Try to read on these APIs what actually you want and we'll do the energy management really nice for you.

When it comes to networking, very similar principles: do it never.

Cut down transfers.

Can you cache, can you compress?

Do you need the highest quality media on the smallest form factor?

Can you do it at a better time?

Can you consider tolerance?

When is it needed?

Can you mark it as a discretionary?

The moment you mark it discretionary, the system takes over.

You can specify, hey, in the next 6 hours or the next 12 hours, I need this to be uploaded or downloaded, and the system will figure out what's the best time, will do the activity for you, and once it's done, it will tell you hey, this activity is done.

Do it more efficiently.

Coalesce transfers.

Let's take a look at an example.

What do we mean by this?

Let's say you have a requirement where you have to sync data to a server, user is using your app and have to periodically sync as it's being generated on the device.

Very simple solution.

As the data is getting generated on the device, just keep pushing it.

What happens here?

For every push, you bring the data up, you send your 2 bytes, 10 bytes, 100 bytes, radio stays on for a long time, it goes to sleep.

Next push, the same is repeated.

The fixed cost is very high in that point.

How do you fix it?

Very simple.

Coalesce all the transfers.

Let the user interact with the device, build a state, and once in a while send the state to the cloud so that you pay the cost only once, the cost of fixed price.

Moving to background, first thing, background when your app is running at the background, it is draining energy from the user.

Please don't do anything in background if you don't need to do it.

If you need to do it, call your task completion handler as quick as possible, and this task completion handler is an indication to the system saying, hey, I am done.

Please suspend me.

Please let the device go to sleep.

Do it efficiently.

There are a lot of background APIs that you can, you know, give your system a hand, you know, please do the work for me as you find the best time and the best, you know, period energy wise and the system will do it for you.

To go back to the energy debugging workflow on iOS, what we have so far, we have Xcode, where you write and build your code.

Customers have battery usage UI where they can see how your app is performing energy wise.

So far, we have had for a few years a tool called Energy Diagnostics in Instruments that can give you a first-cut idea of how your app is behaving.

Let's take a look at this tool.

How do you enable it?

You go to settings, developer, go to the logging pane.

You turn on the energy toggle here and then you say, hey, start recording.

Once you have started recording, use your app as your customer will.

Live on it for a few hours, 12 hours, 24 hours, a few days or so.

And once you are done, just click the button, stop recording.

After this, connect your device to a Mac and go to the instrument, select Energy Diagnostics, and say hey, please import the log data that you have.

Once you do that, you will get a picture, which is something like this.

You'll see Wi-Fi, Bluetooth, and you'll see how long they were on, when they were on, when they were off, and so on.

You will see how many packets were sent out of each interface, what was the CPU activity.

At the top, you will see an energy usage level, which with is a number out of 20.

If you are 20 out of 20, believe me, it's a problem.

Very, very high energy consumption.

You want to stay close to 1.

This tool is good if you want to do long experiments.

But what it doesn't do is it doesn't tell you why did the hardware come up?

Did you request it?

Where did you request it?

It doesn't pinpoint, it's not fine-grain to go to your code.

To fix this problem, this year we are introducing energy gauges on iOS and instruments, a few instruments too, which you can use to pinpoint in your code where the problem is coming from.

To talk about all of these, let's move to demo.

I call Pai-Han Huang, my colleague, to talk all about it.

[ Applause ]

PAI-HAN HUANG: So, in a demo, I will walk you through the major features of the new energy bugging tools, demo the app, and show you how we can use the new tools to identify and improve the energy efficiency of your app.

So as a developer, I like these new tools because they are easy, they are effective, so at the end of the demo, I hope you will join me in including these new tools as part of your project cycle.

There are two major components in the demo.

One is the new tool set; the other one is the demo app.

So let me start from introducing you to the new tool set.

On the screen, what we are seeing is the screenshot of iOS energy gauge, which is the entry point to all the other new energy debugging tools for iOS this year.

So where is it?

It is actually inside debug navigator of Xcode, which you can find over here.

After you launch your apps through Xcode, you will be populated automatically for you over here.

And when you click it, it will bring you to the right-hand side of the screen.

And the iOS energy gauge can visualize the energy impact of your code, can visualize the energy impact of your code, both instantaneously and in the average instance.

So the first is the instantaneous energy impact of your code, can be found in the field meter, which is over here.

There are three different zones in this graph.

In the speedometer, the lowest one, when the needle points to a green zone, it means the energy impact of your code is actually reasonable.

Congratulations.

You are a good citizen of the iOS ecosystem.

But still, we suggest you to take a look at these new tools to see how you can make your customers happier.

When the needle moves up, it enters the yellow zone.

In the yellow zone, the energy impact of your code is high, so it's likely that if you don't deal with it carefully, your app will show up high in the battery usage UI.

So please use the new energy debugging tools to see how you can improve the energy efficiency of your code.

But if the needle keeps moving up, you enter the red zone.

Red zone indicates that the energy impact of your code is very high.

It means that even with the slight usage of your app, users will significantly will experience significant battery drop on your device.

So please use the new tools!

Please [laughter]!

Sorry, I apologize.

That's the evil in me protesting to the people who don't take battery life seriously.

I promise you, I am a very nice guy, so come to chat with me, you know, in the last session this afternoon.

Okay? Okay.

But speedometer can give you an instantaneous energy impact information overall of your app.

If you want to see more breakdown, you should see here, energy impact session.

So this graph will be refreshed once every second.

If your app introduces any workload to CPU, location, or networking, you will see a block showing up on the top three rows in the corresponding time slots.

And, as an earlier talk it was mentioned, your app can consume significant power, not just on the foreground, but on the background as well.

So based on this observation, we have the fourth rule, background.

When your app stays in the background and doesn't go away, you will see the moving blocks showing up on the fourth row.

On top of the graph, you will see a series of color bars.

And they look like this.

Two colors.

Red color means that that is overhead, energy used to bring up the system resources like the radio module to perform work for your app, and it also maps to an earlier talk, the fixed cost of the hardware.

For the blue one, it represents the energy which has been used to service the workload introduced by your app.

Besides instantaneous information, we also provide average information.

For example, like this one, the average overhead in percentile, and this guy shows you the average energy impact.

On the bottom, you will see a series of explanations about legend, CPU, location, networking, and background.

And it also provides some tips about how you can optimize them.

But please remember that iOS energy gauge is designed to show you quick the high-level understanding about your energy impact of your code.

So if you want more detailed information, more breakdown, then check this button.

This button, after you click it, it will trampoline you to the corresponding instrument, to give you breakdown energy information for your app.

This is the iOS energy gauge.

Let me next briefly introduce you to instruments.

Instruments, as many of you already use them: it looks very similar.

For example, the one you see on the screen is the location instrument.

How do we start?

We start from toggle this button, record it, and stop it.

After you record it, you will see the system activity like this.

And you will see some reasons about why you see this kind of activity.

For example, here you will see the location service that is trying to request for location.

And if you want more information, more detail, go here, extended detail.

Then you will bring up this guy, which is the code stack.

So this is the introduction to the instruments.

Next, let me briefly talk about the demo app.

On the screen, you will see a screenshot of our demo app, which we call Energy Buddy.

So, as an iOS power software engineer, I am eager to know whether I can improve my energy efficiency everywhere, not just on my phone, but in my daily life as well.

Energy Buddy can suit my needs pretty well.

I can use it to take a picture, and it will extract the usage information from the picture I take for energy meter, for example.

Then it will query the location of my device, get the weather information based on my location, correlate the weather information with my usage, showing up on the screen.

The structure is like this.

There is a centralized data manager, and if I import a photo from there, it will try to get a reading from it.

And based on the location, it will try to hit a networking service to get the weather information based on my location.

And then data manager will correlate this information, showing up as a curve on the screen.

So next, let's try to give it a shot and see how the new tools can help us identify and improve energy efficiency of Energy Buddy.

So on the left-hand side of the screen, you will see Xcode.

Right-hand side is the screenshot of my testing device.

So let's start from launching Energy Buddy by opening the project files.

So what it's currently doing is, after I hit the round button, it will try to build a binary file and transport it into the device and launch it for me.

So once it's launched, we will see this.

It's here.

So let's go to debug navigator over here.

Energy impact over here...oh, there we go.

The first thing we want to see is whether there's any moving block over here because currently I don't do anything with the UI.

So it seems like it's pretty clear of those kind of moving blocks.

This is a good sign because when the app is idle, not too much should happen.

So this is good.

So let me try to import a photo by clicking the "Import Photo" button, select a photo from my gallery.

It will try to extract information, and I will set the reading.

Okay. Oh, okay, I see lots of activity coming up, including CPU, networking, and location.

But among them, I immediately notice one thing.

That is location is always on.

Huh. It doesn't make sense.

Because Energy Buddy is not the kind of app where you're trying to track your exercise, like running, right?

So why do I need to keep monitoring the location of my device?

It doesn't make sense.

So let's take a look to see what the location instrument can tell us and how we can identify the line of code to improve the situation.

So I will next click the location instrument, and I say restart.

Then you are trying to bring up the instrument, launch an app for me.

Okay. So let me redo import photo again.

Set the reading.

There you go.

Okay. So on the screen, you will see this.

This is the location activity.

It keeps going on and on without stopping.

But where is it?

Where do we introduce this?

Take a look at this.

Go to extended detail and see.

Oh, okay, it's this part request location.

That's how we request for location service.

So let me stop this, go back to Xcode, and search for request location.

Okay. It's already here.

So what is the request looking to do?

First of all, you are trying to set up the confirm view controller.

In this piece of code, you are trying to set up, create a location manager.

Then you are will call start updating location.

So after this line, what will happen is location service will periodically push the location update to us through a callback, which is over here.

So in the callback, let's take a look what does it do?

First thing is you are trying to see, okay, if there is anything updated here, if it's zero, that's invalid, so we just ignore it, return.

Then we will store it, we say, whether location is horizontal accuracy is actually up to our standard, up to our expectation.

If not, we return.

If so, then we are trying to handle location inside the confirm view controller.

And then you return.

And this callback routine will be repeated again and again and again, every time when we receive a callback from the location service.

Push doesn't look nice.

So what we should do?

The thing we should do is we should stop it when we have a value.

Like this line.

So we say when we get a value updating location update, we should stop it.

So let's take a look and launch it again and see what the energy gauge can tell us.

What I expect to see is after I receive the first time a successful location update, I should stop the location, and location service should not be on and on forever.

Let's wait for it to be launched.

Hmmm.

Okay. Go to the iOS energy gauge.

So let me try to import a photo again.

Select a photo from a gallery.

Set a reading.

Okay. Location, one second, two seconds, three seconds, four seconds, and it's gone.

This is an immediate improvement after just one line of code.

You can think about the scenario over here.

So if the app has been turned on for a long time, imagine how much energy you can save just by doing one line of code, which is amazing.

So let's give more try on Energy Buddy to see what will happen next time when we import another one.

Okay. I import another one.

And I see the location has been up for four seconds, but this time, I notice the big thing here is networking service.

This doesn't look nice.

The reason Energy Buddy wants to hit the networking service because it wants to get the weather information.

But I just did a query like two minutes ago, so the weather shouldn't change that much during the past two minutes, right?

Even for an hour, I would say, the weather may not change that much.

So what is the purpose if we want to redo the networking although we already have earlier request that is two minutes ago?

So let's go directly to the code and see how we can fix this.

So the place where we actually request for location is inside the weather file.

And there's a function called Fetch if Missing.

So let's take a look what does it do.

In the first part, we were trying to set some parameters like date, URL based on the query URL for based on the device location and the current date and whether I have done this kind of query within today or not.

And you will store the source ID for the location coordinate, and you will set a constant that is exactly the number of seconds within the hour.

So the first if we are try to go do is we say if we have done the query for today and the data manager already has the weather fetched since the last time we queried, that is like three minutes ago, then we say we just return.

Next is if we don't do it today and data manager already has the weather fetched, then we also return.

If none of these two situations have been satisfied, then we will try to set up a task based on the location, based on the date, and we will try to download it over here.

So what's going wrong there?

The reason it's doing wrong is actually inside this gauge over here.

So I will add in another situation like this, to say if I have done this today and the previous fetch is actually within an hour, then I will not do it again.

So let's launch it again and see how we can see the improvement inside energy gauge.

So what we expect to see is this.

Because we've already done our fetch, like five minutes ago, we should not see any networking every time when we are trying to import a photo again within the next hour.

Let's take a look whether energy gauge will agree with my theory here.

Okay. It's up.

So I am trying to import a photo, select a picture from a gallery.

Set the reading.

So I see the location.

It's been for four seconds like before.

But magically, all the networking is gone.

This is exactly what we expect.

So this is another good way for the energy efficiency of our Energy Buddy.

So besides the foreground, Energy Buddy can also consume significant battery even on the background.

So let's take a look at what the energy gauge can tell us when Energy Buddy is actually on the background.

We put Energy Buddy in the background by hitting the Home button.

So what we see is over here.

We see lots of, lots of background activities of Energy Buddy.

And that means that whenever Energy Buddy is on the background, the device cannot go to sleep, which will consume significant power because there is a fixed cost to keep the device awake.

This doesn't make sense because Energy Buddy doesn't need to do anything on the background.

So what's going wrong here?

Let us go to the callback when we actually go to the background.

Here is the code.

What does it do?

It does the following.

You are trying to set out background task identifier, and they will do one thing, archive to data manager, which will store all the changes to data manager, and they will say wait for input, and we will code in background task when it is actually done.

Does it make sense?

No. Why not?

Because our app is always on in the background, right?

So how come users can actually interact with Energy Buddies through the UI?

So there has been no input at all, and we are waiting for it.

This doesn't look nice.

So what we should do is we shouldn't wait for it.

Instead, we should do something like this.

After we archive the data to data manager, we will call in background task immediately and invalidate the background task identifier.

Again, let's launch Energy Buddy again and see what the energy gauge can tell us.

What we expect is this.

After we just saw all the changes in data manager, it will directly just quit itself and release the control to the assistant.

It will not stay in the background all the time like before.

Okay. Go to energy gauge.

Put the Energy Buddy in the background.

So we are in the background one second, two seconds, and it's gone.

So this is another big win.

So keep in mind that, with very simple fix like I just did on the stage, you can see significant improvements, and Abhinav will introduce you because we carry on a couple hours or even a day with significant battery improvement.

So this concludes my demo, and let me hand it back to Abhinav.

[ Applause ]

ABHINAV PATHAK: Thank you, Pai-Han.

That was a great demo.

Back on the slides.

So let's conclude this talk.

Let's see what happened during this demo, a quick summary.

We started with the Energy Buddy, inefficient code.

We ran it as the user would use it and let's see what happened.

Everything is lighted here.

Bad, bad, really bad, the impact is very high, and your app will come very high in the battery UI.

How did we fix it?

We went to location, and we said hey, location has started.

Then stop.

One line of change, boom, location stops.

Let's see before and after how does it look?

If you focus on location timeline, we see location is on all the time.

Afterwards, location is on only when it is actually required whenever a photo is imported.

Let's go to networking.

What we did was we were getting weather information all the time whenever a new photo was imported, and that is not good.

We wanted to cut down the transfer, and we put a very simple block.

Hey, if this is recently called, don't do that.

We don't need the new information again.

What impact did that have on the energy gauge?

Two photos, again, before and after.

And if you focus on the networking part, networking is highlighted for a long time.

The red bars on the top are highlighted all the time, saying networking hardware is up.

It's a huge amount of time during the usage of the app.

At the bottom, we just do networking once, boom, after that, it's recently called, it won't be done again.

What about the background session?

When we went to background, we stored our state into database and said hey, let's wait for the user input.

Not a good place to do.

User is in the going to do any input at that point.

Very simple fix.

We say don't wait for user input.

Just call the task completion handler.

Tell the system hey, I am done, suspend me, let the system go to sleep.

How does energy gauge look like before and after?

Let's focus on the background line.

Background is up all the time in the top.

At the bottom, the moment we have done the archiving to the database, the background task is done.

We are suspended.

Awesome. Let's take a look at overall code before and after.

Before, you see everything lighted up.

If this is happening to your app, this is a problem.

After is we are doing the same utility, we are giving the same utility to the user, same experience, but very, very little amount of load on the hardware in terms of energy.

Probably the most important slide, as we promised you in the starting, if your app is coming at the top, please do the changes and you will see your app actually going at the bottom of the UI.

What we did, we took two iPhone 6 fresh installs, on one of them installed inefficient code, on the second installed the code with all the fixes, took both of them exact same amount of work, while running other applications as well, same amount of load in terms of all application, in terms of Energy Buddy and other applications.

What we found: the fixed code consumed 50 percent less energy, including display energy, which is exactly the same in both the apps.

Battery UI you see right on the top, 28 percent.

And with optimized code, it goes way down.

User is getting exactly the same thing.

To summarize this talk, battery life is really, really important to have a good customer experience.

Design your app with three things in mind do it never/do it less, do it more efficiently, do it at a better time.

Be a very considerate background application.

Please try out the new debug tools.

We have our labs.

I will give details right now.

Check out the new Energy Guide we have.

It contains all the information we talked about in this talk and more.

Bring your apps to the Power Lab.

Some more information about where you can find the Energy Guides.

Technical support for this talk.

Finally, the related sessions for these talks, which are talking about a few concepts we talked, but in more detail.

Thank you, everyone, for coming.

[ Applause ]

Apple, Inc. AAPL
1 Infinite Loop Cupertino CA 95014 US