summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Melody Hsu <melodymhsu@google.com> 2025-02-05 22:01:40 +0000
committer Melody Hsu <melodymhsu@google.com> 2025-02-11 06:54:40 +0000
commit92b519bd796f212a50d099c08f06ce54dc6609a2 (patch)
treeba96406dd1c052639e59213fcf2b7f972e9b7fed
parenta99ccaecaa8befcc3cc10d1866692b8e9d4d958d (diff)
Calculate workload target using original frame deadline
The target work duration in HWUI ADPF is sometimes incorrect, and is more often incorrect during buffer stuffing recovery due to the exposure of new jank. The issue causes CPU clock frequencies to decrease too much, and cause potential jank in subequent frames. The original frame deadline should be used instead in calculating the workload target deadline when triple buffered because even when the deadline is pushed later during buffer stuffing, the throughput requirements remain the same. Also fixes a misordering in FrameInfoNames that was inconsistent with FrameInfo and FrameMetrics. Bug: b/389939827 Test: atest JankTracker Test: presubmit, perfetto traces w/ and w/o buffer stuffing recovery Flag: com.android.graphics.hwui.flags.calc_workload_orig_deadline Change-Id: I2e3da6ee927d20fcbc9299ab5eda5732660d7246
-rw-r--r--core/java/android/view/FrameMetrics.java25
-rw-r--r--graphics/java/android/graphics/FrameInfo.java3
-rw-r--r--libs/hwui/FrameInfo.cpp5
-rw-r--r--libs/hwui/FrameInfo.h9
-rw-r--r--libs/hwui/JankTracker.cpp2
-rw-r--r--libs/hwui/Properties.cpp8
-rw-r--r--libs/hwui/Properties.h1
-rw-r--r--libs/hwui/aconfig/hwui_flags.aconfig11
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp8
-rw-r--r--libs/hwui/tests/unit/JankTrackerTests.cpp13
10 files changed, 67 insertions, 18 deletions
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index 58b2a67ec69e..a4fc342756ef 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -259,19 +259,20 @@ public final class FrameMetrics {
int FRAME_DEADLINE = 9;
int FRAME_START_TIME = 10;
int FRAME_INTERVAL = 11;
- int SYNC_QUEUED = 12;
- int SYNC_START = 13;
- int ISSUE_DRAW_COMMANDS_START = 14;
- int SWAP_BUFFERS = 15;
- int FRAME_COMPLETED = 16;
- int DEQUEUE_BUFFER_DURATION = 17;
- int QUEUE_BUFFER_DURATION = 18;
- int GPU_COMPLETED = 19;
- int SWAP_BUFFERS_COMPLETED = 20;
- int DISPLAY_PRESENT_TIME = 21;
- int COMMAND_SUBMISSION_COMPLETED = 22;
+ int WORKLOAD_TARGET = 12;
+ int SYNC_QUEUED = 13;
+ int SYNC_START = 14;
+ int ISSUE_DRAW_COMMANDS_START = 15;
+ int SWAP_BUFFERS = 16;
+ int FRAME_COMPLETED = 17;
+ int DEQUEUE_BUFFER_DURATION = 18;
+ int QUEUE_BUFFER_DURATION = 19;
+ int GPU_COMPLETED = 20;
+ int SWAP_BUFFERS_COMPLETED = 21;
+ int DISPLAY_PRESENT_TIME = 22;
+ int COMMAND_SUBMISSION_COMPLETED = 23;
- int FRAME_STATS_COUNT = 23; // must always be last and in sync with
+ int FRAME_STATS_COUNT = 24; // must always be last and in sync with
// FrameInfoIndex::NumIndexes in libs/hwui/FrameInfo.h
}
diff --git a/graphics/java/android/graphics/FrameInfo.java b/graphics/java/android/graphics/FrameInfo.java
index 8f1282897780..7d236d203201 100644
--- a/graphics/java/android/graphics/FrameInfo.java
+++ b/graphics/java/android/graphics/FrameInfo.java
@@ -95,7 +95,8 @@ public final class FrameInfo {
// Must be the last one
// This value must be in sync with `UI_THREAD_FRAME_INFO_SIZE` in FrameInfo.h
- private static final int FRAME_INFO_SIZE = FRAME_INTERVAL + 1;
+ // In calculating size, + 1 for Flags, and + 1 for WorkloadTarget from FrameInfo.h
+ private static final int FRAME_INFO_SIZE = FRAME_INTERVAL + 2;
/** checkstyle */
public void setVsync(long intendedVsync, long usedVsync, long frameTimelineVsyncId,
diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp
index a958a091a830..36feabde07eb 100644
--- a/libs/hwui/FrameInfo.cpp
+++ b/libs/hwui/FrameInfo.cpp
@@ -32,8 +32,9 @@ const std::array FrameInfoNames{"Flags",
"PerformTraversalsStart",
"DrawStart",
"FrameDeadline",
- "FrameInterval",
"FrameStartTime",
+ "FrameInterval",
+ "WorkloadTarget",
"SyncQueued",
"SyncStart",
"IssueDrawCommandsStart",
@@ -48,7 +49,7 @@ const std::array FrameInfoNames{"Flags",
};
-static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 23,
+static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 24,
"Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)");
void FrameInfo::importUiThreadInfo(int64_t* info) {
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index f7ad13978a30..61c30b803b00 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -30,7 +30,8 @@
namespace android {
namespace uirenderer {
-static constexpr size_t UI_THREAD_FRAME_INFO_SIZE = 12;
+// This value must be in sync with `FRAME_INFO_SIZE` in FrameInfo.Java
+static constexpr size_t UI_THREAD_FRAME_INFO_SIZE = 13;
enum class FrameInfoIndex {
Flags = 0,
@@ -47,6 +48,11 @@ enum class FrameInfoIndex {
FrameInterval,
// End of UI frame info
+ // The target workload duration based on the original frame deadline and
+ // and intended vsync. Counted in UI_THREAD_FRAME_INFO_SIZE so its value
+ // can be set in setVsync().
+ WorkloadTarget,
+
SyncQueued,
SyncStart,
@@ -109,6 +115,7 @@ public:
set(FrameInfoIndex::FrameStartTime) = vsyncTime;
set(FrameInfoIndex::FrameDeadline) = frameDeadline;
set(FrameInfoIndex::FrameInterval) = frameInterval;
+ set(FrameInfoIndex::WorkloadTarget) = frameDeadline - intendedVsync;
return *this;
}
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 638a060bdb1c..80eb6bc986d6 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -201,7 +201,7 @@ void JankTracker::finishFrame(FrameInfo& frame, std::unique_ptr<FrameMetricsRepo
// If we are in triple buffering, we have enough buffers in queue to sustain a single frame
// drop without jank, so adjust the frame interval to the deadline.
if (isTripleBuffered) {
- int64_t originalDeadlineDuration = deadline - frame[FrameInfoIndex::IntendedVsync];
+ int64_t originalDeadlineDuration = frame[FrameInfoIndex::WorkloadTarget];
deadline = mNextFrameStartUnstuffed + originalDeadlineDuration;
frame.set(FrameInfoIndex::FrameDeadline) = deadline;
}
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 7d01dfbb446f..21430f7e6777 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -57,6 +57,9 @@ constexpr bool query_global_priority() {
constexpr bool early_preload_gl_context() {
return false;
}
+constexpr bool calc_workload_orig_deadline() {
+ return false;
+}
} // namespace hwui_flags
#endif
@@ -299,5 +302,10 @@ bool Properties::earlyPreloadGlContext() {
hwui_flags::early_preload_gl_context());
}
+bool Properties::calcWorkloadOrigDeadline() {
+ static bool sCalcWorkloadOrigDeadline = base::GetBoolProperty(
+ "debug.hwui.calc_workload_orig_deadline", hwui_flags::calc_workload_orig_deadline());
+ return sCalcWorkloadOrigDeadline;
+}
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 280a75a28e65..a7a564428636 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -384,6 +384,7 @@ public:
static bool initializeGlAlways();
static bool resampleGainmapRegions();
static bool earlyPreloadGlContext();
+ static bool calcWorkloadOrigDeadline();
private:
static StretchEffectBehavior stretchEffectBehavior;
diff --git a/libs/hwui/aconfig/hwui_flags.aconfig b/libs/hwui/aconfig/hwui_flags.aconfig
index 2851dd8b1003..62fd7d358123 100644
--- a/libs/hwui/aconfig/hwui_flags.aconfig
+++ b/libs/hwui/aconfig/hwui_flags.aconfig
@@ -176,4 +176,15 @@ flag {
namespace: "core_graphics"
description: "Initialize GL context and GraphicBufferAllocater init on renderThread preload. This improves app startup time for apps using GL."
bug: "383612849"
+}
+
+flag {
+ name: "calc_workload_orig_deadline"
+ namespace: "window_surfaces"
+ description: "Use original frame deadline to calculate the workload target deadline for jank tracking"
+ bug: "389939827"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
} \ No newline at end of file
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index b36b8be10779..e3e393c4fdfb 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -789,7 +789,13 @@ void CanvasContext::draw(bool solelyTextureViewUpdates) {
int64_t frameDeadline = mCurrentFrameInfo->get(FrameInfoIndex::FrameDeadline);
int64_t dequeueBufferDuration = mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration);
- mHintSessionWrapper->updateTargetWorkDuration(frameDeadline - intendedVsync);
+ if (Properties::calcWorkloadOrigDeadline()) {
+ // Uses the unmodified frame deadline in calculating workload target duration
+ mHintSessionWrapper->updateTargetWorkDuration(
+ mCurrentFrameInfo->get(FrameInfoIndex::WorkloadTarget));
+ } else {
+ mHintSessionWrapper->updateTargetWorkDuration(frameDeadline - intendedVsync);
+ }
if (didDraw) {
int64_t frameStartTime = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime);
diff --git a/libs/hwui/tests/unit/JankTrackerTests.cpp b/libs/hwui/tests/unit/JankTrackerTests.cpp
index b67e419e7d4a..c289d67fbef6 100644
--- a/libs/hwui/tests/unit/JankTrackerTests.cpp
+++ b/libs/hwui/tests/unit/JankTrackerTests.cpp
@@ -45,6 +45,7 @@ TEST(JankTracker, noJank) {
info->set(FrameInfoIndex::FrameCompleted) = 115_ms;
info->set(FrameInfoIndex::FrameInterval) = 16_ms;
info->set(FrameInfoIndex::FrameDeadline) = 120_ms;
+ info->set(FrameInfoIndex::WorkloadTarget) = 20_ms;
jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId);
info = jankTracker.startFrame();
@@ -55,6 +56,7 @@ TEST(JankTracker, noJank) {
info->set(FrameInfoIndex::FrameCompleted) = 131_ms;
info->set(FrameInfoIndex::FrameInterval) = 16_ms;
info->set(FrameInfoIndex::FrameDeadline) = 136_ms;
+ info->set(FrameInfoIndex::WorkloadTarget) = 20_ms;
jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId);
ASSERT_EQ(2, container.get()->totalFrameCount());
@@ -79,6 +81,7 @@ TEST(JankTracker, jank) {
info->set(FrameInfoIndex::FrameCompleted) = 121_ms;
info->set(FrameInfoIndex::FrameInterval) = 16_ms;
info->set(FrameInfoIndex::FrameDeadline) = 120_ms;
+ info->set(FrameInfoIndex::WorkloadTarget) = 20_ms;
jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId);
ASSERT_EQ(1, container.get()->totalFrameCount());
@@ -102,6 +105,7 @@ TEST(JankTracker, legacyJankButNoRealJank) {
info->set(FrameInfoIndex::FrameCompleted) = 118_ms;
info->set(FrameInfoIndex::FrameInterval) = 16_ms;
info->set(FrameInfoIndex::FrameDeadline) = 120_ms;
+ info->set(FrameInfoIndex::WorkloadTarget) = 20_ms;
jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId);
ASSERT_EQ(1, container.get()->totalFrameCount());
@@ -127,6 +131,7 @@ TEST(JankTracker, doubleStuffed) {
info->set(FrameInfoIndex::FrameCompleted) = 121_ms;
info->set(FrameInfoIndex::FrameInterval) = 16_ms;
info->set(FrameInfoIndex::FrameDeadline) = 120_ms;
+ info->set(FrameInfoIndex::WorkloadTarget) = 20_ms;
jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId);
ASSERT_EQ(1, container.get()->jankFrameCount());
@@ -140,6 +145,7 @@ TEST(JankTracker, doubleStuffed) {
info->set(FrameInfoIndex::FrameCompleted) = 137_ms;
info->set(FrameInfoIndex::FrameInterval) = 16_ms;
info->set(FrameInfoIndex::FrameDeadline) = 136_ms;
+ info->set(FrameInfoIndex::WorkloadTarget) = 20_ms;
jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId);
ASSERT_EQ(2, container.get()->totalFrameCount());
@@ -164,6 +170,7 @@ TEST(JankTracker, doubleStuffedThenPauseThenJank) {
info->set(FrameInfoIndex::FrameCompleted) = 121_ms;
info->set(FrameInfoIndex::FrameInterval) = 16_ms;
info->set(FrameInfoIndex::FrameDeadline) = 120_ms;
+ info->set(FrameInfoIndex::WorkloadTarget) = 20_ms;
jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId);
ASSERT_EQ(1, container.get()->jankFrameCount());
@@ -177,6 +184,7 @@ TEST(JankTracker, doubleStuffedThenPauseThenJank) {
info->set(FrameInfoIndex::FrameCompleted) = 137_ms;
info->set(FrameInfoIndex::FrameInterval) = 16_ms;
info->set(FrameInfoIndex::FrameDeadline) = 136_ms;
+ info->set(FrameInfoIndex::WorkloadTarget) = 20_ms;
jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId);
ASSERT_EQ(1, container.get()->jankFrameCount());
@@ -190,6 +198,7 @@ TEST(JankTracker, doubleStuffedThenPauseThenJank) {
info->set(FrameInfoIndex::FrameCompleted) = 169_ms;
info->set(FrameInfoIndex::FrameInterval) = 16_ms;
info->set(FrameInfoIndex::FrameDeadline) = 168_ms;
+ info->set(FrameInfoIndex::WorkloadTarget) = 20_ms;
jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId);
ASSERT_EQ(3, container.get()->totalFrameCount());
@@ -214,6 +223,7 @@ TEST(JankTracker, doubleStuffedTwoIntervalBehind) {
info->set(FrameInfoIndex::FrameCompleted) = 117_ms;
info->set(FrameInfoIndex::FrameInterval) = 16_ms;
info->set(FrameInfoIndex::FrameDeadline) = 116_ms;
+ info->set(FrameInfoIndex::WorkloadTarget) = 16_ms;
jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId);
ASSERT_EQ(1, container.get()->jankFrameCount());
@@ -228,6 +238,7 @@ TEST(JankTracker, doubleStuffedTwoIntervalBehind) {
info->set(FrameInfoIndex::FrameCompleted) = 133_ms;
info->set(FrameInfoIndex::FrameInterval) = 16_ms;
info->set(FrameInfoIndex::FrameDeadline) = 132_ms;
+ info->set(FrameInfoIndex::WorkloadTarget) = 16_ms;
jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId);
ASSERT_EQ(1, container.get()->jankFrameCount());
@@ -242,6 +253,7 @@ TEST(JankTracker, doubleStuffedTwoIntervalBehind) {
info->set(FrameInfoIndex::FrameCompleted) = 165_ms;
info->set(FrameInfoIndex::FrameInterval) = 16_ms;
info->set(FrameInfoIndex::FrameDeadline) = 148_ms;
+ info->set(FrameInfoIndex::WorkloadTarget) = 16_ms;
jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId);
ASSERT_EQ(2, container.get()->jankFrameCount());
@@ -256,6 +268,7 @@ TEST(JankTracker, doubleStuffedTwoIntervalBehind) {
info->set(FrameInfoIndex::FrameCompleted) = 181_ms;
info->set(FrameInfoIndex::FrameInterval) = 16_ms;
info->set(FrameInfoIndex::FrameDeadline) = 164_ms;
+ info->set(FrameInfoIndex::WorkloadTarget) = 16_ms;
jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId);
ASSERT_EQ(2, container.get()->jankFrameCount());