blob: 99c4f621536d52f4715230bd14fee23653dde825 [file] [log] [blame]
Jamie Gennis82dbc742012-11-08 19:23:28 -08001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// This is needed for stdint.h to define INT64_MAX in C++
18#define __STDC_LIMIT_MACROS
19
Greg Hackmann86efcc02014-03-07 12:44:02 -080020#include <inttypes.h>
21
Mark Salyzyna5e161b2016-09-29 08:08:05 -070022#include <android/log.h>
23#include <utils/String8.h>
Jamie Gennis6547ff42013-07-16 20:12:42 -070024
Jamie Gennis82dbc742012-11-08 19:23:28 -080025#include <ui/Fence.h>
Svetoslavd85084b2014-03-20 10:28:31 -070026#include <ui/FrameStats.h>
Jamie Gennis82dbc742012-11-08 19:23:28 -080027
Jamie Gennis82dbc742012-11-08 19:23:28 -080028#include "FrameTracker.h"
Jamie Gennis6547ff42013-07-16 20:12:42 -070029#include "EventLog/EventLog.h"
Jamie Gennis82dbc742012-11-08 19:23:28 -080030
31namespace android {
32
33FrameTracker::FrameTracker() :
34 mOffset(0),
Jamie Gennis6547ff42013-07-16 20:12:42 -070035 mNumFences(0),
36 mDisplayPeriod(0) {
37 resetFrameCountersLocked();
Jamie Gennis82dbc742012-11-08 19:23:28 -080038}
39
40void FrameTracker::setDesiredPresentTime(nsecs_t presentTime) {
Jamie Gennis4b0eba92013-02-05 13:30:24 -080041 Mutex::Autolock lock(mMutex);
Jamie Gennis82dbc742012-11-08 19:23:28 -080042 mFrameRecords[mOffset].desiredPresentTime = presentTime;
43}
44
45void FrameTracker::setFrameReadyTime(nsecs_t readyTime) {
Jamie Gennis4b0eba92013-02-05 13:30:24 -080046 Mutex::Autolock lock(mMutex);
Jamie Gennis82dbc742012-11-08 19:23:28 -080047 mFrameRecords[mOffset].frameReadyTime = readyTime;
48}
49
50void FrameTracker::setFrameReadyFence(const sp<Fence>& readyFence) {
Jamie Gennis4b0eba92013-02-05 13:30:24 -080051 Mutex::Autolock lock(mMutex);
Jamie Gennis82dbc742012-11-08 19:23:28 -080052 mFrameRecords[mOffset].frameReadyFence = readyFence;
53 mNumFences++;
54}
55
56void FrameTracker::setActualPresentTime(nsecs_t presentTime) {
Jamie Gennis4b0eba92013-02-05 13:30:24 -080057 Mutex::Autolock lock(mMutex);
Jamie Gennis82dbc742012-11-08 19:23:28 -080058 mFrameRecords[mOffset].actualPresentTime = presentTime;
59}
60
61void FrameTracker::setActualPresentFence(const sp<Fence>& readyFence) {
Jamie Gennis4b0eba92013-02-05 13:30:24 -080062 Mutex::Autolock lock(mMutex);
Jamie Gennis82dbc742012-11-08 19:23:28 -080063 mFrameRecords[mOffset].actualPresentFence = readyFence;
64 mNumFences++;
65}
66
Jamie Gennis6547ff42013-07-16 20:12:42 -070067void FrameTracker::setDisplayRefreshPeriod(nsecs_t displayPeriod) {
68 Mutex::Autolock lock(mMutex);
69 mDisplayPeriod = displayPeriod;
70}
71
Jamie Gennis82dbc742012-11-08 19:23:28 -080072void FrameTracker::advanceFrame() {
Jamie Gennis4b0eba92013-02-05 13:30:24 -080073 Mutex::Autolock lock(mMutex);
Jamie Gennis6547ff42013-07-16 20:12:42 -070074
75 // Update the statistic to include the frame we just finished.
76 updateStatsLocked(mOffset);
77
78 // Advance to the next frame.
Jamie Gennis82dbc742012-11-08 19:23:28 -080079 mOffset = (mOffset+1) % NUM_FRAME_RECORDS;
80 mFrameRecords[mOffset].desiredPresentTime = INT64_MAX;
81 mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
82 mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
83
84 if (mFrameRecords[mOffset].frameReadyFence != NULL) {
85 // We're clobbering an unsignaled fence, so we need to decrement the
86 // fence count.
87 mFrameRecords[mOffset].frameReadyFence = NULL;
88 mNumFences--;
89 }
90
91 if (mFrameRecords[mOffset].actualPresentFence != NULL) {
92 // We're clobbering an unsignaled fence, so we need to decrement the
93 // fence count.
94 mFrameRecords[mOffset].actualPresentFence = NULL;
95 mNumFences--;
96 }
97
98 // Clean up the signaled fences to keep the number of open fence FDs in
99 // this process reasonable.
Jamie Gennis4b0eba92013-02-05 13:30:24 -0800100 processFencesLocked();
Jamie Gennis82dbc742012-11-08 19:23:28 -0800101}
102
Svetoslavd85084b2014-03-20 10:28:31 -0700103void FrameTracker::clearStats() {
Jamie Gennis4b0eba92013-02-05 13:30:24 -0800104 Mutex::Autolock lock(mMutex);
Jamie Gennis82dbc742012-11-08 19:23:28 -0800105 for (size_t i = 0; i < NUM_FRAME_RECORDS; i++) {
106 mFrameRecords[i].desiredPresentTime = 0;
107 mFrameRecords[i].frameReadyTime = 0;
108 mFrameRecords[i].actualPresentTime = 0;
109 mFrameRecords[i].frameReadyFence.clear();
110 mFrameRecords[i].actualPresentFence.clear();
111 }
112 mNumFences = 0;
Jamie Gennis4b0eba92013-02-05 13:30:24 -0800113 mFrameRecords[mOffset].desiredPresentTime = INT64_MAX;
114 mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
115 mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
Jamie Gennis82dbc742012-11-08 19:23:28 -0800116}
117
Svetoslavd85084b2014-03-20 10:28:31 -0700118void FrameTracker::getStats(FrameStats* outStats) const {
119 Mutex::Autolock lock(mMutex);
120 processFencesLocked();
121
122 outStats->refreshPeriodNano = mDisplayPeriod;
123
124 const size_t offset = mOffset;
125 for (size_t i = 1; i < NUM_FRAME_RECORDS; i++) {
126 const size_t index = (offset + i) % NUM_FRAME_RECORDS;
127
128 // Skip frame records with no data (if buffer not yet full).
129 if (mFrameRecords[index].desiredPresentTime == 0) {
130 continue;
131 }
132
133 nsecs_t desiredPresentTimeNano = mFrameRecords[index].desiredPresentTime;
134 outStats->desiredPresentTimesNano.push_back(desiredPresentTimeNano);
135
136 nsecs_t actualPresentTimeNano = mFrameRecords[index].actualPresentTime;
137 outStats->actualPresentTimesNano.push_back(actualPresentTimeNano);
138
139 nsecs_t frameReadyTimeNano = mFrameRecords[index].frameReadyTime;
140 outStats->frameReadyTimesNano.push_back(frameReadyTimeNano);
141 }
142}
143
Jamie Gennis6547ff42013-07-16 20:12:42 -0700144void FrameTracker::logAndResetStats(const String8& name) {
145 Mutex::Autolock lock(mMutex);
146 logStatsLocked(name);
147 resetFrameCountersLocked();
148}
149
Jamie Gennis4b0eba92013-02-05 13:30:24 -0800150void FrameTracker::processFencesLocked() const {
Jamie Gennis82dbc742012-11-08 19:23:28 -0800151 FrameRecord* records = const_cast<FrameRecord*>(mFrameRecords);
152 int& numFences = const_cast<int&>(mNumFences);
153
154 for (int i = 1; i < NUM_FRAME_RECORDS && numFences > 0; i++) {
155 size_t idx = (mOffset+NUM_FRAME_RECORDS-i) % NUM_FRAME_RECORDS;
Jamie Gennis6547ff42013-07-16 20:12:42 -0700156 bool updated = false;
Jamie Gennis82dbc742012-11-08 19:23:28 -0800157
158 const sp<Fence>& rfence = records[idx].frameReadyFence;
159 if (rfence != NULL) {
160 records[idx].frameReadyTime = rfence->getSignalTime();
161 if (records[idx].frameReadyTime < INT64_MAX) {
162 records[idx].frameReadyFence = NULL;
163 numFences--;
Jamie Gennis6547ff42013-07-16 20:12:42 -0700164 updated = true;
Jamie Gennis82dbc742012-11-08 19:23:28 -0800165 }
166 }
167
168 const sp<Fence>& pfence = records[idx].actualPresentFence;
169 if (pfence != NULL) {
170 records[idx].actualPresentTime = pfence->getSignalTime();
171 if (records[idx].actualPresentTime < INT64_MAX) {
172 records[idx].actualPresentFence = NULL;
173 numFences--;
Jamie Gennis6547ff42013-07-16 20:12:42 -0700174 updated = true;
Jamie Gennis82dbc742012-11-08 19:23:28 -0800175 }
176 }
Jamie Gennis6547ff42013-07-16 20:12:42 -0700177
178 if (updated) {
179 updateStatsLocked(idx);
180 }
Jamie Gennis82dbc742012-11-08 19:23:28 -0800181 }
182}
183
Jamie Gennis6547ff42013-07-16 20:12:42 -0700184void FrameTracker::updateStatsLocked(size_t newFrameIdx) const {
185 int* numFrames = const_cast<int*>(mNumFrames);
186
187 if (mDisplayPeriod > 0 && isFrameValidLocked(newFrameIdx)) {
188 size_t prevFrameIdx = (newFrameIdx+NUM_FRAME_RECORDS-1) %
189 NUM_FRAME_RECORDS;
190
191 if (isFrameValidLocked(prevFrameIdx)) {
192 nsecs_t newPresentTime =
193 mFrameRecords[newFrameIdx].actualPresentTime;
194 nsecs_t prevPresentTime =
195 mFrameRecords[prevFrameIdx].actualPresentTime;
196
197 nsecs_t duration = newPresentTime - prevPresentTime;
198 int numPeriods = int((duration + mDisplayPeriod/2) /
199 mDisplayPeriod);
200
201 for (int i = 0; i < NUM_FRAME_BUCKETS-1; i++) {
202 int nextBucket = 1 << (i+1);
203 if (numPeriods < nextBucket) {
204 numFrames[i]++;
205 return;
206 }
207 }
208
209 // The last duration bucket is a catch-all.
210 numFrames[NUM_FRAME_BUCKETS-1]++;
211 }
212 }
213}
214
215void FrameTracker::resetFrameCountersLocked() {
216 for (int i = 0; i < NUM_FRAME_BUCKETS; i++) {
217 mNumFrames[i] = 0;
218 }
219}
220
221void FrameTracker::logStatsLocked(const String8& name) const {
222 for (int i = 0; i < NUM_FRAME_BUCKETS; i++) {
223 if (mNumFrames[i] > 0) {
224 EventLog::logFrameDurations(name, mNumFrames, NUM_FRAME_BUCKETS);
225 return;
226 }
227 }
228}
229
230bool FrameTracker::isFrameValidLocked(size_t idx) const {
231 return mFrameRecords[idx].actualPresentTime > 0 &&
232 mFrameRecords[idx].actualPresentTime < INT64_MAX;
233}
234
Svetoslavd85084b2014-03-20 10:28:31 -0700235void FrameTracker::dumpStats(String8& result) const {
Jamie Gennis4b0eba92013-02-05 13:30:24 -0800236 Mutex::Autolock lock(mMutex);
237 processFencesLocked();
Jamie Gennis82dbc742012-11-08 19:23:28 -0800238
239 const size_t o = mOffset;
240 for (size_t i = 1; i < NUM_FRAME_RECORDS; i++) {
241 const size_t index = (o+i) % NUM_FRAME_RECORDS;
Greg Hackmann86efcc02014-03-07 12:44:02 -0800242 result.appendFormat("%" PRId64 "\t%" PRId64 "\t%" PRId64 "\n",
Jamie Gennis82dbc742012-11-08 19:23:28 -0800243 mFrameRecords[index].desiredPresentTime,
244 mFrameRecords[index].actualPresentTime,
245 mFrameRecords[index].frameReadyTime);
246 }
247 result.append("\n");
248}
249
250} // namespace android