Track slowest frames

Fixes: 27795291

Track the 10 slowest frames over the last 24 hours
to try and give approximate insight into total system health.

Change-Id: I8aa646cef0bea185d46b3c78478266bc01d17fd7
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index c305f65..2246cf9c 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -21,6 +21,8 @@
 #include <cstdio>
 #include <errno.h>
 #include <inttypes.h>
+#include <limits>
+#include <cmath>
 #include <sys/mman.h>
 
 namespace android {
@@ -202,6 +204,40 @@
 
 }
 
+static bool shouldReplace(SlowFrame& existing, SlowFrame& candidate) {
+    if (candidate.whenHours - existing.whenHours >= 24) {
+        // If the old slowframe is over 24 hours older than the candidate,
+        // replace it. It's too stale
+        return true;
+    }
+    if (candidate.frametimeMs > existing.frametimeMs) {
+        return true;
+    }
+    return false;
+}
+
+void JankTracker::updateSlowest(const FrameInfo& frame) {
+    uint16_t durationMs = static_cast<uint16_t>(std::min(
+            ns2ms(frame[FrameInfoIndex::FrameCompleted] - frame[FrameInfoIndex::IntendedVsync]),
+            static_cast<nsecs_t>(std::numeric_limits<uint16_t>::max())));
+    uint16_t startHours = static_cast<uint16_t>(std::lround(
+            ns2s(frame[FrameInfoIndex::IntendedVsync]) / 3600.0f));
+    SlowFrame* toReplace = nullptr;
+    SlowFrame thisFrame{startHours, durationMs};
+    // First find the best candidate for replacement
+    for (SlowFrame& existing : mData->slowestFrames) {
+        // If we should replace the current data with the replacement candidate,
+        // it means the current data is worse than the replacement candidate
+        if (!toReplace || shouldReplace(existing, *toReplace)) {
+            toReplace = &existing;
+        }
+    }
+    // Now see if we should replace it
+    if (shouldReplace(*toReplace, thisFrame)) {
+        *toReplace = thisFrame;
+    }
+}
+
 void JankTracker::addFrame(const FrameInfo& frame) {
     mData->totalFrameCount++;
     // Fast-path for jank-free frames
@@ -215,6 +251,11 @@
         return;
     }
 
+    // For slowest frames we are still interested in frames that are otherwise
+    // exempt (such as first-draw). Although those frames don't directly impact
+    // smoothness, they do impact responsiveness.
+    updateSlowest(frame);
+
     if (frame[FrameInfoIndex::Flags] & EXEMPT_FRAMES_FLAGS) {
         return;
     }
@@ -247,6 +288,11 @@
     dprintf(fd, "\n90th percentile: %ums", findPercentile(data, 90));
     dprintf(fd, "\n95th percentile: %ums", findPercentile(data, 95));
     dprintf(fd, "\n99th percentile: %ums", findPercentile(data, 99));
+    dprintf(fd, "\nSlowest frames over last 24h: ");
+    for (auto& slowFrame : data->slowestFrames) {
+        if (!slowFrame.frametimeMs) continue;
+        dprintf(fd, "%ums ", slowFrame.frametimeMs);
+    }
     for (int i = 0; i < NUM_BUCKETS; i++) {
         dprintf(fd, "\nNumber %s: %u", JANK_TYPE_NAMES[i], data->jankTypeCounts[i]);
     }