Journey to Save Energy

Alaa AL-Zaibak
Volt Lines
Published in
6 min readDec 28, 2018

Brief Introduction

In Volt Lines, one of the most important apps we have is our driver app. It’s mostly a navigation app that helps our drivers in their trips. Basic functionalities include viewing the route they should follow, knowing stop locations, and the passengers that need to be picked up/dropped off there.

The map (Google Maps is used) in this application is the core item that appears in most use cases and most pages, and we lay out the needed info in views and buttons on top of it.

Also, we are using native location services (Core Location / CLLocationManager) to collect current location and bus movement to be monitored by the operation control department and to inform passengers about their driver’s location and estimated time to pick them up.

Moreover, we use Zendrive’s SDK to get the bus speed and driver behaviors that help us improve the safety and efficiency of our fleets.

When it Started

Our story started when we received feedback from drivers that the app is draining the phone’s battery and making it overheat (my first impression and response was “apps on iOS doesn’t do that, the drivers that were complaining must be using android phones”, but the answer was -believe it or not- “no it’s iPhone”).

So we (the tech team) started a brainstorming session to figure out what could be the cause of this issue.

We listed parts of the app that might cause energy consumption and phone overheating, to start eliminating and fixing them one by one. We downsized the suspected items to the following:

Google Maps appears in most use cases and we add markers (stops) and poly lines (routes) on it.

Core Location is used to send location information continuously to our servers.

Zendrive SDK is used to get data for speed and driver behaviors.

Getting Our Hands Dirty

We started experimenting and researching the possible cause of energy consumption in the previously mentioned parts, but here before I explain what we did, I actually have to confess that I didn’t know (at that time) that Xcode has a built-in utility “Energy impact gauge” that calculates energy consumption of the app, so I used the Xcode developer tool “Instruments”, which doesn’t contain any helpful (numeric) data that can be used to know where to look and which part of the code should be improved.

Instruments debug trace

With help of the “instruments”, this is a summary of what we suspected, how it possibly consumed energy, and what we did to gain energy saving as much as we can:

Location services: The obvious (most concurrent) cause of energy consumption, although, it’s inevitable part of the app and we can’t compromise a lot on it, but we tried to improve its impact on energy anyway by decreasing the accuracy form “best for navigation” to “nearest ten meters” and adding a distance filter to 30 meters. That didn’t help a lot, but it was the best we could do.

Zendrive SDK: It seems like a good suspect regarding battery drain accusations. It is monitoring the bus speed, collisions, aggressive driving, and distracted driving… How can you possibly do all of this without triggering and using a lot of hardware on the device? So we pointed fingers onto it and started researching and testing. Unfortunately, we found it innocent as much as it seems a suspect, at least in our app. How did we know? This was easy; We tried to disable/remove the whole SDK from the app and gained nothing as energy impact when we did it.

The map: We suspected energy consumption to be from loading the map tiles continuously from the internet, so we tried to cache the map tiles. We gained an improvement of roughly 4% of the energy impact doing this.

before caching maps
after maps caching

The Real Deal

After all the research and improvements, we couldn’t fix our issue but here’s what we missed: While I was asking myself the question, I discovered the existence of “Energy impact gauge” in Xcode (yes, it was late, but better late than never), so I checked the app with it to take a look, this how it looked after minutes of running:

I played a little with the app while monitoring energy report on Xcode. I found that our app has sometimes “high” and sometimes a “very high” energy impact, and that difference is about 40% of energy impact which caused by that lovely green item (check the previous picture), GPU. Wait, hold on a second… What? GPU? What does the app use the GPU for? We neither have any part of our own code that uses metal, nor have anything on the screen that needs a GPU processing.

I started investigating this usage and differentiating between these use cases. Well, again the differences were summarized in:

Enabling Zendrive.

Getting more accurate location updates from CLLocationManager.

Adding a polyline and some extra markers to the map.

But we already excluded Zendrive and location manager won’t use GPU, so Google Maps went back to the spotlight.

While I’m searching and researching regarding this abnormal usage, I saw this closed issue “Custom marker in google map causes high CPU load on iOS” in “react-community/react-native-maps“ on GitHub.

But this bug is on react community; we are using Google Maps SDK for iOS so it’s mostly irrelevant. Besides, it is a closed issue. But anyway, it won’t hurt to check our code and custom markers.

our custom marker

We were adding markers, as stops, to the map and a UIView -with rounded corners to form a circle- to each one of them, and that UIView contained a UILabel with a number to indicate the stop number. I removed the code that adds markers to the map and rechecked energy. Guess what, GPU usage is gone!

I checked this further and re-added one marker only, to make sure it is not the number of markers on the map causes the abnormal usage, this made GPU usage come back. I replaced that view with a plain UIView without any design and subviews to make sure the issue is not the complexity of the view, but the usage was still there. So custom marker with a view in it can’t be used in the app, so I did one more test, I re-added the markers with images (UIImage) instead of views this time. And that’s it, GPU wasn’t being used!

The app at the end of our journey

So I suggested a quick solution for this issue, which is making all the circles we need in the app as images and use them instead of adding UIView to the map markers, and that’s what we did, and saved with this tweak about 40% of the app consumed energy.

At the end of this journey, I don’t have any “smart” conclusion that come to my mind other than that Google Maps thinks of itself as “Assassin’s Creed” game when you add a marker with UIView to it. :)

P.S. I found another suggestion while I was writing this blog for solving this issue to set the property tracksViewChanges to false, but never checked if it works “https://stackoverflow.com/a/37578838/4434352”.

The Volt Lines team will be growing from 12 people to nearly 26 by the end of January 2019. Here are some of the top positions we’re hiring for: HR Manager, Finance Manager, Product Manager, Corporate Sales Managers, Operation Managers, Data Scientists, and Backend Developers. Please visit our careers page for more details.

--

--