androidvsyncsystracesurfaceflinger

Performance drop of Android animation when device stays still but is touched


My app changes the properties of some really simple views (rotation, translation) per frame. I used systrace, as advised by Android performance articles, to check if I was dropping frames.

Something really unexpected came up. When the device was standing still (even if I touched the screen) the CPU usage was higher, alerts on systrace came up and the red portion of GPU rendering profiler was longer. When I rotated or shook the device really fast, everything was OK.

Below are the links of the results. Shake is when I rotated the devices really fast, no_shake is when it was left sitting on my desk.

I made a really simple test app that uses a single translation animation: source code.

Systrace: no shake, shake

CPU usage: enter image description here

GPU profiler: enter image description here

Looking at the shake systrace, where frame-rate is smooth, why do HW_VSYNC_0 and HW_VSYNC_ON_0 lines have no data? How can I read the CPU frequency (I did enable the option when capturing the trace).

Regarding the problem, my theory was that the device could be lowering the CPU frequency. How can I read this in systrace? I used a 3rd party app to test this hypothesis and it is true as shown below. So, what can I do to avoid this problem?

enter image description here

Why is the device doing this? At first I thought that the device uses the accelerometer data to understand if it is not being used and then it reduced the CPU frequency. But, in order to increase the CPU frequency I have to shake the device really hard. Holding it like a normal person would does not increase the CPU frequency.

I know that's a lot of questions, but having read all the related articles about the Android graphics pipeline, I am out of ideas.

The problem occurred on a Sony Xperia Z3 running Android 5.1 The problem was not reproducable on a Nexus 5 running Android 6.

Update

It seems that the performance issue is caused by CPU/GPU throttling. The same device, Xperia Z3, when running Android 4.4, even though it reduces the clock speed, it performs better according to Systrace. Also, it does not increase speed when shaking.

Regarding the shaking gesture required to increase the CPU speed, I noticed that when I try to rotate the device from portrait to landscape or vice versa, then the CPU clock increase in triggered (even if the app doesn't change orientation). So, I think that the reason this gesture is monitored is to speed up a possible orientation change.


Solution

  • Some observations...

    Mobile devices, particularly those based on Qualcomm chips, aggressively reduce the CPU clocks to minimize power consumption. Sometimes their policies are a bit heavy-handed. They also try to reduce the number of active cores to the number needed to handle the current workload.

    Looking at the systrace output, just at the "CPU n" lines, you can see that the "shake" trace is keeping all four cores busy, while the "no shake" trace is often making do with 2 or 3. So the load on the system is lighter when you're not shaking it. Depending on how the CPU governor is tuned, it may be making other changes, such as to the clock frequencies.

    You can see changes to the values of the various clocks by adding the "freq" tag to the systrace command line. You may need a rooted device to get this information. It should show changes to the settings for the CPU clocks, GPU bandwidth, and other arcane items. Note it only reports changes, so you may want to tap the screen after recording starts to encourage it to do something.

    I'm sure you know this, but for those who don't: if something takes N CPU cycles to execute, and the CPU is running at 100% speed, the task will complete in T seconds. If the CPU is running at 50% speed, the task will complete in 2*T seconds. The tools that measure CPU utilization do so by determining what percentage of the time the CPU is running vs. idle over a given period. If the tool watches for 1 second, and the task runs for 1 second, that's 100% utilization. If the CPU clocks are higher and the task finishes in 0.5 seconds, that's 50% utilization. The advantage of lower clocks is that power consumption is nonlinear, so while you're using N CPU cycles either way, the lower-and-slower configuration drains the battery less. The trouble with lower clocks is that things take longer to execute, and your app can end up dropping frames. This is why touching the screen raises the clocks: the CPU governor knows you're interacting with the device, and configures the system to make interaction as smooth as possible.

    You should ignore the VSYNC stuff. On some devices SurfaceFlinger uses out-of-phase software-generated VSYNC signals (google "dispsync" for details). It uses feedback from the display refresh fence to decide if it's drifting, and will turn hardware VSYNC back on briefly to re-sync when necessary. (FWIW, the lines in question do have data in the traces you posted.)