Merge "Track slowest frames" into nyc-dev
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]);
}
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
index 3887e5e..1a4a489 100644
--- a/libs/hwui/JankTracker.h
+++ b/libs/hwui/JankTracker.h
@@ -39,6 +39,11 @@
NUM_BUCKETS,
};
+struct SlowFrame {
+ uint16_t whenHours; // When this occurred in CLOCK_MONOTONIC in hours
+ uint16_t frametimeMs; // How long the frame took in ms
+};
+
// Try to keep as small as possible, should match ASHMEM_SIZE in
// GraphicsStatsService.java
struct ProfileData {
@@ -49,6 +54,8 @@
uint32_t totalFrameCount;
uint32_t jankFrameCount;
nsecs_t statStartTime;
+
+ std::array<SlowFrame, 10> slowestFrames;
};
// TODO: Replace DrawProfiler with this
@@ -71,6 +78,7 @@
private:
void freeData();
void setFrameInterval(nsecs_t frameIntervalNanos);
+ void updateSlowest(const FrameInfo& frame);
static uint32_t findPercentile(const ProfileData* data, int p);
static void dumpData(const ProfileData* data, int fd);
diff --git a/services/core/java/com/android/server/GraphicsStatsService.java b/services/core/java/com/android/server/GraphicsStatsService.java
index 044bb04..e29515f 100644
--- a/services/core/java/com/android/server/GraphicsStatsService.java
+++ b/services/core/java/com/android/server/GraphicsStatsService.java
@@ -51,17 +51,15 @@
* 2) ASHMEM_SIZE (for scratch space used during dumping)
* 3) ASHMEM_SIZE * HISTORY_SIZE
*
- * Currently ASHMEM_SIZE is 256 bytes and HISTORY_SIZE is 20. Assuming
- * the system then also has 10 active rendering processes in the worst case
- * this would end up using under 14KiB (12KiB for the buffers, plus some overhead
- * for userId, pid, package name, and a couple other objects)
+ * This is currently under 16KiB total memory in the worst case of
+ * 20 processes in history + 10 unique active processes.
*
* @hide */
public class GraphicsStatsService extends IGraphicsStats.Stub {
public static final String GRAPHICS_STATS_SERVICE = "graphicsstats";
private static final String TAG = "GraphicsStatsService";
- private static final int ASHMEM_SIZE = 256;
+ private static final int ASHMEM_SIZE = 296;
private static final int HISTORY_SIZE = 20;
private final Context mContext;