Loading core/proto/android/service/graphicsstats.proto +4 −1 Original line number Diff line number Diff line Loading @@ -56,7 +56,7 @@ message GraphicsStatsJankSummaryProto { // Number of "missed vsync" events. optional int32 missed_vsync_count = 3; // Number of "high input latency" events. // Number of frames in triple-buffering scenario (high input latency) optional int32 high_input_latency_count = 4; // Number of "slow UI thread" events. Loading @@ -67,6 +67,9 @@ message GraphicsStatsJankSummaryProto { // Number of "slow draw" events. optional int32 slow_draw_count = 7; // Number of frames that missed their deadline (aka, visibly janked) optional int32 missed_deadline_count = 8; } message GraphicsStatsHistogramBucketProto { Loading libs/hwui/JankTracker.cpp +52 −35 Original line number Diff line number Diff line Loading @@ -38,16 +38,27 @@ namespace android { namespace uirenderer { struct Comparison { JankType type; std::function<int64_t(nsecs_t)> computeThreadshold; FrameInfoIndex start; FrameInfoIndex end; }; static const Comparison COMPARISONS[] = { {FrameInfoIndex::IntendedVsync, FrameInfoIndex::Vsync}, {FrameInfoIndex::OldestInputEvent, FrameInfoIndex::Vsync}, {FrameInfoIndex::Vsync, FrameInfoIndex::SyncStart}, {FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart}, {FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::FrameCompleted}, static const std::array<Comparison, 4> COMPARISONS{ Comparison{JankType::kMissedVsync, [](nsecs_t) { return 1; }, FrameInfoIndex::IntendedVsync, FrameInfoIndex::Vsync}, Comparison{JankType::kSlowUI, [](nsecs_t frameInterval) { return static_cast<int64_t>(.5 * frameInterval); }, FrameInfoIndex::Vsync, FrameInfoIndex::SyncStart}, Comparison{JankType::kSlowSync, [](nsecs_t frameInterval) { return static_cast<int64_t>(.2 * frameInterval); }, FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart}, Comparison{JankType::kSlowRT, [](nsecs_t frameInterval) { return static_cast<int64_t>(.75 * frameInterval); }, FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::FrameCompleted}, }; // If the event exceeds 10 seconds throw it away, this isn't a jank event Loading Loading @@ -91,24 +102,10 @@ JankTracker::JankTracker(ProfileDataContainer* globalData, const DisplayInfo& di void JankTracker::setFrameInterval(nsecs_t frameInterval) { mFrameInterval = frameInterval; mThresholds[kMissedVsync] = 1; /* * Due to interpolation and sample rate differences between the touch * panel and the display (example, 85hz touch panel driving a 60hz display) * we call high latency 1.5 * frameinterval * * NOTE: Be careful when tuning this! A theoretical 1,000hz touch panel * on a 60hz display will show kOldestInputEvent - kIntendedVsync of being 15ms * Thus this must always be larger than frameInterval, or it will fail */ mThresholds[kHighInputLatency] = static_cast<int64_t>(1.5 * frameInterval); // Note that these do not add up to 1. This is intentional. It's to deal // with variance in values, and should be sort of an upper-bound on what // is reasonable to expect. mThresholds[kSlowUI] = static_cast<int64_t>(.5 * frameInterval); mThresholds[kSlowSync] = static_cast<int64_t>(.2 * frameInterval); mThresholds[kSlowRT] = static_cast<int64_t>(.75 * frameInterval); for (auto& comparison : COMPARISONS) { mThresholds[comparison.type] = comparison.computeThreadshold(frameInterval); } } void JankTracker::finishFrame(const FrameInfo& frame) { Loading @@ -129,28 +126,48 @@ void JankTracker::finishFrame(const FrameInfo& frame) { totalDuration -= forgiveAmount; } } LOG_ALWAYS_FATAL_IF(totalDuration <= 0, "Impossible totalDuration %" PRId64, totalDuration); mData->reportFrame(totalDuration); (*mGlobalData)->reportFrame(totalDuration); // Keep the fast path as fast as possible. if (CC_LIKELY(totalDuration < mFrameInterval)) { return; } // Only things like Surface.lockHardwareCanvas() are exempt from tracking if (frame[FrameInfoIndex::Flags] & EXEMPT_FRAMES_FLAGS) { if (CC_UNLIKELY(frame[FrameInfoIndex::Flags] & EXEMPT_FRAMES_FLAGS)) { return; } if (totalDuration > mFrameInterval) { mData->reportJank(); (*mGlobalData)->reportJank(); } bool isTripleBuffered = mSwapDeadline > frame[FrameInfoIndex::IntendedVsync]; mSwapDeadline = std::max(mSwapDeadline + mFrameInterval, frame[FrameInfoIndex::IntendedVsync] + mFrameInterval); // If we hit the deadline, cool! if (frame[FrameInfoIndex::FrameCompleted] < mSwapDeadline) { if (isTripleBuffered) { mData->reportJankType(JankType::kHighInputLatency); (*mGlobalData)->reportJankType(JankType::kHighInputLatency); } return; } mData->reportJankType(JankType::kMissedDeadline); (*mGlobalData)->reportJankType(JankType::kMissedDeadline); // Janked, reset the swap deadline nsecs_t jitterNanos = frame[FrameInfoIndex::FrameCompleted] - frame[FrameInfoIndex::Vsync]; nsecs_t lastFrameOffset = jitterNanos % mFrameInterval; mSwapDeadline = frame[FrameInfoIndex::FrameCompleted] - lastFrameOffset + mFrameInterval; for (int i = 0; i < NUM_BUCKETS; i++) { int64_t delta = frame.duration(COMPARISONS[i].start, COMPARISONS[i].end); if (delta >= mThresholds[i] && delta < IGNORE_EXCEEDING) { mData->reportJankType((JankType)i); (*mGlobalData)->reportJankType((JankType)i); for (auto& comparison : COMPARISONS) { int64_t delta = frame.duration(comparison.start, comparison.end); if (delta >= mThresholds[comparison.type] && delta < IGNORE_EXCEEDING) { mData->reportJankType(comparison.type); (*mGlobalData)->reportJankType(comparison.type); } } Loading libs/hwui/JankTracker.h +1 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ private: std::array<int64_t, NUM_BUCKETS> mThresholds; int64_t mFrameInterval; nsecs_t mSwapDeadline; // The amount of time we will erase from the total duration to account // for SF vsync offsets with HWC2 blocking dequeueBuffers. // (Vsync + mDequeueBlockTolerance) is the point at which we expect Loading libs/hwui/ProfileData.cpp +1 −2 Original line number Diff line number Diff line Loading @@ -23,8 +23,7 @@ namespace uirenderer { static const char* JANK_TYPE_NAMES[] = { "Missed Vsync", "High input latency", "Slow UI thread", "Slow bitmap uploads", "Slow issue draw commands", }; "Slow bitmap uploads", "Slow issue draw commands", "Frame deadline missed"}; // The bucketing algorithm controls so to speak // If a frame is <= to this it goes in bucket 0 Loading libs/hwui/ProfileData.h +1 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ enum JankType { kSlowUI, kSlowSync, kSlowRT, kMissedDeadline, // must be last NUM_BUCKETS, Loading Loading
core/proto/android/service/graphicsstats.proto +4 −1 Original line number Diff line number Diff line Loading @@ -56,7 +56,7 @@ message GraphicsStatsJankSummaryProto { // Number of "missed vsync" events. optional int32 missed_vsync_count = 3; // Number of "high input latency" events. // Number of frames in triple-buffering scenario (high input latency) optional int32 high_input_latency_count = 4; // Number of "slow UI thread" events. Loading @@ -67,6 +67,9 @@ message GraphicsStatsJankSummaryProto { // Number of "slow draw" events. optional int32 slow_draw_count = 7; // Number of frames that missed their deadline (aka, visibly janked) optional int32 missed_deadline_count = 8; } message GraphicsStatsHistogramBucketProto { Loading
libs/hwui/JankTracker.cpp +52 −35 Original line number Diff line number Diff line Loading @@ -38,16 +38,27 @@ namespace android { namespace uirenderer { struct Comparison { JankType type; std::function<int64_t(nsecs_t)> computeThreadshold; FrameInfoIndex start; FrameInfoIndex end; }; static const Comparison COMPARISONS[] = { {FrameInfoIndex::IntendedVsync, FrameInfoIndex::Vsync}, {FrameInfoIndex::OldestInputEvent, FrameInfoIndex::Vsync}, {FrameInfoIndex::Vsync, FrameInfoIndex::SyncStart}, {FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart}, {FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::FrameCompleted}, static const std::array<Comparison, 4> COMPARISONS{ Comparison{JankType::kMissedVsync, [](nsecs_t) { return 1; }, FrameInfoIndex::IntendedVsync, FrameInfoIndex::Vsync}, Comparison{JankType::kSlowUI, [](nsecs_t frameInterval) { return static_cast<int64_t>(.5 * frameInterval); }, FrameInfoIndex::Vsync, FrameInfoIndex::SyncStart}, Comparison{JankType::kSlowSync, [](nsecs_t frameInterval) { return static_cast<int64_t>(.2 * frameInterval); }, FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart}, Comparison{JankType::kSlowRT, [](nsecs_t frameInterval) { return static_cast<int64_t>(.75 * frameInterval); }, FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::FrameCompleted}, }; // If the event exceeds 10 seconds throw it away, this isn't a jank event Loading Loading @@ -91,24 +102,10 @@ JankTracker::JankTracker(ProfileDataContainer* globalData, const DisplayInfo& di void JankTracker::setFrameInterval(nsecs_t frameInterval) { mFrameInterval = frameInterval; mThresholds[kMissedVsync] = 1; /* * Due to interpolation and sample rate differences between the touch * panel and the display (example, 85hz touch panel driving a 60hz display) * we call high latency 1.5 * frameinterval * * NOTE: Be careful when tuning this! A theoretical 1,000hz touch panel * on a 60hz display will show kOldestInputEvent - kIntendedVsync of being 15ms * Thus this must always be larger than frameInterval, or it will fail */ mThresholds[kHighInputLatency] = static_cast<int64_t>(1.5 * frameInterval); // Note that these do not add up to 1. This is intentional. It's to deal // with variance in values, and should be sort of an upper-bound on what // is reasonable to expect. mThresholds[kSlowUI] = static_cast<int64_t>(.5 * frameInterval); mThresholds[kSlowSync] = static_cast<int64_t>(.2 * frameInterval); mThresholds[kSlowRT] = static_cast<int64_t>(.75 * frameInterval); for (auto& comparison : COMPARISONS) { mThresholds[comparison.type] = comparison.computeThreadshold(frameInterval); } } void JankTracker::finishFrame(const FrameInfo& frame) { Loading @@ -129,28 +126,48 @@ void JankTracker::finishFrame(const FrameInfo& frame) { totalDuration -= forgiveAmount; } } LOG_ALWAYS_FATAL_IF(totalDuration <= 0, "Impossible totalDuration %" PRId64, totalDuration); mData->reportFrame(totalDuration); (*mGlobalData)->reportFrame(totalDuration); // Keep the fast path as fast as possible. if (CC_LIKELY(totalDuration < mFrameInterval)) { return; } // Only things like Surface.lockHardwareCanvas() are exempt from tracking if (frame[FrameInfoIndex::Flags] & EXEMPT_FRAMES_FLAGS) { if (CC_UNLIKELY(frame[FrameInfoIndex::Flags] & EXEMPT_FRAMES_FLAGS)) { return; } if (totalDuration > mFrameInterval) { mData->reportJank(); (*mGlobalData)->reportJank(); } bool isTripleBuffered = mSwapDeadline > frame[FrameInfoIndex::IntendedVsync]; mSwapDeadline = std::max(mSwapDeadline + mFrameInterval, frame[FrameInfoIndex::IntendedVsync] + mFrameInterval); // If we hit the deadline, cool! if (frame[FrameInfoIndex::FrameCompleted] < mSwapDeadline) { if (isTripleBuffered) { mData->reportJankType(JankType::kHighInputLatency); (*mGlobalData)->reportJankType(JankType::kHighInputLatency); } return; } mData->reportJankType(JankType::kMissedDeadline); (*mGlobalData)->reportJankType(JankType::kMissedDeadline); // Janked, reset the swap deadline nsecs_t jitterNanos = frame[FrameInfoIndex::FrameCompleted] - frame[FrameInfoIndex::Vsync]; nsecs_t lastFrameOffset = jitterNanos % mFrameInterval; mSwapDeadline = frame[FrameInfoIndex::FrameCompleted] - lastFrameOffset + mFrameInterval; for (int i = 0; i < NUM_BUCKETS; i++) { int64_t delta = frame.duration(COMPARISONS[i].start, COMPARISONS[i].end); if (delta >= mThresholds[i] && delta < IGNORE_EXCEEDING) { mData->reportJankType((JankType)i); (*mGlobalData)->reportJankType((JankType)i); for (auto& comparison : COMPARISONS) { int64_t delta = frame.duration(comparison.start, comparison.end); if (delta >= mThresholds[comparison.type] && delta < IGNORE_EXCEEDING) { mData->reportJankType(comparison.type); (*mGlobalData)->reportJankType(comparison.type); } } Loading
libs/hwui/JankTracker.h +1 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ private: std::array<int64_t, NUM_BUCKETS> mThresholds; int64_t mFrameInterval; nsecs_t mSwapDeadline; // The amount of time we will erase from the total duration to account // for SF vsync offsets with HWC2 blocking dequeueBuffers. // (Vsync + mDequeueBlockTolerance) is the point at which we expect Loading
libs/hwui/ProfileData.cpp +1 −2 Original line number Diff line number Diff line Loading @@ -23,8 +23,7 @@ namespace uirenderer { static const char* JANK_TYPE_NAMES[] = { "Missed Vsync", "High input latency", "Slow UI thread", "Slow bitmap uploads", "Slow issue draw commands", }; "Slow bitmap uploads", "Slow issue draw commands", "Frame deadline missed"}; // The bucketing algorithm controls so to speak // If a frame is <= to this it goes in bucket 0 Loading
libs/hwui/ProfileData.h +1 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ enum JankType { kSlowUI, kSlowSync, kSlowRT, kMissedDeadline, // must be last NUM_BUCKETS, Loading