Teach JankTracker about new swap behaviors

am: 2d5b8d7392

Change-Id: I28afc748f8a43944863bd752c3bd2cb983d19c23
This commit is contained in:
John Reck
2016-07-29 16:31:38 +00:00
committed by android-build-merger
8 changed files with 73 additions and 9 deletions

View File

@@ -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

View File

@@ -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));
}

View File

@@ -48,6 +48,9 @@ enum class FrameInfoIndex {
SwapBuffers,
FrameCompleted,
DequeueBufferDuration,
QueueBufferDuration,
// Must be the last value!
NumIndexes
};

View File

@@ -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)) {

View File

@@ -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;
};

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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 */