Change hwui jank detection to use deadline & gpu completion (1/2)
- Use GPU finish time as well as actual deadline to determine jank
rate.
- Use dynamic interval to adjust for 60/90hz switching
- Move frame metrics reporting into JankTracker to adjust the
deadline communicated to the app when in stuffing scenario.
- Adjust double-stuffing detection to be a bit more readable.
Test: GraphicsStatsValidationTest.java
Test: adb shell dumpsys gfxinfo
Test: FrameMetricsListenerTest
Test: Log output of FrameMetricsObserver
Bug: 169858044
Change-Id: I3a6b8ed163e2cf9cf2b67667110340ebe35f98a1
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index aedb5c2..b2a9863 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -473,6 +473,9 @@
return;
}
+ mCurrentFrameInfo->set(FrameInfoIndex::FrameInterval) =
+ mRenderThread.timeLord().frameIntervalNanos();
+
mCurrentFrameInfo->markIssueDrawCommandsStart();
Frame frame = mRenderPipeline->getFrame();
@@ -591,25 +594,13 @@
mCurrentFrameInfo->markFrameCompleted();
mCurrentFrameInfo->set(FrameInfoIndex::GpuCompleted)
= mCurrentFrameInfo->get(FrameInfoIndex::FrameCompleted);
- finishFrame(mCurrentFrameInfo);
+ mJankTracker.finishFrame(*mCurrentFrameInfo, mFrameMetricsReporter);
}
}
mRenderThread.cacheManager().onFrameCompleted();
}
-void CanvasContext::finishFrame(FrameInfo* frameInfo) {
- // TODO (b/169858044): Consolidate this into a single call.
- mJankTracker.finishFrame(*frameInfo);
- mJankTracker.finishGpuDraw(*frameInfo);
-
- // TODO (b/169858044): Move this into JankTracker to adjust deadline when queue is
- // double-stuffed.
- if (CC_UNLIKELY(mFrameMetricsReporter.get() != nullptr)) {
- mFrameMetricsReporter->reportFrameMetrics(frameInfo->data(), false /*hasPresentTime*/);
- }
-}
-
void CanvasContext::reportMetricsWithPresentTime() {
if (mFrameMetricsReporter == nullptr) {
return;
@@ -675,7 +666,7 @@
}
frameInfo->set(FrameInfoIndex::FrameCompleted) = gpuCompleteTime;
frameInfo->set(FrameInfoIndex::GpuCompleted) = gpuCompleteTime;
- instance->finishFrame(frameInfo);
+ instance->mJankTracker.finishFrame(*frameInfo, instance->mFrameMetricsReporter);
}
}
@@ -704,10 +695,11 @@
nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos();
int64_t vsyncId = mRenderThread.timeLord().lastVsyncId();
int64_t frameDeadline = mRenderThread.timeLord().lastFrameDeadline();
+ int64_t frameInterval = mRenderThread.timeLord().frameIntervalNanos();
int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
UiFrameInfoBuilder(frameInfo)
.addFlag(FrameInfoFlags::RTAnimation)
- .setVsync(vsync, vsync, vsyncId, frameDeadline);
+ .setVsync(vsync, vsync, vsyncId, frameDeadline, frameInterval);
TreeInfo info(TreeInfo::MODE_RT_ONLY, *this);
prepareTree(info, frameInfo, systemTime(SYSTEM_TIME_MONOTONIC), node);
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 7a38a3b..cb92aa1 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -161,7 +161,9 @@
int64_t intendedVsync = mFrameInfo[static_cast<int>(FrameInfoIndex::IntendedVsync)];
int64_t vsyncId = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameTimelineVsyncId)];
int64_t frameDeadline = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameDeadline)];
- mRenderThread->timeLord().vsyncReceived(vsync, intendedVsync, vsyncId, frameDeadline);
+ int64_t frameInterval = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameInterval)];
+ mRenderThread->timeLord().vsyncReceived(vsync, intendedVsync, vsyncId, frameDeadline,
+ frameInterval);
bool canDraw = mContext->makeCurrent();
mContext->unpinImages();
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 79b9388..682baa6 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -87,9 +87,10 @@
RenderThread* rt = reinterpret_cast<RenderThread*>(data);
int64_t vsyncId = AChoreographer_getVsyncId(rt->mChoreographer);
int64_t frameDeadline = AChoreographer_getFrameDeadline(rt->mChoreographer);
+ int64_t frameInterval = AChoreographer_getFrameInterval(rt->mChoreographer);
rt->mVsyncRequested = false;
- if (rt->timeLord().vsyncReceived(frameTimeNanos, frameTimeNanos, vsyncId, frameDeadline) &&
- !rt->mFrameCallbackTaskPending) {
+ if (rt->timeLord().vsyncReceived(frameTimeNanos, frameTimeNanos, vsyncId, frameDeadline,
+ frameInterval) && !rt->mFrameCallbackTaskPending) {
ATRACE_NAME("queue mFrameCallbackTask");
rt->mFrameCallbackTaskPending = true;
nsecs_t runAt = (frameTimeNanos + rt->mDispatchFrameDelay);
diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp
index abb6330..406066c 100644
--- a/libs/hwui/renderthread/TimeLord.cpp
+++ b/libs/hwui/renderthread/TimeLord.cpp
@@ -27,11 +27,14 @@
mFrameDeadline(std::numeric_limits<int64_t>::max()){}
bool TimeLord::vsyncReceived(nsecs_t vsync, nsecs_t intendedVsync, int64_t vsyncId,
- int64_t frameDeadline) {
+ int64_t frameDeadline, nsecs_t frameInterval) {
if (intendedVsync > mFrameIntendedTimeNanos) {
mFrameIntendedTimeNanos = intendedVsync;
mFrameVsyncId = vsyncId;
mFrameDeadline = frameDeadline;
+ if (frameInterval > 0) {
+ mFrameIntervalNanos = frameInterval;
+ }
}
if (vsync > mFrameTimeNanos) {
diff --git a/libs/hwui/renderthread/TimeLord.h b/libs/hwui/renderthread/TimeLord.h
index fa05c030..8cd6733 100644
--- a/libs/hwui/renderthread/TimeLord.h
+++ b/libs/hwui/renderthread/TimeLord.h
@@ -33,7 +33,7 @@
// returns true if the vsync is newer, false if it was rejected for staleness
bool vsyncReceived(nsecs_t vsync, nsecs_t indendedVsync, int64_t vsyncId,
- int64_t frameDeadline);
+ int64_t frameDeadline, nsecs_t frameInterval);
nsecs_t latestVsync() { return mFrameTimeNanos; }
nsecs_t computeFrameTimeNanos();
int64_t lastVsyncId() const { return mFrameVsyncId; }