Skip to content

Commit 4fdf9c6

Browse files
author
Jeff Brown
committed
Detect bad behavior earlier in Choreographer.
Detect wonky vsync timestamps (should they occur) and warn loudly about them. Warn when too many frames are skipped. The threshold is pretty conservative right now (only warn if at least 30 frames are skipped) but it can be adjusted using system property. Even skipping just a couple of frames is enough to generate noticeable jank. The threshold is currently intended to help track down bigger problems such when an app does too much work on the UI thread. Bug: 6574842 Change-Id: I4aac7e5e17d1fb51adb0510e318a72a28b3775ed
1 parent 926a5c5 commit 4fdf9c6

File tree

1 file changed

+30
-3
lines changed

1 file changed

+30
-3
lines changed

core/java/android/view/Choreographer.java

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ protected Choreographer initialValue() {
103103
private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean(
104104
"debug.choreographer.frametime", true);
105105

106+
// Set a limit to warn about skipped frames.
107+
// Skipped frames imply jank.
108+
private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt(
109+
"debug.choreographer.skipwarning", 30);
110+
106111
private static final long NANOS_PER_MS = 1000000;
107112

108113
private static final int MSG_DO_FRAME = 0;
@@ -486,21 +491,26 @@ void doFrame(long frameTimeNanos, int frame) {
486491
startNanos = System.nanoTime();
487492
final long jitterNanos = startNanos - frameTimeNanos;
488493
if (jitterNanos >= mFrameIntervalNanos) {
494+
final long skippedFrames = jitterNanos / mFrameIntervalNanos;
495+
if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
496+
Log.w(TAG, "Skipped " + skippedFrames + " frames! "
497+
+ "The application may be doing too much work on its main thread.");
498+
}
489499
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
490500
if (DEBUG) {
491501
Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
492502
+ "which is more than the frame interval of "
493503
+ (mFrameIntervalNanos * 0.000001f) + " ms! "
494-
+ "Setting frame time to " + (lastFrameOffset * 0.000001f)
495-
+ " ms in the past.");
504+
+ "Skipping " + skippedFrames + " frames and setting frame "
505+
+ "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
496506
}
497507
frameTimeNanos = startNanos - lastFrameOffset;
498508
}
499509

500510
if (frameTimeNanos < mLastFrameTimeNanos) {
501511
if (DEBUG) {
502512
Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
503-
+ "previously skipped frame. Waiting for next vsync");
513+
+ "previously skipped frame. Waiting for next vsync.");
504514
}
505515
scheduleVsyncLocked();
506516
return;
@@ -658,6 +668,7 @@ public void handleMessage(Message msg) {
658668

659669
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
660670
implements Runnable {
671+
private boolean mHavePendingVsync;
661672
private long mTimestampNanos;
662673
private int mFrame;
663674

@@ -672,6 +683,21 @@ public void onVsync(long timestampNanos, int frame) {
672683
// the message queue. If there are no messages in the queue with timestamps
673684
// earlier than the frame time, then the vsync event will be processed immediately.
674685
// Otherwise, messages that predate the vsync event will be handled first.
686+
long now = System.nanoTime();
687+
if (timestampNanos > now) {
688+
Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
689+
+ " ms in the future! Check that graphics HAL is generating vsync "
690+
+ "timestamps using the correct timebase.");
691+
timestampNanos = now;
692+
}
693+
694+
if (mHavePendingVsync) {
695+
Log.w(TAG, "Already have a pending vsync event. There should only be "
696+
+ "one at a time.");
697+
} else {
698+
mHavePendingVsync = true;
699+
}
700+
675701
mTimestampNanos = timestampNanos;
676702
mFrame = frame;
677703
Message msg = Message.obtain(mHandler, this);
@@ -681,6 +707,7 @@ public void onVsync(long timestampNanos, int frame) {
681707

682708
@Override
683709
public void run() {
710+
mHavePendingVsync = false;
684711
doFrame(mTimestampNanos, mFrame);
685712
}
686713
}

0 commit comments

Comments
 (0)