diff options
author | John Reck <jreck@google.com> | 2015-02-19 14:36:50 -0800 |
---|---|---|
committer | John Reck <jreck@google.com> | 2015-02-20 08:27:38 -0800 |
commit | ba6adf66d3c44c0aa2fd8a224862ff1901d64300 (patch) | |
tree | 8172a893f00caa283cf0386dd3d585ca8fac867c /libs/hwui/JankTracker.cpp | |
parent | 004a46eb171bc86a3d40eb8fc6a4d9eed48027c7 (diff) |
Initial attempt at jank-tracking stat collection
Is a bit naive, perhaps overly aggressive, but sorta works
Change-Id: I01a774e00dbe681439c02557d9728ae43c45ce50
Diffstat (limited to 'libs/hwui/JankTracker.cpp')
-rw-r--r-- | libs/hwui/JankTracker.cpp | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp new file mode 100644 index 000000000000..62cb97ce4ecd --- /dev/null +++ b/libs/hwui/JankTracker.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "JankTracker.h" + +#include <cstdio> +#include <inttypes.h> + +namespace android { +namespace uirenderer { + +static const char* JANK_TYPE_NAMES[] = { + "Missed Vsync", + "High input latency", + "Slow UI thread", + "Slow bitmap uploads", + "Slow draw", +}; + +struct Comparison { + FrameInfoIndexEnum start; + FrameInfoIndexEnum end; +}; + +static const Comparison COMPARISONS[] = { + {FrameInfoIndex::kIntendedVsync, FrameInfoIndex::kVsync}, + {FrameInfoIndex::kOldestInputEvent, FrameInfoIndex::kVsync}, + {FrameInfoIndex::kVsync, FrameInfoIndex::kSyncStart}, + {FrameInfoIndex::kSyncStart, FrameInfoIndex::kIssueDrawCommandsStart}, + {FrameInfoIndex::kIssueDrawCommandsStart, FrameInfoIndex::kFrameCompleted}, +}; + +// If the event exceeds 10 seconds throw it away, this isn't a jank event +// it's an ANR and will be handled as such +static const int64_t IGNORE_EXCEEDING = seconds_to_nanoseconds(10); + +/* + * Frames that are exempt from jank metrics. + * First-draw frames, for example, are expected to + * be slow, this is hidden from the user with window animations and + * other tricks + * + * Similarly, we don't track direct-drawing via Surface:lockHardwareCanvas() + * for now + * + * TODO: kSurfaceCanvas can negatively impact other drawing by using up + * time on the RenderThread, figure out how to attribute that as a jank-causer + */ +static const int64_t EXEMPT_FRAMES_FLAGS + = FrameInfoFlags::kWindowLayoutChanged + | FrameInfoFlags::kSurfaceCanvas; + +JankTracker::JankTracker(nsecs_t frameIntervalNanos) { + reset(); + setFrameInterval(frameIntervalNanos); +} + +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); + +} + +void JankTracker::addFrame(const FrameInfo& frame) { + using namespace FrameInfoIndex; + mTotalFrameCount++; + // Fast-path for jank-free frames + int64_t totalDuration = frame[kFrameCompleted] - frame[kIntendedVsync]; + if (CC_LIKELY(totalDuration < mFrameInterval)) { + return; + } + + if (frame[kFlags] & EXEMPT_FRAMES_FLAGS) { + return; + } + + mJankFrameCount++; + + for (int i = 0; i < NUM_BUCKETS; i++) { + int64_t delta = frame[COMPARISONS[i].end] - frame[COMPARISONS[i].start]; + if (delta >= mThresholds[i] && delta < IGNORE_EXCEEDING) { + mBuckets[i].count++; + } + } +} + +void JankTracker::dump(int fd) { + FILE* file = fdopen(fd, "a"); + fprintf(file, "\nFrame stats:"); + fprintf(file, "\n Total frames rendered: %u", mTotalFrameCount); + fprintf(file, "\n Janky frames: %u (%.2f%%)", mJankFrameCount, + (float) mJankFrameCount / (float) mTotalFrameCount * 100.0f); + for (int i = 0; i < NUM_BUCKETS; i++) { + fprintf(file, "\n Number %s: %u", JANK_TYPE_NAMES[i], mBuckets[i].count); + } + fprintf(file, "\n"); + fflush(file); +} + +void JankTracker::reset() { + memset(mBuckets, 0, sizeof(JankBucket) * NUM_BUCKETS); + mTotalFrameCount = 0; + mJankFrameCount = 0; +} + +} /* namespace uirenderer */ +} /* namespace android */ |