Merge "Choreographer: add more traces" into sc-dev

This commit is contained in:
Ady Abraham
2021-04-15 19:17:28 +00:00
committed by Android (Google) Code Review

View File

@@ -693,71 +693,79 @@ public final class Choreographer {
ThreadedRenderer.setFPSDivisor(divisor); ThreadedRenderer.setFPSDivisor(divisor);
} }
private void traceMessage(String msg) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, msg);
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
void doFrame(long frameTimeNanos, int frame, void doFrame(long frameTimeNanos, int frame,
DisplayEventReceiver.VsyncEventData vsyncEventData) { DisplayEventReceiver.VsyncEventData vsyncEventData) {
final long startNanos; final long startNanos;
final long frameIntervalNanos = vsyncEventData.frameInterval; final long frameIntervalNanos = vsyncEventData.frameInterval;
synchronized (mLock) {
if (!mFrameScheduled) {
return; // no work to do
}
if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
mDebugPrintNextFrameTimeDelta = false;
Log.d(TAG, "Frame time delta: "
+ ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
}
long intendedFrameTimeNanos = frameTimeNanos;
startNanos = System.nanoTime();
final long jitterNanos = startNanos - frameTimeNanos;
if (jitterNanos >= frameIntervalNanos) {
final long skippedFrames = jitterNanos / frameIntervalNanos;
if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
Log.i(TAG, "Skipped " + skippedFrames + " frames! "
+ "The application may be doing too much work on its main thread.");
}
final long lastFrameOffset = jitterNanos % frameIntervalNanos;
if (DEBUG_JANK) {
Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
+ "which is more than the frame interval of "
+ (frameIntervalNanos * 0.000001f) + " ms! "
+ "Skipping " + skippedFrames + " frames and setting frame "
+ "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
}
frameTimeNanos = startNanos - lastFrameOffset;
}
if (frameTimeNanos < mLastFrameTimeNanos) {
if (DEBUG_JANK) {
Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
+ "previously skipped frame. Waiting for next vsync.");
}
scheduleVsyncLocked();
return;
}
if (mFPSDivisor > 1) {
long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
if (timeSinceVsync < (frameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
scheduleVsyncLocked();
return;
}
}
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos, vsyncEventData.id,
vsyncEventData.frameDeadline, startNanos, vsyncEventData.frameInterval);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
mLastFrameIntervalNanos = frameIntervalNanos;
mLastVsyncEventData = vsyncEventData;
}
try { try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, Trace.traceBegin(Trace.TRACE_TAG_VIEW,
"Choreographer#doFrame " + vsyncEventData.id); "Choreographer#doFrame " + vsyncEventData.id);
} }
synchronized (mLock) {
if (!mFrameScheduled) {
traceMessage("Frame not scheduled");
return; // no work to do
}
if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
mDebugPrintNextFrameTimeDelta = false;
Log.d(TAG, "Frame time delta: "
+ ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
}
long intendedFrameTimeNanos = frameTimeNanos;
startNanos = System.nanoTime();
final long jitterNanos = startNanos - frameTimeNanos;
if (jitterNanos >= frameIntervalNanos) {
final long skippedFrames = jitterNanos / frameIntervalNanos;
if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
Log.i(TAG, "Skipped " + skippedFrames + " frames! "
+ "The application may be doing too much work on its main thread.");
}
final long lastFrameOffset = jitterNanos % frameIntervalNanos;
if (DEBUG_JANK) {
Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
+ "which is more than the frame interval of "
+ (frameIntervalNanos * 0.000001f) + " ms! "
+ "Skipping " + skippedFrames + " frames and setting frame "
+ "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
}
frameTimeNanos = startNanos - lastFrameOffset;
}
if (frameTimeNanos < mLastFrameTimeNanos) {
if (DEBUG_JANK) {
Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
+ "previously skipped frame. Waiting for next vsync.");
}
traceMessage("Frame time goes backward");
scheduleVsyncLocked();
return;
}
if (mFPSDivisor > 1) {
long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
if (timeSinceVsync < (frameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
traceMessage("Frame skipped due to FPSDivisor");
scheduleVsyncLocked();
return;
}
}
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos, vsyncEventData.id,
vsyncEventData.frameDeadline, startNanos, vsyncEventData.frameInterval);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
mLastFrameIntervalNanos = frameIntervalNanos;
mLastVsyncEventData = vsyncEventData;
}
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS); AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart(); mFrameInfo.markInputHandlingStart();
@@ -870,7 +878,12 @@ public final class Choreographer {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private void scheduleVsyncLocked() { private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync(); try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#scheduleVsyncLocked");
mDisplayEventReceiver.scheduleVsync();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
} }
private boolean isRunningOnLooperThreadLocked() { private boolean isRunningOnLooperThreadLocked() {
@@ -967,32 +980,40 @@ public final class Choreographer {
@Override @Override
public void onVsync(long timestampNanos, long physicalDisplayId, int frame, public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
VsyncEventData vsyncEventData) { VsyncEventData vsyncEventData) {
// Post the vsync event to the Handler. try {
// The idea is to prevent incoming vsync events from completely starving if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
// the message queue. If there are no messages in the queue with timestamps Trace.traceBegin(Trace.TRACE_TAG_VIEW,
// earlier than the frame time, then the vsync event will be processed immediately. "Choreographer#onVsync " + vsyncEventData.id);
// Otherwise, messages that predate the vsync event will be handled first. }
long now = System.nanoTime(); // Post the vsync event to the Handler.
if (timestampNanos > now) { // The idea is to prevent incoming vsync events from completely starving
Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f) // the message queue. If there are no messages in the queue with timestamps
+ " ms in the future! Check that graphics HAL is generating vsync " // earlier than the frame time, then the vsync event will be processed immediately.
+ "timestamps using the correct timebase."); // Otherwise, messages that predate the vsync event will be handled first.
timestampNanos = now; long now = System.nanoTime();
} if (timestampNanos > now) {
Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
+ " ms in the future! Check that graphics HAL is generating vsync "
+ "timestamps using the correct timebase.");
timestampNanos = now;
}
if (mHavePendingVsync) { if (mHavePendingVsync) {
Log.w(TAG, "Already have a pending vsync event. There should only be " Log.w(TAG, "Already have a pending vsync event. There should only be "
+ "one at a time."); + "one at a time.");
} else { } else {
mHavePendingVsync = true; mHavePendingVsync = true;
} }
mTimestampNanos = timestampNanos; mTimestampNanos = timestampNanos;
mFrame = frame; mFrame = frame;
mLastVsyncEventData = vsyncEventData; mLastVsyncEventData = vsyncEventData;
Message msg = Message.obtain(mHandler, this); Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true); msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS); mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
} }
@Override @Override