Loading core/java/android/os/flags.aconfig +11 −0 Original line number Original line 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 { flag { name: "adpf_gpu_report_actual_work_duration" name: "adpf_gpu_report_actual_work_duration" is_exported: true is_exported: true Loading native/android/libandroid.map.txt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -432,6 +432,7 @@ LIBANDROID_PLATFORM { APerformanceHint_setUseNewLoadHintBehaviorForTesting; APerformanceHint_setUseNewLoadHintBehaviorForTesting; APerformanceHint_closeSessionFromJava; APerformanceHint_closeSessionFromJava; APerformanceHint_createSessionFromJava; APerformanceHint_createSessionFromJava; APerformanceHint_setReportBatchSizeCapForTesting; extern "C++" { extern "C++" { ASurfaceControl_registerSurfaceStatsListener*; ASurfaceControl_registerSurfaceStatsListener*; ASurfaceControl_unregisterSurfaceStatsListener*; ASurfaceControl_unregisterSurfaceStatsListener*; Loading native/android/performance_hint.cpp +21 −3 Original line number Original line Diff line number Diff line Loading @@ -98,6 +98,9 @@ constexpr double kReplenishRate = kMaxLoadHintsPerInterval / static_cast<double> constexpr int64_t kSendHintTimeout = kLoadHintInterval / kMaxLoadHintsPerInterval; constexpr int64_t kSendHintTimeout = kLoadHintInterval / kMaxLoadHintsPerInterval; bool kForceNewHintBehavior = false; bool kForceNewHintBehavior = false; std::optional<size_t> kReportBatchSizeCap = android::os::adpf_cap_max_batch_size() ? std::make_optional(50) : std::nullopt; template <class T> template <class T> constexpr int32_t enum_size() { constexpr int32_t enum_size() { return static_cast<int32_t>(*(ndk::enum_range<T>().end() - 1)) + 1; 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); 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) { if (actualTotalDurationNanos >= mTargetDurationNanos) { // Reset timestamps if we are equal or over the target. // 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); std::vector<ASurfaceControl*> controlVec(controls, controls + numSurfaceControls); for (auto&& aSurfaceControl : controlVec) { for (auto&& aSurfaceControl : controlVec) { SurfaceControl* control = reinterpret_cast<SurfaceControl*>(aSurfaceControl); SurfaceControl* control = reinterpret_cast<SurfaceControl*>(aSurfaceControl); if (control != nullptr) { if (control->isValid()) { if (control->isValid()) { out.push_back(control->getHandle()); out.push_back(control->getHandle()); } } } } } } } } } // ===================================== FMQ wrapper implementation // ===================================== FMQ wrapper implementation Loading Loading @@ -1396,6 +1410,10 @@ void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior) { kForceNewHintBehavior = newBehavior; kForceNewHintBehavior = newBehavior; } } void APerformanceHint_setReportBatchSizeCapForTesting(int cap) { kReportBatchSizeCap = cap > 0 ? std::make_optional(cap) : std::nullopt; } void ASessionCreationConfig_setNativeSurfaces(ASessionCreationConfig* config, void ASessionCreationConfig_setNativeSurfaces(ASessionCreationConfig* config, ANativeWindow** nativeWindows, ANativeWindow** nativeWindows, size_t nativeWindowsSize, size_t nativeWindowsSize, Loading native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +57 −0 Original line number Original line Diff line number Diff line Loading @@ -640,6 +640,63 @@ TEST_F(PerformanceHintTest, TestSupportObject) { EXPECT_EQ(expectedSupportInt, actualSupportInt); 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) { TEST_F(PerformanceHintTest, TestCreatingAutoSession) { // Disable GPU capability for testing // Disable GPU capability for testing mClientData.supportInfo.sessionModes &= ~(1 << (int)hal::SessionMode::AUTO_GPU); mClientData.supportInfo.sessionModes &= ~(1 << (int)hal::SessionMode::AUTO_GPU); Loading Loading
core/java/android/os/flags.aconfig +11 −0 Original line number Original line 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 { flag { name: "adpf_gpu_report_actual_work_duration" name: "adpf_gpu_report_actual_work_duration" is_exported: true is_exported: true Loading
native/android/libandroid.map.txt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -432,6 +432,7 @@ LIBANDROID_PLATFORM { APerformanceHint_setUseNewLoadHintBehaviorForTesting; APerformanceHint_setUseNewLoadHintBehaviorForTesting; APerformanceHint_closeSessionFromJava; APerformanceHint_closeSessionFromJava; APerformanceHint_createSessionFromJava; APerformanceHint_createSessionFromJava; APerformanceHint_setReportBatchSizeCapForTesting; extern "C++" { extern "C++" { ASurfaceControl_registerSurfaceStatsListener*; ASurfaceControl_registerSurfaceStatsListener*; ASurfaceControl_unregisterSurfaceStatsListener*; ASurfaceControl_unregisterSurfaceStatsListener*; Loading
native/android/performance_hint.cpp +21 −3 Original line number Original line Diff line number Diff line Loading @@ -98,6 +98,9 @@ constexpr double kReplenishRate = kMaxLoadHintsPerInterval / static_cast<double> constexpr int64_t kSendHintTimeout = kLoadHintInterval / kMaxLoadHintsPerInterval; constexpr int64_t kSendHintTimeout = kLoadHintInterval / kMaxLoadHintsPerInterval; bool kForceNewHintBehavior = false; bool kForceNewHintBehavior = false; std::optional<size_t> kReportBatchSizeCap = android::os::adpf_cap_max_batch_size() ? std::make_optional(50) : std::nullopt; template <class T> template <class T> constexpr int32_t enum_size() { constexpr int32_t enum_size() { return static_cast<int32_t>(*(ndk::enum_range<T>().end() - 1)) + 1; 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); 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) { if (actualTotalDurationNanos >= mTargetDurationNanos) { // Reset timestamps if we are equal or over the target. // 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); std::vector<ASurfaceControl*> controlVec(controls, controls + numSurfaceControls); for (auto&& aSurfaceControl : controlVec) { for (auto&& aSurfaceControl : controlVec) { SurfaceControl* control = reinterpret_cast<SurfaceControl*>(aSurfaceControl); SurfaceControl* control = reinterpret_cast<SurfaceControl*>(aSurfaceControl); if (control != nullptr) { if (control->isValid()) { if (control->isValid()) { out.push_back(control->getHandle()); out.push_back(control->getHandle()); } } } } } } } } } // ===================================== FMQ wrapper implementation // ===================================== FMQ wrapper implementation Loading Loading @@ -1396,6 +1410,10 @@ void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior) { kForceNewHintBehavior = newBehavior; kForceNewHintBehavior = newBehavior; } } void APerformanceHint_setReportBatchSizeCapForTesting(int cap) { kReportBatchSizeCap = cap > 0 ? std::make_optional(cap) : std::nullopt; } void ASessionCreationConfig_setNativeSurfaces(ASessionCreationConfig* config, void ASessionCreationConfig_setNativeSurfaces(ASessionCreationConfig* config, ANativeWindow** nativeWindows, ANativeWindow** nativeWindows, size_t nativeWindowsSize, size_t nativeWindowsSize, Loading
native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +57 −0 Original line number Original line Diff line number Diff line Loading @@ -640,6 +640,63 @@ TEST_F(PerformanceHintTest, TestSupportObject) { EXPECT_EQ(expectedSupportInt, actualSupportInt); 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) { TEST_F(PerformanceHintTest, TestCreatingAutoSession) { // Disable GPU capability for testing // Disable GPU capability for testing mClientData.supportInfo.sessionModes &= ~(1 << (int)hal::SessionMode::AUTO_GPU); mClientData.supportInfo.sessionModes &= ~(1 << (int)hal::SessionMode::AUTO_GPU); Loading