1ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck/*
2ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck * Copyright (C) 2015 The Android Open Source Project
3ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck *
4ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck * Licensed under the Apache License, Version 2.0 (the "License");
5ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck * you may not use this file except in compliance with the License.
6ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck * You may obtain a copy of the License at
7ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck *
8ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck *      http://www.apache.org/licenses/LICENSE-2.0
9ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck *
10ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck * Unless required by applicable law or agreed to in writing, software
11ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck * distributed under the License is distributed on an "AS IS" BASIS,
12ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck * See the License for the specific language governing permissions and
14ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck * limitations under the License.
15ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck */
16ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck#include "JankTracker.h"
17ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
18c7cd9cf25d9775446ffcb6b5f20b0a4c1e3c99c5John Reck#include "Properties.h"
19c7cd9cf25d9775446ffcb6b5f20b0a4c1e3c99c5John Reck
20e70c5754d01f2ab0ff47ea3eabaa88aca5ed2a36John Reck#include <algorithm>
21edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck#include <cutils/ashmem.h>
22edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck#include <cutils/log.h>
23ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck#include <cstdio>
24edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck#include <errno.h>
25ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck#include <inttypes.h>
265ed587f25b367cfd1f68279d6cd96ee403bd6f34John Reck#include <limits>
275ed587f25b367cfd1f68279d6cd96ee403bd6f34John Reck#include <cmath>
28edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck#include <sys/mman.h>
29ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
30ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Recknamespace android {
31ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Recknamespace uirenderer {
32ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
33ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reckstatic const char* JANK_TYPE_NAMES[] = {
34ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck        "Missed Vsync",
35ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck        "High input latency",
36ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck        "Slow UI thread",
37ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck        "Slow bitmap uploads",
38be3fba05e823f740f65b2679929347dc3dd282adJohn Reck        "Slow issue draw commands",
39ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck};
40ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
41ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reckstruct Comparison {
42c87be99c6ead0720a8918ea38ce3b25e5c49e1c6John Reck    FrameInfoIndex start;
43c87be99c6ead0720a8918ea38ce3b25e5c49e1c6John Reck    FrameInfoIndex end;
44ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck};
45ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
46ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reckstatic const Comparison COMPARISONS[] = {
471b54fb27ac48495ed0b33868fda5776fb49fe0f3Chris Craik        {FrameInfoIndex::IntendedVsync, FrameInfoIndex::Vsync},
481b54fb27ac48495ed0b33868fda5776fb49fe0f3Chris Craik        {FrameInfoIndex::OldestInputEvent, FrameInfoIndex::Vsync},
491b54fb27ac48495ed0b33868fda5776fb49fe0f3Chris Craik        {FrameInfoIndex::Vsync, FrameInfoIndex::SyncStart},
501b54fb27ac48495ed0b33868fda5776fb49fe0f3Chris Craik        {FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart},
511b54fb27ac48495ed0b33868fda5776fb49fe0f3Chris Craik        {FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::FrameCompleted},
52ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck};
53ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
54ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck// If the event exceeds 10 seconds throw it away, this isn't a jank event
55ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck// it's an ANR and will be handled as such
56ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reckstatic const int64_t IGNORE_EXCEEDING = seconds_to_nanoseconds(10);
57ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
58ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck/*
59660108075e61d7b7e6c138000890011510d5b079John Reck * We don't track direct-drawing via Surface:lockHardwareCanvas()
60ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck * for now
61ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck *
62ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck * TODO: kSurfaceCanvas can negatively impact other drawing by using up
63ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck * time on the RenderThread, figure out how to attribute that as a jank-causer
64ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck */
65660108075e61d7b7e6c138000890011510d5b079John Reckstatic const int64_t EXEMPT_FRAMES_FLAGS = FrameInfoFlags::SurfaceCanvas;
66ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
67edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck// The bucketing algorithm controls so to speak
68edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck// If a frame is <= to this it goes in bucket 0
69660108075e61d7b7e6c138000890011510d5b079John Reckstatic const uint32_t kBucketMinThreshold = 5;
70edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck// If a frame is > this, start counting in increments of 2ms
71edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reckstatic const uint32_t kBucket2msIntervals = 32;
72edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck// If a frame is > this, start counting in increments of 4ms
73edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reckstatic const uint32_t kBucket4msIntervals = 48;
74edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck
75c7cd9cf25d9775446ffcb6b5f20b0a4c1e3c99c5John Reck// For testing purposes to try and eliminate test infra overhead we will
76c7cd9cf25d9775446ffcb6b5f20b0a4c1e3c99c5John Reck// consider any unknown delay of frame start as part of the test infrastructure
77c7cd9cf25d9775446ffcb6b5f20b0a4c1e3c99c5John Reck// and filter it out of the frame profile data
78c7cd9cf25d9775446ffcb6b5f20b0a4c1e3c99c5John Reckstatic FrameInfoIndex sFrameStart = FrameInfoIndex::IntendedVsync;
79c7cd9cf25d9775446ffcb6b5f20b0a4c1e3c99c5John Reck
80660108075e61d7b7e6c138000890011510d5b079John Reck// The interval of the slow frame histogram
81660108075e61d7b7e6c138000890011510d5b079John Reckstatic const uint32_t kSlowFrameBucketIntervalMs = 50;
82660108075e61d7b7e6c138000890011510d5b079John Reck// The start point of the slow frame bucket in ms
83660108075e61d7b7e6c138000890011510d5b079John Reckstatic const uint32_t kSlowFrameBucketStartMs = 150;
84660108075e61d7b7e6c138000890011510d5b079John Reck
85edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck// This will be called every frame, performance sensitive
86edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck// Uses bit twiddling to avoid branching while achieving the packing desired
87660108075e61d7b7e6c138000890011510d5b079John Reckstatic uint32_t frameCountIndexForFrameTime(nsecs_t frameTime) {
88edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    uint32_t index = static_cast<uint32_t>(ns2ms(frameTime));
89edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    // If index > kBucketMinThreshold mask will be 0xFFFFFFFF as a result
90edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    // of negating 1 (twos compliment, yaay) else mask will be 0
91edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    uint32_t mask = -(index > kBucketMinThreshold);
92edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    // If index > threshold, this will essentially perform:
93edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    // amountAboveThreshold = index - threshold;
94edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    // index = threshold + (amountAboveThreshold / 2)
95edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    // However if index is <= this will do nothing. It will underflow, do
96edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    // a right shift by 0 (no-op), then overflow back to the original value
97edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    index = ((index - kBucket4msIntervals) >> (index > kBucket4msIntervals))
98edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck            + kBucket4msIntervals;
99edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    index = ((index - kBucket2msIntervals) >> (index > kBucket2msIntervals))
100edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck            + kBucket2msIntervals;
101edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    // If index was < minThreshold at the start of all this it's going to
102edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    // be a pretty garbage value right now. However, mask is 0 so we'll end
103edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    // up with the desired result of 0.
104edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    index = (index - kBucketMinThreshold) & mask;
105660108075e61d7b7e6c138000890011510d5b079John Reck    return index;
106edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck}
107edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck
108edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck// Only called when dumping stats, less performance sensitive
109edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reckstatic uint32_t frameTimeForFrameCountIndex(uint32_t index) {
110edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    index = index + kBucketMinThreshold;
111edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    if (index > kBucket2msIntervals) {
112edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        index += (index - kBucket2msIntervals);
113edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    }
114edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    if (index > kBucket4msIntervals) {
115edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        // This works because it was already doubled by the above if
116edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        // 1 is added to shift slightly more towards the middle of the bucket
117edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        index += (index - kBucket4msIntervals) + 1;
118edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    }
119edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    return index;
120edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck}
121edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck
122ba6adf66d3c44c0aa2fd8a224862ff1901d64300John ReckJankTracker::JankTracker(nsecs_t frameIntervalNanos) {
123edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    // By default this will use malloc memory. It may be moved later to ashmem
124edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    // if there is shared space for it and a request comes in to do that.
125edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    mData = new ProfileData;
126ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    reset();
127ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    setFrameInterval(frameIntervalNanos);
128ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck}
129ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
130edc524c90506d80e0fc5fb67e8de7b8f3ef53439John ReckJankTracker::~JankTracker() {
131edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    freeData();
132edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck}
133edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck
134edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reckvoid JankTracker::freeData() {
135edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    if (mIsMapped) {
136edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        munmap(mData, sizeof(ProfileData));
137edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    } else {
138edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        delete mData;
139edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    }
140edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    mIsMapped = false;
141edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    mData = nullptr;
142edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck}
143edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck
144edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reckvoid JankTracker::switchStorageToAshmem(int ashmemfd) {
145edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    int regionSize = ashmem_get_size_region(ashmemfd);
146edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    if (regionSize < static_cast<int>(sizeof(ProfileData))) {
147edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        ALOGW("Ashmem region is too small! Received %d, required %u",
14898fa0a322e6bf4f6b543487c820955d8598193b5John Reck                regionSize, static_cast<unsigned int>(sizeof(ProfileData)));
149edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        return;
150edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    }
151edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    ProfileData* newData = reinterpret_cast<ProfileData*>(
152edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck            mmap(NULL, sizeof(ProfileData), PROT_READ | PROT_WRITE,
153edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck            MAP_SHARED, ashmemfd, 0));
154edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    if (newData == MAP_FAILED) {
155edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        int err = errno;
156edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        ALOGW("Failed to move profile data to ashmem fd %d, error = %d",
157edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck                ashmemfd, err);
158edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        return;
159edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    }
160edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck
161edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    // The new buffer may have historical data that we want to build on top of
162edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    // But let's make sure we don't overflow Just In Case
163edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    uint32_t divider = 0;
164edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    if (newData->totalFrameCount > (1 << 24)) {
165edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        divider = 4;
166edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    }
167edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    for (size_t i = 0; i < mData->jankTypeCounts.size(); i++) {
168edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        newData->jankTypeCounts[i] >>= divider;
169edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        newData->jankTypeCounts[i] += mData->jankTypeCounts[i];
170edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    }
171edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    for (size_t i = 0; i < mData->frameCounts.size(); i++) {
172edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        newData->frameCounts[i] >>= divider;
173edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        newData->frameCounts[i] += mData->frameCounts[i];
174edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    }
175edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    newData->jankFrameCount >>= divider;
176edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    newData->jankFrameCount += mData->jankFrameCount;
177edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    newData->totalFrameCount >>= divider;
178edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    newData->totalFrameCount += mData->totalFrameCount;
179379f264bb62ace2cf2053d4765307234bf66552fJohn Reck    if (newData->statStartTime > mData->statStartTime
180379f264bb62ace2cf2053d4765307234bf66552fJohn Reck            || newData->statStartTime == 0) {
181379f264bb62ace2cf2053d4765307234bf66552fJohn Reck        newData->statStartTime = mData->statStartTime;
182379f264bb62ace2cf2053d4765307234bf66552fJohn Reck    }
183edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck
184edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    freeData();
185edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    mData = newData;
186edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    mIsMapped = true;
187edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck}
188edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck
189ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reckvoid JankTracker::setFrameInterval(nsecs_t frameInterval) {
190ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    mFrameInterval = frameInterval;
191ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    mThresholds[kMissedVsync] = 1;
192ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    /*
193ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck     * Due to interpolation and sample rate differences between the touch
194ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck     * panel and the display (example, 85hz touch panel driving a 60hz display)
195ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck     * we call high latency 1.5 * frameinterval
196ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck     *
197ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck     * NOTE: Be careful when tuning this! A theoretical 1,000hz touch panel
198ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck     * on a 60hz display will show kOldestInputEvent - kIntendedVsync of being 15ms
199ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck     * Thus this must always be larger than frameInterval, or it will fail
200ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck     */
201ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    mThresholds[kHighInputLatency] = static_cast<int64_t>(1.5 * frameInterval);
202ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
203ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    // Note that these do not add up to 1. This is intentional. It's to deal
204ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    // with variance in values, and should be sort of an upper-bound on what
205ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    // is reasonable to expect.
206ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    mThresholds[kSlowUI] = static_cast<int64_t>(.5 * frameInterval);
207ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    mThresholds[kSlowSync] = static_cast<int64_t>(.2 * frameInterval);
208ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    mThresholds[kSlowRT] = static_cast<int64_t>(.75 * frameInterval);
209ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
210ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck}
211ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
212ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reckvoid JankTracker::addFrame(const FrameInfo& frame) {
213edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    mData->totalFrameCount++;
214ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    // Fast-path for jank-free frames
215126720aa65fd90105bdf54c04f327f146763c5cfJohn Reck    int64_t totalDuration = frame.duration(sFrameStart, FrameInfoIndex::FrameCompleted);
216660108075e61d7b7e6c138000890011510d5b079John Reck    uint32_t framebucket = frameCountIndexForFrameTime(totalDuration);
217e70c5754d01f2ab0ff47ea3eabaa88aca5ed2a36John Reck    // Keep the fast path as fast as possible.
218ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    if (CC_LIKELY(totalDuration < mFrameInterval)) {
219edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        mData->frameCounts[framebucket]++;
220ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck        return;
221ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    }
222ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
223660108075e61d7b7e6c138000890011510d5b079John Reck    // Only things like Surface.lockHardwareCanvas() are exempt from tracking
2241b54fb27ac48495ed0b33868fda5776fb49fe0f3Chris Craik    if (frame[FrameInfoIndex::Flags] & EXEMPT_FRAMES_FLAGS) {
225ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck        return;
226ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    }
227ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
228660108075e61d7b7e6c138000890011510d5b079John Reck    if (framebucket <= mData->frameCounts.size()) {
229660108075e61d7b7e6c138000890011510d5b079John Reck        mData->frameCounts[framebucket]++;
230660108075e61d7b7e6c138000890011510d5b079John Reck    } else {
231660108075e61d7b7e6c138000890011510d5b079John Reck        framebucket = (ns2ms(totalDuration) - kSlowFrameBucketStartMs)
232660108075e61d7b7e6c138000890011510d5b079John Reck                / kSlowFrameBucketIntervalMs;
233660108075e61d7b7e6c138000890011510d5b079John Reck        framebucket = std::min(framebucket,
234660108075e61d7b7e6c138000890011510d5b079John Reck                static_cast<uint32_t>(mData->slowFrameCounts.size() - 1));
235660108075e61d7b7e6c138000890011510d5b079John Reck        framebucket = std::max(framebucket, 0u);
236660108075e61d7b7e6c138000890011510d5b079John Reck        mData->slowFrameCounts[framebucket]++;
237660108075e61d7b7e6c138000890011510d5b079John Reck    }
238660108075e61d7b7e6c138000890011510d5b079John Reck
239edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    mData->jankFrameCount++;
240ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
241ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    for (int i = 0; i < NUM_BUCKETS; i++) {
242be3fba05e823f740f65b2679929347dc3dd282adJohn Reck        int64_t delta = frame.duration(COMPARISONS[i].start, COMPARISONS[i].end);
243ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck        if (delta >= mThresholds[i] && delta < IGNORE_EXCEEDING) {
244edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck            mData->jankTypeCounts[i]++;
245ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck        }
246ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    }
247ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck}
248ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
249edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reckvoid JankTracker::dumpBuffer(const void* buffer, size_t bufsize, int fd) {
250edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    if (bufsize < sizeof(ProfileData)) {
251edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        return;
252edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    }
253edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    const ProfileData* data = reinterpret_cast<const ProfileData*>(buffer);
254edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    dumpData(data, fd);
255edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck}
256edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck
257edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reckvoid JankTracker::dumpData(const ProfileData* data, int fd) {
258c7cd9cf25d9775446ffcb6b5f20b0a4c1e3c99c5John Reck    if (sFrameStart != FrameInfoIndex::IntendedVsync) {
259c7cd9cf25d9775446ffcb6b5f20b0a4c1e3c99c5John Reck        dprintf(fd, "\nNote: Data has been filtered!");
260c7cd9cf25d9775446ffcb6b5f20b0a4c1e3c99c5John Reck    }
26105f5674ae8cae94c9cc3f039e55747f0e787f959Ying Wang    dprintf(fd, "\nStats since: %" PRIu64 "ns", data->statStartTime);
262edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    dprintf(fd, "\nTotal frames rendered: %u", data->totalFrameCount);
263edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    dprintf(fd, "\nJanky frames: %u (%.2f%%)", data->jankFrameCount,
264edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck            (float) data->jankFrameCount / (float) data->totalFrameCount * 100.0f);
265682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck    dprintf(fd, "\n50th percentile: %ums", findPercentile(data, 50));
266edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    dprintf(fd, "\n90th percentile: %ums", findPercentile(data, 90));
267edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    dprintf(fd, "\n95th percentile: %ums", findPercentile(data, 95));
268edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    dprintf(fd, "\n99th percentile: %ums", findPercentile(data, 99));
269ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    for (int i = 0; i < NUM_BUCKETS; i++) {
270edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        dprintf(fd, "\nNumber %s: %u", JANK_TYPE_NAMES[i], data->jankTypeCounts[i]);
271ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck    }
272660108075e61d7b7e6c138000890011510d5b079John Reck    dprintf(fd, "\nHISTOGRAM:");
273660108075e61d7b7e6c138000890011510d5b079John Reck    for (size_t i = 0; i < data->frameCounts.size(); i++) {
274660108075e61d7b7e6c138000890011510d5b079John Reck        dprintf(fd, " %ums=%u", frameTimeForFrameCountIndex(i),
275660108075e61d7b7e6c138000890011510d5b079John Reck                data->frameCounts[i]);
276660108075e61d7b7e6c138000890011510d5b079John Reck    }
277660108075e61d7b7e6c138000890011510d5b079John Reck    for (size_t i = 0; i < data->slowFrameCounts.size(); i++) {
278660108075e61d7b7e6c138000890011510d5b079John Reck        dprintf(fd, " %zums=%u", (i * kSlowFrameBucketIntervalMs) + kSlowFrameBucketStartMs,
279660108075e61d7b7e6c138000890011510d5b079John Reck                data->slowFrameCounts[i]);
280660108075e61d7b7e6c138000890011510d5b079John Reck    }
281edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    dprintf(fd, "\n");
282ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck}
283ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
284ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reckvoid JankTracker::reset() {
285edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    mData->jankTypeCounts.fill(0);
286edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    mData->frameCounts.fill(0);
2878f55d00c2aa351d6914dca4d0cc2c07725002d90John Reck    mData->slowFrameCounts.fill(0);
288edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    mData->totalFrameCount = 0;
289edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    mData->jankFrameCount = 0;
290379f264bb62ace2cf2053d4765307234bf66552fJohn Reck    mData->statStartTime = systemTime(CLOCK_MONOTONIC);
291c7cd9cf25d9775446ffcb6b5f20b0a4c1e3c99c5John Reck    sFrameStart = Properties::filterOutTestOverhead
292c7cd9cf25d9775446ffcb6b5f20b0a4c1e3c99c5John Reck            ? FrameInfoIndex::HandleInputStart
293c7cd9cf25d9775446ffcb6b5f20b0a4c1e3c99c5John Reck            : FrameInfoIndex::IntendedVsync;
294ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck}
295ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck
296edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reckuint32_t JankTracker::findPercentile(const ProfileData* data, int percentile) {
297edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    int pos = percentile * data->totalFrameCount / 100;
298edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    int remaining = data->totalFrameCount - pos;
299660108075e61d7b7e6c138000890011510d5b079John Reck    for (int i = data->slowFrameCounts.size() - 1; i >= 0; i--) {
300660108075e61d7b7e6c138000890011510d5b079John Reck        remaining -= data->slowFrameCounts[i];
301660108075e61d7b7e6c138000890011510d5b079John Reck        if (remaining <= 0) {
302660108075e61d7b7e6c138000890011510d5b079John Reck            return (i * kSlowFrameBucketIntervalMs) + kSlowFrameBucketStartMs;
303660108075e61d7b7e6c138000890011510d5b079John Reck        }
304660108075e61d7b7e6c138000890011510d5b079John Reck    }
305edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck    for (int i = data->frameCounts.size() - 1; i >= 0; i--) {
306edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck        remaining -= data->frameCounts[i];
307e70c5754d01f2ab0ff47ea3eabaa88aca5ed2a36John Reck        if (remaining <= 0) {
308edc524c90506d80e0fc5fb67e8de7b8f3ef53439John Reck            return frameTimeForFrameCountIndex(i);
309e70c5754d01f2ab0ff47ea3eabaa88aca5ed2a36John Reck        }
310e70c5754d01f2ab0ff47ea3eabaa88aca5ed2a36John Reck    }
311e70c5754d01f2ab0ff47ea3eabaa88aca5ed2a36John Reck    return 0;
312e70c5754d01f2ab0ff47ea3eabaa88aca5ed2a36John Reck}
313e70c5754d01f2ab0ff47ea3eabaa88aca5ed2a36John Reck
314ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck} /* namespace uirenderer */
315ba6adf66d3c44c0aa2fd8a224862ff1901d64300John Reck} /* namespace android */
316