Teach JankTracker about new swap behaviors
am: 2d5b8d7392
Change-Id: I28afc748f8a43944863bd752c3bd2cb983d19c23
This commit is contained in:
@@ -113,6 +113,10 @@ hwui_cflags := \
|
||||
-DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\" \
|
||||
-Wall -Wno-unused-parameter -Wunreachable-code -Werror
|
||||
|
||||
ifeq ($(TARGET_USES_HWC2),true)
|
||||
hwui_cflags += -DUSE_HWC2
|
||||
endif
|
||||
|
||||
# GCC false-positives on this warning, and since we -Werror that's
|
||||
# a problem
|
||||
hwui_cflags += -Wno-free-nonheap-object
|
||||
|
||||
@@ -35,8 +35,14 @@ const std::string FrameInfoNames[] = {
|
||||
"IssueDrawCommandsStart",
|
||||
"SwapBuffers",
|
||||
"FrameCompleted",
|
||||
"DequeueBufferDuration",
|
||||
"QueueBufferDuration",
|
||||
};
|
||||
|
||||
static_assert((sizeof(FrameInfoNames)/sizeof(FrameInfoNames[0]))
|
||||
== static_cast<int>(FrameInfoIndex::NumIndexes),
|
||||
"size mismatch: FrameInfoNames doesn't match the enum!");
|
||||
|
||||
void FrameInfo::importUiThreadInfo(int64_t* info) {
|
||||
memcpy(mFrameInfo, info, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
|
||||
}
|
||||
|
||||
@@ -48,6 +48,9 @@ enum class FrameInfoIndex {
|
||||
SwapBuffers,
|
||||
FrameCompleted,
|
||||
|
||||
DequeueBufferDuration,
|
||||
QueueBufferDuration,
|
||||
|
||||
// Must be the last value!
|
||||
NumIndexes
|
||||
};
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "JankTracker.h"
|
||||
|
||||
#include "Properties.h"
|
||||
#include "utils/TimeUtils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cutils/ashmem.h>
|
||||
@@ -119,11 +120,27 @@ static uint32_t frameTimeForFrameCountIndex(uint32_t index) {
|
||||
return index;
|
||||
}
|
||||
|
||||
JankTracker::JankTracker(nsecs_t frameIntervalNanos) {
|
||||
JankTracker::JankTracker(const DisplayInfo& displayInfo) {
|
||||
// By default this will use malloc memory. It may be moved later to ashmem
|
||||
// if there is shared space for it and a request comes in to do that.
|
||||
mData = new ProfileData;
|
||||
reset();
|
||||
nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1_s / displayInfo.fps);
|
||||
#if USE_HWC2
|
||||
nsecs_t sfOffset = frameIntervalNanos - (displayInfo.presentationDeadline - 1_ms);
|
||||
nsecs_t offsetDelta = sfOffset - displayInfo.appVsyncOffset;
|
||||
// There are two different offset cases. If the offsetDelta is positive
|
||||
// and small, then the intention is to give apps extra time by leveraging
|
||||
// pipelining between the UI & RT threads. If the offsetDelta is large or
|
||||
// negative, the intention is to subtract time from the total duration
|
||||
// in which case we can't afford to wait for dequeueBuffer blockage.
|
||||
if (offsetDelta <= 4_ms && offsetDelta >= 0) {
|
||||
// SF will begin composition at VSYNC-app + offsetDelta. If we are triple
|
||||
// buffered, this is the expected time at which dequeueBuffer will
|
||||
// return due to the staggering of VSYNC-app & VSYNC-sf.
|
||||
mDequeueTimeForgiveness = offsetDelta + 4_ms;
|
||||
}
|
||||
#endif
|
||||
setFrameInterval(frameIntervalNanos);
|
||||
}
|
||||
|
||||
@@ -213,6 +230,19 @@ void JankTracker::addFrame(const FrameInfo& frame) {
|
||||
mData->totalFrameCount++;
|
||||
// Fast-path for jank-free frames
|
||||
int64_t totalDuration = frame.duration(sFrameStart, FrameInfoIndex::FrameCompleted);
|
||||
if (mDequeueTimeForgiveness
|
||||
&& frame[FrameInfoIndex::DequeueBufferDuration] > 500_us) {
|
||||
nsecs_t expectedDequeueDuration =
|
||||
mDequeueTimeForgiveness + frame[FrameInfoIndex::Vsync]
|
||||
- frame[FrameInfoIndex::IssueDrawCommandsStart];
|
||||
if (expectedDequeueDuration > 0) {
|
||||
// Forgive only up to the expected amount, but not more than
|
||||
// the actual time spent blocked.
|
||||
nsecs_t forgiveAmount = std::min(expectedDequeueDuration,
|
||||
frame[FrameInfoIndex::DequeueBufferDuration]);
|
||||
totalDuration -= forgiveAmount;
|
||||
}
|
||||
}
|
||||
uint32_t framebucket = frameCountIndexForFrameTime(totalDuration);
|
||||
// Keep the fast path as fast as possible.
|
||||
if (CC_LIKELY(totalDuration < mFrameInterval)) {
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "utils/RingBuffer.h"
|
||||
|
||||
#include <cutils/compiler.h>
|
||||
#include <ui/DisplayInfo.h>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
@@ -56,7 +57,7 @@ struct ProfileData {
|
||||
// TODO: Replace DrawProfiler with this
|
||||
class JankTracker {
|
||||
public:
|
||||
JankTracker(nsecs_t frameIntervalNanos);
|
||||
JankTracker(const DisplayInfo& displayInfo);
|
||||
~JankTracker();
|
||||
|
||||
void addFrame(const FrameInfo& frame);
|
||||
@@ -79,6 +80,14 @@ private:
|
||||
|
||||
std::array<int64_t, NUM_BUCKETS> mThresholds;
|
||||
int64_t mFrameInterval;
|
||||
// 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
|
||||
// SF to have released the buffer normally, so we will forgive up to that
|
||||
// point in time by comparing to (IssueDrawCommandsStart + DequeueDuration)
|
||||
// This is only used if we are in pipelined mode and are using HWC2,
|
||||
// otherwise it's 0.
|
||||
nsecs_t mDequeueTimeForgiveness = 0;
|
||||
ProfileData* mData;
|
||||
bool mIsMapped = false;
|
||||
};
|
||||
|
||||
@@ -67,7 +67,7 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent,
|
||||
, mEglManager(thread.eglManager())
|
||||
, mOpaque(!translucent)
|
||||
, mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
|
||||
, mJankTracker(thread.timeLord().frameIntervalNanos())
|
||||
, mJankTracker(thread.mainDisplayInfo())
|
||||
, mProfiler(mFrames)
|
||||
, mContentDrawBounds(0, 0, 0, 0) {
|
||||
mRenderNodes.emplace_back(rootRenderNode);
|
||||
@@ -286,11 +286,6 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
|
||||
if (CC_LIKELY(mSwapHistory.size())) {
|
||||
nsecs_t latestVsync = mRenderThread.timeLord().latestVsync();
|
||||
SwapHistory& lastSwap = mSwapHistory.back();
|
||||
int durationUs;
|
||||
mNativeSurface->query(NATIVE_WINDOW_LAST_DEQUEUE_DURATION, &durationUs);
|
||||
lastSwap.dequeueDuration = us2ns(durationUs);
|
||||
mNativeSurface->query(NATIVE_WINDOW_LAST_QUEUE_DURATION, &durationUs);
|
||||
lastSwap.queueDuration = us2ns(durationUs);
|
||||
nsecs_t vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync);
|
||||
// The slight fudge-factor is to deal with cases where
|
||||
// the vsync was estimated due to being slow handling the signal.
|
||||
@@ -567,6 +562,15 @@ void CanvasContext::draw() {
|
||||
swap.damage = screenDirty;
|
||||
swap.swapCompletedTime = systemTime(CLOCK_MONOTONIC);
|
||||
swap.vsyncTime = mRenderThread.timeLord().latestVsync();
|
||||
int durationUs;
|
||||
mNativeSurface->query(NATIVE_WINDOW_LAST_DEQUEUE_DURATION, &durationUs);
|
||||
swap.dequeueDuration = us2ns(durationUs);
|
||||
mNativeSurface->query(NATIVE_WINDOW_LAST_QUEUE_DURATION, &durationUs);
|
||||
swap.queueDuration = us2ns(durationUs);
|
||||
mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration)
|
||||
= swap.dequeueDuration;
|
||||
mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration)
|
||||
= swap.queueDuration;
|
||||
mHaveNewSurface = false;
|
||||
mFrameNumber = -1;
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ void RenderThread::initThreadLocals() {
|
||||
initializeDisplayEventReceiver();
|
||||
mEglManager = new EglManager(*this);
|
||||
mRenderState = new RenderState(*this);
|
||||
mJankTracker = new JankTracker(frameIntervalNanos);
|
||||
mJankTracker = new JankTracker(mDisplayInfo);
|
||||
}
|
||||
|
||||
int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
|
||||
|
||||
@@ -21,10 +21,18 @@
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
constexpr nsecs_t operator"" _s (unsigned long long s) {
|
||||
return seconds_to_nanoseconds(s);
|
||||
}
|
||||
|
||||
constexpr nsecs_t operator"" _ms (unsigned long long ms) {
|
||||
return milliseconds_to_nanoseconds(ms);
|
||||
}
|
||||
|
||||
constexpr nsecs_t operator"" _us (unsigned long long us) {
|
||||
return microseconds_to_nanoseconds(us);
|
||||
}
|
||||
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user