mapbox-gl-native
mapbox-gl-native copied to clipboard
iOS user tracking mode = follow leads to excessive CPU usage
Platform: iOS Mapbox SDK version: 3.4.0-beta.4
Steps to trigger behavior
- Create a map
- Call
mapView.setUserTrackingMode(.follow, animated: true)
- If simulating, feed in a GPX trace. If outside, walk around.
- Watch 1 thread use 100% CPU
- Swipe the map to cancel user tracking
- Watch the CPU usage return to baseline
The value of animated:
does not seem to have an effect on CPU usage. true/false
both lead to one pegged core.
Small video showing the CPU changes with tracking mode changes with the iOS simulator:
https://www.youtube.com/watch?v=_71Hoz_7neA&feature=youtu.be
Expected behavior
Animating the map to follow the user marker shouldn't consume an entire core.
Actual behavior
My phone gets really hot and the battery drains quickly. My wife gets angry that she can't call me because my phone is dead. I get lost in the wilderness because I no longer have maps.
Note that #6060 and #7125 do not address this issue because the camera changes significantly on each location update.
/cc @incanus @bsudekum @willwhite
I’m moving this issue to v3.5.0, because a complete fix will require beta testing and possibly changes to mbgl. However, note that #7125 remains on the milestone, and #7724 has landed.
This issue has been automatically detected as stale because it has not had recent activity and will be archived. Thank you for your contributions.
Hello, do you plan to include a fix for this issue in one of the next releases? Following user location with the SDK causes this CPU spikes also in 4.9
I'd like to point out that the same issue in the Android SDK is caused by the heavy usage of the compass component.
this Might be related?
I'm testing version 4.10.0 on an iPhone X iOS 12.2, seems that we have spikes but profiling with instruments some are related to the core libraries but goes down immediately. The larger spikes in this chart are me playing with zooming in/out.
![cpuusage](https://user-images.githubusercontent.com/2745166/56620116-a790b580-65dc-11e9-9375-ae153e1ef475.png)
@racer1988 could you please post a screenshot of what you are seeing.
@fabian-guerra This is my graph when changing the map TrackingMode
the issue seems to be identical to the one that the reported initially raised.
Unfortunately I can't profile on the device and go around to reproduce the same. If you know how to run a GPX simulation while profiling, I'd be happy to try that.
Just by profiling and tracking user location I can see the map spiking to 50% and most of the usage is due to MapBox rendering:
I guess following user location is triggering re-rendering on the map somehow in a heavy way.
The usage of the total CPU cores in Xcode is around 50%, where Thread 1 is stuck at 100%. Memory consumption goes to very high.
Doing the same exact test with Mapkit sets the thread around 7/8 %
@racer1988 which map's SDK version are you testing? What's the device?
Tested with both 4.9 and 4.10 This graph comes from a iPhone X
the same is visible on the simulators if using a GPX track to reproduce the location
Using 4.9.0
Again the spikes are me zooming in/out panning
@racer1988 do you have a test app we could use to track down the issue?
I currently don’t have access to my laptop. I don’t have a existing app, I would need to create a new one to share. I could check next week.
If it can help, I am hosting the map in a child view controller that is then included in the main one. Not sure how this is relevant, but might have different layout passes than a direct use of the map
@julianrex @fabian-guerra I stripped down my production code to a basic map and I am able to reproduce in 100% of the cases.
You can find the code and reproduce yourself from here: https://github.com/racer1988/mapboxIssue
Important Notes:
- I did not put a token, so the map is not rendered. Even with that, the issue still occurs!
- The spike also happens while zooming in the first time by starting to track the user location. (the spike then goes down when the camera goes idle)
How to reproduce:
- Use
CocoaPod
to install MapBox (and PureLayout) - Run the app on a random simulator
- Simulate the location in Xcode with a random GPX: I provided
2014-04-09_2527084_test-iphone-5s_export_xcode.gpx
so you can use that one directly. - Click on the blue button on the map to cycle between:
ModeFollow
->ModeFollowWithHeading
->ModeNone
you can see the same behaviour reported by me and @danpat :
The TrackingMode button is the following one:
This is what I can see when clicking tracking for the first time and the zooming kicks in:
EDIT:
You can reproduce while profiling using the Simulator debug location (eg: Freeway ride)
@racer1988 thanks so much for providing a test case!
Hi, @racer1988. Thank you for the test app.
It seems that this is related to the gpx
file update frequency. I looked into our logs (you also can, take a look at this config), and realized there were 4~5 updates per second. Playing with the file to update every second I got the following chart:
![onesecond](https://user-images.githubusercontent.com/2745166/56929960-144df900-6a90-11e9-90fc-2215234825c4.png)
You can modify the file changing the time as it's suggested here: https://stackoverflow.com/a/36416589/1919929
In case you need, we have an API that will let you simulate location updates: https://docs.mapbox.com/ios/api/maps/4.10.0/Location%20Updates.html and an example on how to implement it is in: https://github.com/mapbox/mapbox-gl-native/blob/master/platform/ios/app/MBXCustomLocationViewController.m
@fabian-guerra Even at 4-5hz, if there's no map being rendered, what on earth is eating up all the CPU time? Why are location updates so CPU intensive if there's nothing to render?
@danpat I'm still researching this issue. Location management technology is cpu intensive. That being said don't know if Apple has some sort of optimizations for gpx
files in MapKit. This chart is from our API that simulates a location manager with a route in SF, and userTrackingMode
set to follow
.
@fabian-guerra the same behaviour in spike of CPU happens even with a fixed location when the tracking is set to follow and the map is slowly zoomed from level 1 to the max zoom level.
There the issue looks the same, however the cause can't be the location updates, as there are none. To me it looks like something else is eating CPU time
@racer1988 a fixed location in a gpx
file?
Without having any knowledge of this specific issue, one optimization that @LukasPaczos implemented on Android seems worth investigating on iOS — https://github.com/mapbox/mapbox-gl-native/pull/13678 — the idea being that we attempt to update the user location too frequently and for no real/visible benefit.
@fabian-guerra 2 more points here for your investigation:
- No, no need for a GPX.
You can simulate the issue two ways:
- On a simulator, launch the app, go to the location picker and choose a fixed one provided by apple. then switch to TrackingFollow (from None)
- On a Device: launch the app and switch tracking mode to zoom to your location.
Even with this simple case, the CPU spike is the same (eats 100% Thread), the inspector shows the same issue (see image at the bottom)
This is a simple case of a user wanting to zoom to his location. Even in this case, the camera updates are eating the full Thread, without anything really rendered
- The CPU is not going to 100% if the Location is updated without modifying the viewport even with the fast GPX file.
To simulate, start the GPX file, start following the user, then slighly pan away, to fallback to tracking None.
When the location annotation is in the viewPort, but the tracking is set to NONE, the CPU is at 0%
and only didUpdateUserLocation
is printed. (same if location is outside the viewport)
as soon as you set the mode to Follow
then the CPU start spiking due to the region updates:
didUpdateUserLocation
regionDidChangeAnimated
regionWillChangeAnimated
didUpdateUserLocation
regionDidChangeAnimated
This point IMHO that the issue is not with the location updates, but with the update of the region in the viewPort
@racer1988 I did tried with a single coordinate gpx
file or fixed location in the simulator. Although I see a spike and I think is normal because the map zooms in, after that it goes to zero. I'm testing the map with the token set.
In my comment https://github.com/mapbox/mapbox-gl-native/issues/7236#issuecomment-487770575 I posted how using our custom api to simulate updates it's almost unnoticeable.
Thanks for the info I will continue researching. Considering as well if we can try what it was implemented on Android as described in this comment https://github.com/mapbox/mapbox-gl-native/issues/7236#issuecomment-487773663
The intensive CPU usage is due to two main factors:
Location update frequency: Xcode does not allow set a frequency update for gpx
files, this can be somehow achieved by adding a timestamp to each location entry per https://stackoverflow.com/a/36416589/1919929. This behavior may be reproducible in an app using a combination of distanceFilter
and desiredAccuracy
in the default MGLLocationManager
, but as is known getting more frequent updates drain the battery, and require more calculations (major cpu usage).
Rendering frequency: As is already pointed in this comment https://github.com/mapbox/mapbox-gl-native/issues/7236#issuecomment-487566985 updateFromDisplayLink
calls our Core GL rendering stack. This stack performs a myriad of calculations leading to the "excessive" cpu usage (even tho you don't provide a token to download the tiles, the calculations are triggered anyways). Although #7125 and #7724 landed a while ago, both are platform level optimizations. It would require a significant change to our render engine to account for a render "cache" mechanism that leads to .
A workaround is change the location update frequency to let the cpu finish the job.
In this pr https://github.com/mapbox/mapbox-gl-native/pull/14577 I'm exploring another platform level optimization. In the pr I added a point based threshold that will move the camera thus triggering the render engine once the userAnnotationView.center
property crossed it.
This is how it looks with a 20point threshold, and using the gpx
file. While this optimization seems viable rises questions on if it's worth a lag feeling for camera updates, and how it will behave for followWithCourse
.
In conclusion I suggest change the location update frequency.
Has there been any progress on this? We're running into this with a turn by turn issue (using react-native-mapbox-gl)
bump to this. not only user tracking is affected, but [source setShape: shape];
too
Also experiencing crash logs due to excessive cpu usage during turn-by-turn navigation:
Event: cpu usage
Action taken: Process killed
CPU: 48 seconds cpu time over 59 seconds (81% cpu average), exceeding limit of 80% cpu over 60 seconds
CPU limit: 48s
Limit duration: 60s
CPU used: 48s
Duration: 7.03s
Steps: 8
any updated on this?
I'm seeing this in a React Native app too, but interestingly, I'm also seeing the exact same behaviour in a pure SwiftUI app.
On a simulator running either app, as soon as I set tracking mode to follow
, the CPU goes through the roof.
I can't reproduce the issue on my iPhone XR so perhaps this is a simulator-only problem? Certainly wouldn't be the first 😤