Loading core/java/android/os/flags.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,17 @@ flag { } } flag { name: "adpf_cap_max_batch_size" namespace: "game" description: "Caps the maximum batch size of work durations that can be sent in a report" is_fixed_read_only: true bug: "406377213" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "adpf_gpu_report_actual_work_duration" is_exported: true Loading native/android/libandroid.map.txt +1 −0 Original line number Diff line number Diff line Loading @@ -432,6 +432,7 @@ LIBANDROID_PLATFORM { APerformanceHint_setUseNewLoadHintBehaviorForTesting; APerformanceHint_closeSessionFromJava; APerformanceHint_createSessionFromJava; APerformanceHint_setReportBatchSizeCapForTesting; extern "C++" { ASurfaceControl_registerSurfaceStatsListener*; ASurfaceControl_unregisterSurfaceStatsListener*; Loading native/android/performance_hint.cpp +21 −3 Original line number Diff line number Diff line Loading @@ -98,6 +98,9 @@ constexpr double kReplenishRate = kMaxLoadHintsPerInterval / static_cast<double> constexpr int64_t kSendHintTimeout = kLoadHintInterval / kMaxLoadHintsPerInterval; bool kForceNewHintBehavior = false; std::optional<size_t> kReportBatchSizeCap = android::os::adpf_cap_max_batch_size() ? std::make_optional(50) : std::nullopt; template <class T> constexpr int32_t enum_size() { return static_cast<int32_t>(*(ndk::enum_range<T>().end() - 1)) + 1; Loading Loading @@ -783,7 +786,16 @@ int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* wor } traceActualDuration(actualTotalDurationNanos); mActualWorkDurations.push_back(std::move(*workDuration)); mActualWorkDurations.push_back(*workDuration); if (kReportBatchSizeCap.has_value()) { // Check if the buffer is larger than the max size, and if it is pop the oldest elements const int overflow = mActualWorkDurations.size() - *kReportBatchSizeCap; if (overflow > 0) { mActualWorkDurations.erase(mActualWorkDurations.begin(), mActualWorkDurations.begin() + overflow); } } if (actualTotalDurationNanos >= mTargetDurationNanos) { // Reset timestamps if we are equal or over the target. Loading Loading @@ -872,12 +884,14 @@ void APerformanceHintManager::layersFromNativeSurfaces(ANativeWindow** windows, std::vector<ASurfaceControl*> controlVec(controls, controls + numSurfaceControls); for (auto&& aSurfaceControl : controlVec) { SurfaceControl* control = reinterpret_cast<SurfaceControl*>(aSurfaceControl); if (control != nullptr) { if (control->isValid()) { out.push_back(control->getHandle()); } } } } } // ===================================== FMQ wrapper implementation Loading Loading @@ -1396,6 +1410,10 @@ void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior) { kForceNewHintBehavior = newBehavior; } void APerformanceHint_setReportBatchSizeCapForTesting(int cap) { kReportBatchSizeCap = cap > 0 ? std::make_optional(cap) : std::nullopt; } void ASessionCreationConfig_setNativeSurfaces(ASessionCreationConfig* config, ANativeWindow** nativeWindows, size_t nativeWindowsSize, Loading native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +57 −0 Original line number Diff line number Diff line Loading @@ -640,6 +640,63 @@ TEST_F(PerformanceHintTest, TestSupportObject) { EXPECT_EQ(expectedSupportInt, actualSupportInt); } TEST_F(PerformanceHintTest, TestReportActualOverflow) { mClientData.preferredRateNanos = 10000000L; APerformanceHintManager* manager = createManager(); auto&& config = configFromCreator({ .tids = mTids, .targetDuration = 20, }); auto&& session = createSession(manager); hal::WorkDuration duration{.timeStampNanos = 3, .durationNanos = 10, .workPeriodStartTimestampNanos = 1, .cpuDurationNanos = 5, .gpuDurationNanos = 5}; EXPECT_CALL(*mMockSession, reportActualWorkDuration2(_)).Times(2); // Report a duration under the target, to signal the start of good behavior per the rate limiter APerformanceHint_reportActualWorkDuration2(session.get(), reinterpret_cast<AWorkDuration*>(&duration)); // Sleep for longer than preferredUpdateRateNanos. usleep(12000); // Report a duration under the target, to signal continued good behavior per the rate limiter APerformanceHint_reportActualWorkDuration2(session.get(), reinterpret_cast<AWorkDuration*>(&duration)); EXPECT_CALL(*mMockSession, reportActualWorkDuration2(SizeIs(Eq(30)))).Times(1); APerformanceHint_setReportBatchSizeCapForTesting(-1); for (int i = 0; i < 29; ++i) { APerformanceHint_reportActualWorkDuration2(session.get(), reinterpret_cast<AWorkDuration*>(&duration)); } // Sleep for longer than preferredUpdateRateNanos. usleep(12000); APerformanceHint_reportActualWorkDuration2(session.get(), reinterpret_cast<AWorkDuration*>(&duration)); // Enforce that report spam gets capped EXPECT_CALL(*mMockSession, reportActualWorkDuration2(SizeIs(Eq(10)))).Times(1); APerformanceHint_setReportBatchSizeCapForTesting(10); for (int i = 0; i < 29; ++i) { APerformanceHint_reportActualWorkDuration2(session.get(), reinterpret_cast<AWorkDuration*>(&duration)); } // Sleep for longer than preferredUpdateRateNanos. usleep(12000); APerformanceHint_reportActualWorkDuration2(session.get(), reinterpret_cast<AWorkDuration*>(&duration)); } TEST_F(PerformanceHintTest, TestCreatingAutoSession) { // Disable GPU capability for testing mClientData.supportInfo.sessionModes &= ~(1 << (int)hal::SessionMode::AUTO_GPU); Loading Loading
core/java/android/os/flags.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,17 @@ flag { } } flag { name: "adpf_cap_max_batch_size" namespace: "game" description: "Caps the maximum batch size of work durations that can be sent in a report" is_fixed_read_only: true bug: "406377213" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "adpf_gpu_report_actual_work_duration" is_exported: true Loading
native/android/libandroid.map.txt +1 −0 Original line number Diff line number Diff line Loading @@ -432,6 +432,7 @@ LIBANDROID_PLATFORM { APerformanceHint_setUseNewLoadHintBehaviorForTesting; APerformanceHint_closeSessionFromJava; APerformanceHint_createSessionFromJava; APerformanceHint_setReportBatchSizeCapForTesting; extern "C++" { ASurfaceControl_registerSurfaceStatsListener*; ASurfaceControl_unregisterSurfaceStatsListener*; Loading
native/android/performance_hint.cpp +21 −3 Original line number Diff line number Diff line Loading @@ -98,6 +98,9 @@ constexpr double kReplenishRate = kMaxLoadHintsPerInterval / static_cast<double> constexpr int64_t kSendHintTimeout = kLoadHintInterval / kMaxLoadHintsPerInterval; bool kForceNewHintBehavior = false; std::optional<size_t> kReportBatchSizeCap = android::os::adpf_cap_max_batch_size() ? std::make_optional(50) : std::nullopt; template <class T> constexpr int32_t enum_size() { return static_cast<int32_t>(*(ndk::enum_range<T>().end() - 1)) + 1; Loading Loading @@ -783,7 +786,16 @@ int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* wor } traceActualDuration(actualTotalDurationNanos); mActualWorkDurations.push_back(std::move(*workDuration)); mActualWorkDurations.push_back(*workDuration); if (kReportBatchSizeCap.has_value()) { // Check if the buffer is larger than the max size, and if it is pop the oldest elements const int overflow = mActualWorkDurations.size() - *kReportBatchSizeCap; if (overflow > 0) { mActualWorkDurations.erase(mActualWorkDurations.begin(), mActualWorkDurations.begin() + overflow); } } if (actualTotalDurationNanos >= mTargetDurationNanos) { // Reset timestamps if we are equal or over the target. Loading Loading @@ -872,12 +884,14 @@ void APerformanceHintManager::layersFromNativeSurfaces(ANativeWindow** windows, std::vector<ASurfaceControl*> controlVec(controls, controls + numSurfaceControls); for (auto&& aSurfaceControl : controlVec) { SurfaceControl* control = reinterpret_cast<SurfaceControl*>(aSurfaceControl); if (control != nullptr) { if (control->isValid()) { out.push_back(control->getHandle()); } } } } } // ===================================== FMQ wrapper implementation Loading Loading @@ -1396,6 +1410,10 @@ void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior) { kForceNewHintBehavior = newBehavior; } void APerformanceHint_setReportBatchSizeCapForTesting(int cap) { kReportBatchSizeCap = cap > 0 ? std::make_optional(cap) : std::nullopt; } void ASessionCreationConfig_setNativeSurfaces(ASessionCreationConfig* config, ANativeWindow** nativeWindows, size_t nativeWindowsSize, Loading
native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +57 −0 Original line number Diff line number Diff line Loading @@ -640,6 +640,63 @@ TEST_F(PerformanceHintTest, TestSupportObject) { EXPECT_EQ(expectedSupportInt, actualSupportInt); } TEST_F(PerformanceHintTest, TestReportActualOverflow) { mClientData.preferredRateNanos = 10000000L; APerformanceHintManager* manager = createManager(); auto&& config = configFromCreator({ .tids = mTids, .targetDuration = 20, }); auto&& session = createSession(manager); hal::WorkDuration duration{.timeStampNanos = 3, .durationNanos = 10, .workPeriodStartTimestampNanos = 1, .cpuDurationNanos = 5, .gpuDurationNanos = 5}; EXPECT_CALL(*mMockSession, reportActualWorkDuration2(_)).Times(2); // Report a duration under the target, to signal the start of good behavior per the rate limiter APerformanceHint_reportActualWorkDuration2(session.get(), reinterpret_cast<AWorkDuration*>(&duration)); // Sleep for longer than preferredUpdateRateNanos. usleep(12000); // Report a duration under the target, to signal continued good behavior per the rate limiter APerformanceHint_reportActualWorkDuration2(session.get(), reinterpret_cast<AWorkDuration*>(&duration)); EXPECT_CALL(*mMockSession, reportActualWorkDuration2(SizeIs(Eq(30)))).Times(1); APerformanceHint_setReportBatchSizeCapForTesting(-1); for (int i = 0; i < 29; ++i) { APerformanceHint_reportActualWorkDuration2(session.get(), reinterpret_cast<AWorkDuration*>(&duration)); } // Sleep for longer than preferredUpdateRateNanos. usleep(12000); APerformanceHint_reportActualWorkDuration2(session.get(), reinterpret_cast<AWorkDuration*>(&duration)); // Enforce that report spam gets capped EXPECT_CALL(*mMockSession, reportActualWorkDuration2(SizeIs(Eq(10)))).Times(1); APerformanceHint_setReportBatchSizeCapForTesting(10); for (int i = 0; i < 29; ++i) { APerformanceHint_reportActualWorkDuration2(session.get(), reinterpret_cast<AWorkDuration*>(&duration)); } // Sleep for longer than preferredUpdateRateNanos. usleep(12000); APerformanceHint_reportActualWorkDuration2(session.get(), reinterpret_cast<AWorkDuration*>(&duration)); } TEST_F(PerformanceHintTest, TestCreatingAutoSession) { // Disable GPU capability for testing mClientData.supportInfo.sessionModes &= ~(1 << (int)hal::SessionMode::AUTO_GPU); Loading