[ Music ]
Hello, I'm Jonathan Davis, Web Technologies Evangelist for the Safari and WebKit Teams.
Welcome to "Understanding CPU Usage with Web Inspector."
We all know that battery life is important to users, and you probably instinctively know the web browser is one of the most-used apps on our devices.
But beyond that, web content is also incorporated into many popular iOS and macOS apps.
That means web content significantly affects battery life for users, so making it power-efficient has a big impact.
Safari and WebKit already provide features to automatically save power for users when possible, such as throttling timers when a webpage is in the background.
And with support for content blocker extensions, users can automatically block loading unwanted content that's often just junk slowing down their browser, or worse, tracking them.
But even with the built-in power-saving features in Safari, there's a lot left in the hands of web developers, so it's an opportunity for all of us to improve performance and build a power-efficient web for users.
The good news is that everything you know about good performance practices on the web also apply as best practices for saving power.
Whether you're experienced with all of the best practices for performance on the web, or just starting out, I'm going to show you a powerful new tool in Web Inspector that's going to give you super powers for finding where performance can be improved to save battery life.
It's called the CPU Usage Timeline, and it's new in Web Inspector in Safari 13 for macOS.
It provides a window into power use that makes it easy to see the impact of behaviors that contribute to high CPU usage.
Today, I'm going to show you how to work with the new CPU Usage Timeline, discover power issues through CPU Usage, and then I'll briefly go over some strategies for improving power savings in your web-based projects.
Now, before you can use the new timeline, you'll need to enable the Develop menu to access Web Inspector.
Just load up Safari Preferences, and click on Advanced, and click to enable to Show Develop menu in menu bar option.
Now, just load up a webpage, and open Web Inspector from the Develop menu, or use the keyboard shortcut Command-Option-I.
I'm going to use the new CPU Usage Timeline to look for where we can improve power on webkit.org.
The homepage is pretty simple, but it should be interesting, because it still has some dynamic things happening, like this subtle logo animation in the background.
With Web Inspector open, click over to the Timelines tab.
In the upper left is a list of different timelines.
There's a bunch of other timelines you can use, but the defaults will work great to look for ways to improve CPU usage.
To start a recording, you can click the red Record button, or press the Space bar, but I'm going to click the Reload button, which will automatically start a recording and capture page load, too.
When looking at CPU usage, it's important to remember you'll want to record at least 15 seconds in order to get useful measurements.
So I'll let this recording go a bit beyond that to capture enough data.
Now I'll scroll over the timeline to zoom out a bit so I can see everything.
Clicking on the CPU timeline, you can see details about CPU usage of the page.
At a glance, I can tell the page does a pretty good job of keeping energy use low.
The quick load time helps a lot, and when the page becomes idle, the timeline shows the page is basically doing nothing.
This is great, because it means users can stay on the page all day, and the CPU drops to a very low power state, with negligible battery drain caused by the web content.
The main thread is where a lot of interesting work happens for web content.
Based on this, we can see that most of the time working was spent on painting.
In the middle of the indicator is the time it took for the main thread to complete its work.
The entire recording was about 20 seconds, but the main thread only took about 100 milliseconds to complete its work.
Below the main thread chart is a detailed breakdown of the CPU usage across all of the threads involved in doing work for the web content.
I can take a closer look at this by clicking and dragging in the timeline to select just the time range where the work is being done.
And just under the CPU usage graph, in this strip is the main thread indicator, which shows categories of work that were happening on the main thread at different points in time.
In this area of growing activity, there were some layout events in red, followed by significant painting work, just like in the chart above, but showing when it happened.
The energy impact gauge really brings it all together, though.
It provides a score based on the total average usage across all CPU cores for the selected time range.
The energy impact gauge is interactive, and as a total average, will change depending on the time range selected.
For the page load period, the gauge shows medium energy impact, but loading is expensive in terms of power, so that's expected.
At least this stayed out of the high range.
That would've indicated a problem but double-clicking the timeline area to select the entire recording shows the overall average CPU is low.
I can click and drag the timeline to select a slice of time out of the recording and watch the average change.
Now, when I click to grab the selection, and slide it to a period where the page goes idle, the energy impact drops to low.
That's really great.
When the page is idle, we don't want to be costing the user lots of power for content they're not actively using.
The CPU use was in the low range while idle, even with the rotating logo animation happening in the background.
That's because it's using a simple CSS animation that makes it really cheap to animate, but it still gives the page a nice visual impact.
Webkit.org is doing great so far, but when you're looking for power issues, looking at loading and idle are good starts.
To cover all of the bases, we need to capture some interactivity, too.
The WebKit Feature Status page is a great way to stay up to date on WebKit support for your favorite web features.
It allows you to filter and search, and that's perfect for capturing interaction.
I'm going to record a timeline and interact with the page in some ways.
I'll just scroll down to the bottom, and then all the way back up to the top, and then I'll do a quick search, and click on some things here and there.
And again, we should at least capture 15 seconds.
Since we're on a new page, we should capture some period of idle, too.
I'm going to let this continue recording to get enough idle time captured.
Okay, that looks pretty good.
Now I'm going to select the entire recording and scroll to zoom out of the timeline a bit so we can see everything and click to look at the CPU usage details.
Let's start digging into these areas, starting with loading.
The page managed to stay out of the high range during the quick load time, so we're okay there.
Now let's look at this range of interactivity.
We definitely want to avoid doing any extra CPU work while scrolling, since it's very expensive to scroll.
Let's see if we need to be doing that work or not.
The Statistics and Sources sections tell the story.
Now, I know that reducing timers and staying off of scrolling is better for performance, but we need to look at the code to know if it's necessary or can be improved.
Ah, OK, it looks like the request animation frame timer is calling updateImages, which iterates over all of the images, and checks if they are in view, and if so, it loads them.
It's a pretty basic, lazy-loaded images pattern, but this dimmed-out code in the debugger tells us inView and loadImage are never called.
Even though we scrolled the entire page to the bottom, and back up to the top, it makes sense, though, because there's basically no images on the page.
So the lazy-loading image code shouldn't be firing at all on this page.
Let's switch back to the code.
The images and the event handlers are set up here.
So looking at the code, it's just always setting up the event handlers for scroll and resize all of the time.
To keep that from happening, we just need to add a conditional guard.
There, let's try that.
OK, so let's capture a timeline with the fix in place.
I'll click back over to the Timelines tab, start a new recording, and I'll do some quick scrolling.
The energy impact has been reduced, and all of the main thread work is paints for scrolling, but we need to make sure that the pages that should be using lazy-loaded images are still working.
Again, with the fix in place, I'll record a new timeline on a page with a MotionMark logo image at the bottom that should use the lazy loader.
Perfect. The MotionMark image loaded in.
I'm going to scroll to get some CPU measurements of the new behavior and click the CPU Timelines to see where we're at.
So we've reduced the timer and events to just the pages where it's necessary.
That's great, but there's still a lot of entries into Script when scrolling on pages with a lazy-loaded image.
There's an API available in Safari that we can use to take this solution a step further.
We can replace the request animation frame implementation to use Intersection Observer instead.
Intersection Observer can tell when an element comes into view, so you can limit your work to just when it's visible.
And as soon as it goes out of view, you can stop the work to get back to a low CPU power state and save power.
So with the Intersection Observer implementation, let's record another timeline, and do some scrolling to see how this solution performs.
So in the end, we went from 16.3% down to 9-1/2% average CPU usage with the Intersection Observer solution.
Every little bit helps, and that's a really nice improvement.
So there are lots of ways to save power in web content.
Use the CPU usage timeline to investigate web content for ways to improve during interactivity and when the page is idle.
Remember that reducing CPU usage saves energy and reduces battery drain for users.
CSS animations and transitions can provide dynamic visuals without the power cost and try to avoid doing work while scrolling.
Using the Intersection Observer API instead.
Users want an engaging, dynamic experience with web content, but the best version of those experiences use the least amount of CPU possible.
There are a lot more power-saving tips for web development on the WebKit Blog.
Check out the links in the resources section associated with this video.
We hope you'll try using these tools on your web content, and use the advice in this video as some starting places for your investigations on how to make your web content power efficient, and join us in helping the web become more powerful by using less power.