SF: Add composition strategy prediction stats

Track number of frames we attempted to predict
the composition strategy and the number of
frames it was successful. This should only be used
as a convenient way to debug locally. Composition
strategy prediction hit and misses are also tracked
via trace tags and can be extracted for metrics.

Enable stats: adb shell su root dumpsys SurfaceFlinger --timestats -enable
Dump stats: adb shell su root dumpsys SurfaceFlinger --timestats -dump -maxlayers 0
Clear stats: adb shell su root dumpsys SurfaceFlinger --timestats -clear

Test: adb shell
Bug: 220031739
Change-Id: Ifc35efa7ce110e82041f529b58acebfa1c325f36
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index b1a2bda..e5a9dd4 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -321,22 +321,19 @@
     mTimeStats.missedFramesLegacy++;
 }
 
-void TimeStats::incrementClientCompositionFrames() {
-    if (!mEnabled.load()) return;
+void TimeStats::pushCompositionStrategyState(const TimeStats::ClientCompositionRecord& record) {
+    if (!mEnabled.load() || !record.hasInterestingData()) {
+        return;
+    }
 
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.clientCompositionFramesLegacy++;
-}
-
-void TimeStats::incrementClientCompositionReusedFrames() {
-    if (!mEnabled.load()) return;
-
-    ATRACE_CALL();
-
-    std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.clientCompositionReusedFramesLegacy++;
+    if (record.changed) mTimeStats.compositionStrategyChangesLegacy++;
+    if (record.hadClientComposition) mTimeStats.clientCompositionFramesLegacy++;
+    if (record.reused) mTimeStats.clientCompositionReusedFramesLegacy++;
+    if (record.predicted) mTimeStats.compositionStrategyPredictedLegacy++;
+    if (record.predictionSucceeded) mTimeStats.compositionStrategyPredictionSucceededLegacy++;
 }
 
 void TimeStats::incrementRefreshRateSwitches() {
@@ -348,15 +345,6 @@
     mTimeStats.refreshRateSwitchesLegacy++;
 }
 
-void TimeStats::incrementCompositionStrategyChanges() {
-    if (!mEnabled.load()) return;
-
-    ATRACE_CALL();
-
-    std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.compositionStrategyChangesLegacy++;
-}
-
 void TimeStats::recordDisplayEventConnectionCount(int32_t count) {
     if (!mEnabled.load()) return;
 
@@ -1062,8 +1050,10 @@
     mTimeStats.missedFramesLegacy = 0;
     mTimeStats.clientCompositionFramesLegacy = 0;
     mTimeStats.clientCompositionReusedFramesLegacy = 0;
-    mTimeStats.refreshRateSwitchesLegacy = 0;
     mTimeStats.compositionStrategyChangesLegacy = 0;
+    mTimeStats.compositionStrategyPredictedLegacy = 0;
+    mTimeStats.compositionStrategyPredictionSucceededLegacy = 0;
+    mTimeStats.refreshRateSwitchesLegacy = 0;
     mTimeStats.displayEventConnectionsCountLegacy = 0;
     mTimeStats.displayOnTimeLegacy = 0;
     mTimeStats.presentToPresentLegacy.hist.clear();
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 77c7973..7a159b8 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -45,7 +45,7 @@
     virtual ~TimeStats() = default;
 
     // Process a pull request from statsd.
-    virtual bool onPullAtom(const int atomId, std::string* pulledData);
+    virtual bool onPullAtom(const int atomId, std::string* pulledData) = 0;
 
     virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
     virtual bool isEnabled() = 0;
@@ -53,14 +53,8 @@
 
     virtual void incrementTotalFrames() = 0;
     virtual void incrementMissedFrames() = 0;
-    virtual void incrementClientCompositionFrames() = 0;
-    virtual void incrementClientCompositionReusedFrames() = 0;
     // Increments the number of times the display refresh rate changed.
     virtual void incrementRefreshRateSwitches() = 0;
-    // Increments the number of changes in composition strategy
-    // The intention is to reflect the number of changes between hwc and gpu
-    // composition, where "gpu composition" may also include mixed composition.
-    virtual void incrementCompositionStrategyChanges() = 0;
     // Records the most up-to-date count of display event connections.
     // The stored count will be the maximum ever recoded.
     virtual void recordDisplayEventConnectionCount(int32_t count) = 0;
@@ -158,6 +152,24 @@
         }
     };
 
+    struct ClientCompositionRecord {
+        // Frame had client composition or mixed composition
+        bool hadClientComposition = false;
+        // Composition changed between hw composition and mixed/client composition
+        bool changed = false;
+        // Frame reused the client composition result from a previous frame
+        bool reused = false;
+        // Composition strategy predicted for frame
+        bool predicted = false;
+        // Composition strategy prediction succeeded
+        bool predictionSucceeded = false;
+
+        // Whether there is data we want to record.
+        bool hasInterestingData() const {
+            return hadClientComposition || changed || reused || predicted;
+        }
+    };
+
     virtual void incrementJankyFrames(const JankyFramesInfo& info) = 0;
     // Clean up the layer record
     virtual void onDestroy(int32_t layerId) = 0;
@@ -169,6 +181,7 @@
     // Source of truth is RefrehRateStats.
     virtual void recordRefreshRate(uint32_t fps, nsecs_t duration) = 0;
     virtual void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) = 0;
+    virtual void pushCompositionStrategyState(const ClientCompositionRecord&) = 0;
 };
 
 namespace impl {
@@ -236,10 +249,7 @@
 
     void incrementTotalFrames() override;
     void incrementMissedFrames() override;
-    void incrementClientCompositionFrames() override;
-    void incrementClientCompositionReusedFrames() override;
     void incrementRefreshRateSwitches() override;
-    void incrementCompositionStrategyChanges() override;
     void recordDisplayEventConnectionCount(int32_t count) override;
 
     void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) override;
@@ -275,6 +285,8 @@
     void recordRefreshRate(uint32_t fps, nsecs_t duration) override;
     void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) override;
 
+    void pushCompositionStrategyState(const ClientCompositionRecord&) override;
+
     static const size_t MAX_NUM_TIME_RECORDS = 64;
 
 private:
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 69afa2a..cf1ca65 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -143,6 +143,14 @@
                   clientCompositionReusedFramesLegacy);
     StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitchesLegacy);
     StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChangesLegacy);
+    StringAppendF(&result, "compositionStrategyPredicted = %d\n",
+                  compositionStrategyPredictedLegacy);
+    StringAppendF(&result, "compositionStrategyPredictionSucceeded = %d\n",
+                  compositionStrategyPredictionSucceededLegacy);
+    StringAppendF(&result, "compositionStrategyPredictionFailed = %d\n",
+                  compositionStrategyPredictedLegacy -
+                          compositionStrategyPredictionSucceededLegacy);
+
     StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTimeLegacy);
     StringAppendF(&result, "displayConfigStats is as below:\n");
     for (const auto& [fps, duration] : refreshRateStatsLegacy) {
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 438561c..237ae8d 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -178,6 +178,8 @@
         Histogram frameDurationLegacy;
         Histogram renderEngineTimingLegacy;
         std::unordered_map<uint32_t, nsecs_t> refreshRateStatsLegacy;
+        int32_t compositionStrategyPredictedLegacy = 0;
+        int32_t compositionStrategyPredictionSucceededLegacy = 0;
 
         std::unordered_map<TimelineStatsKey, TimelineStats, TimelineStatsKey::Hasher> stats;