Loading libs/hwui/JankTracker.cpp +46 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ #include <cstdio> #include <errno.h> #include <inttypes.h> #include <limits> #include <cmath> #include <sys/mman.h> namespace android { Loading Loading @@ -202,6 +204,40 @@ void JankTracker::setFrameInterval(nsecs_t frameInterval) { } 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 Loading @@ -215,6 +251,11 @@ void JankTracker::addFrame(const FrameInfo& frame) { 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; } Loading Loading @@ -247,6 +288,11 @@ void JankTracker::dumpData(const ProfileData* data, int fd) { 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]); } Loading libs/hwui/JankTracker.h +8 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,11 @@ enum JankType { 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 { Loading @@ -49,6 +54,8 @@ struct ProfileData { uint32_t totalFrameCount; uint32_t jankFrameCount; nsecs_t statStartTime; std::array<SlowFrame, 10> slowestFrames; }; // TODO: Replace DrawProfiler with this Loading @@ -71,6 +78,7 @@ public: 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); Loading services/core/java/com/android/server/GraphicsStatsService.java +3 −5 Original line number Diff line number Diff line Loading @@ -51,17 +51,15 @@ import java.util.ArrayList; * 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; Loading Loading
libs/hwui/JankTracker.cpp +46 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ #include <cstdio> #include <errno.h> #include <inttypes.h> #include <limits> #include <cmath> #include <sys/mman.h> namespace android { Loading Loading @@ -202,6 +204,40 @@ void JankTracker::setFrameInterval(nsecs_t frameInterval) { } 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 Loading @@ -215,6 +251,11 @@ void JankTracker::addFrame(const FrameInfo& frame) { 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; } Loading Loading @@ -247,6 +288,11 @@ void JankTracker::dumpData(const ProfileData* data, int fd) { 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]); } Loading
libs/hwui/JankTracker.h +8 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,11 @@ enum JankType { 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 { Loading @@ -49,6 +54,8 @@ struct ProfileData { uint32_t totalFrameCount; uint32_t jankFrameCount; nsecs_t statStartTime; std::array<SlowFrame, 10> slowestFrames; }; // TODO: Replace DrawProfiler with this Loading @@ -71,6 +78,7 @@ public: 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); Loading
services/core/java/com/android/server/GraphicsStatsService.java +3 −5 Original line number Diff line number Diff line Loading @@ -51,17 +51,15 @@ import java.util.ArrayList; * 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; Loading