1 /*
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
20 #include <cutils/log.h>
21
22 #include <ui/Fence.h>
23
24 #include <utils/String8.h>
25
26 #include "FrameTracker.h"
27 #include "EventLog/EventLog.h"
28
29 namespace android {
30
FrameTracker()31 FrameTracker::FrameTracker() :
32 mOffset(0),
33 mNumFences(0),
34 mDisplayPeriod(0) {
35 resetFrameCountersLocked();
36 }
37
setDesiredPresentTime(nsecs_t presentTime)38 void FrameTracker::setDesiredPresentTime(nsecs_t presentTime) {
39 Mutex::Autolock lock(mMutex);
40 mFrameRecords[mOffset].desiredPresentTime = presentTime;
41 }
42
setFrameReadyTime(nsecs_t readyTime)43 void FrameTracker::setFrameReadyTime(nsecs_t readyTime) {
44 Mutex::Autolock lock(mMutex);
45 mFrameRecords[mOffset].frameReadyTime = readyTime;
46 }
47
setFrameReadyFence(const sp<Fence> & readyFence)48 void FrameTracker::setFrameReadyFence(const sp<Fence>& readyFence) {
49 Mutex::Autolock lock(mMutex);
50 mFrameRecords[mOffset].frameReadyFence = readyFence;
51 mNumFences++;
52 }
53
setActualPresentTime(nsecs_t presentTime)54 void FrameTracker::setActualPresentTime(nsecs_t presentTime) {
55 Mutex::Autolock lock(mMutex);
56 mFrameRecords[mOffset].actualPresentTime = presentTime;
57 }
58
setActualPresentFence(const sp<Fence> & readyFence)59 void FrameTracker::setActualPresentFence(const sp<Fence>& readyFence) {
60 Mutex::Autolock lock(mMutex);
61 mFrameRecords[mOffset].actualPresentFence = readyFence;
62 mNumFences++;
63 }
64
setDisplayRefreshPeriod(nsecs_t displayPeriod)65 void FrameTracker::setDisplayRefreshPeriod(nsecs_t displayPeriod) {
66 Mutex::Autolock lock(mMutex);
67 mDisplayPeriod = displayPeriod;
68 }
69
advanceFrame()70 void FrameTracker::advanceFrame() {
71 Mutex::Autolock lock(mMutex);
72
73 // Update the statistic to include the frame we just finished.
74 updateStatsLocked(mOffset);
75
76 // Advance to the next frame.
77 mOffset = (mOffset+1) % NUM_FRAME_RECORDS;
78 mFrameRecords[mOffset].desiredPresentTime = INT64_MAX;
79 mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
80 mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
81
82 if (mFrameRecords[mOffset].frameReadyFence != NULL) {
83 // We're clobbering an unsignaled fence, so we need to decrement the
84 // fence count.
85 mFrameRecords[mOffset].frameReadyFence = NULL;
86 mNumFences--;
87 }
88
89 if (mFrameRecords[mOffset].actualPresentFence != NULL) {
90 // We're clobbering an unsignaled fence, so we need to decrement the
91 // fence count.
92 mFrameRecords[mOffset].actualPresentFence = NULL;
93 mNumFences--;
94 }
95
96 // Clean up the signaled fences to keep the number of open fence FDs in
97 // this process reasonable.
98 processFencesLocked();
99 }
100
clear()101 void FrameTracker::clear() {
102 Mutex::Autolock lock(mMutex);
103 for (size_t i = 0; i < NUM_FRAME_RECORDS; i++) {
104 mFrameRecords[i].desiredPresentTime = 0;
105 mFrameRecords[i].frameReadyTime = 0;
106 mFrameRecords[i].actualPresentTime = 0;
107 mFrameRecords[i].frameReadyFence.clear();
108 mFrameRecords[i].actualPresentFence.clear();
109 }
110 mNumFences = 0;
111 mFrameRecords[mOffset].desiredPresentTime = INT64_MAX;
112 mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
113 mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
114 }
115
logAndResetStats(const String8 & name)116 void FrameTracker::logAndResetStats(const String8& name) {
117 Mutex::Autolock lock(mMutex);
118 logStatsLocked(name);
119 resetFrameCountersLocked();
120 }
121
processFencesLocked() const122 void FrameTracker::processFencesLocked() const {
123 FrameRecord* records = const_cast<FrameRecord*>(mFrameRecords);
124 int& numFences = const_cast<int&>(mNumFences);
125
126 for (int i = 1; i < NUM_FRAME_RECORDS && numFences > 0; i++) {
127 size_t idx = (mOffset+NUM_FRAME_RECORDS-i) % NUM_FRAME_RECORDS;
128 bool updated = false;
129
130 const sp<Fence>& rfence = records[idx].frameReadyFence;
131 if (rfence != NULL) {
132 records[idx].frameReadyTime = rfence->getSignalTime();
133 if (records[idx].frameReadyTime < INT64_MAX) {
134 records[idx].frameReadyFence = NULL;
135 numFences--;
136 updated = true;
137 }
138 }
139
140 const sp<Fence>& pfence = records[idx].actualPresentFence;
141 if (pfence != NULL) {
142 records[idx].actualPresentTime = pfence->getSignalTime();
143 if (records[idx].actualPresentTime < INT64_MAX) {
144 records[idx].actualPresentFence = NULL;
145 numFences--;
146 updated = true;
147 }
148 }
149
150 if (updated) {
151 updateStatsLocked(idx);
152 }
153 }
154 }
155
updateStatsLocked(size_t newFrameIdx) const156 void FrameTracker::updateStatsLocked(size_t newFrameIdx) const {
157 int* numFrames = const_cast<int*>(mNumFrames);
158
159 if (mDisplayPeriod > 0 && isFrameValidLocked(newFrameIdx)) {
160 size_t prevFrameIdx = (newFrameIdx+NUM_FRAME_RECORDS-1) %
161 NUM_FRAME_RECORDS;
162
163 if (isFrameValidLocked(prevFrameIdx)) {
164 nsecs_t newPresentTime =
165 mFrameRecords[newFrameIdx].actualPresentTime;
166 nsecs_t prevPresentTime =
167 mFrameRecords[prevFrameIdx].actualPresentTime;
168
169 nsecs_t duration = newPresentTime - prevPresentTime;
170 int numPeriods = int((duration + mDisplayPeriod/2) /
171 mDisplayPeriod);
172
173 for (int i = 0; i < NUM_FRAME_BUCKETS-1; i++) {
174 int nextBucket = 1 << (i+1);
175 if (numPeriods < nextBucket) {
176 numFrames[i]++;
177 return;
178 }
179 }
180
181 // The last duration bucket is a catch-all.
182 numFrames[NUM_FRAME_BUCKETS-1]++;
183 }
184 }
185 }
186
resetFrameCountersLocked()187 void FrameTracker::resetFrameCountersLocked() {
188 for (int i = 0; i < NUM_FRAME_BUCKETS; i++) {
189 mNumFrames[i] = 0;
190 }
191 }
192
logStatsLocked(const String8 & name) const193 void FrameTracker::logStatsLocked(const String8& name) const {
194 for (int i = 0; i < NUM_FRAME_BUCKETS; i++) {
195 if (mNumFrames[i] > 0) {
196 EventLog::logFrameDurations(name, mNumFrames, NUM_FRAME_BUCKETS);
197 return;
198 }
199 }
200 }
201
isFrameValidLocked(size_t idx) const202 bool FrameTracker::isFrameValidLocked(size_t idx) const {
203 return mFrameRecords[idx].actualPresentTime > 0 &&
204 mFrameRecords[idx].actualPresentTime < INT64_MAX;
205 }
206
dump(String8 & result) const207 void FrameTracker::dump(String8& result) const {
208 Mutex::Autolock lock(mMutex);
209 processFencesLocked();
210
211 const size_t o = mOffset;
212 for (size_t i = 1; i < NUM_FRAME_RECORDS; i++) {
213 const size_t index = (o+i) % NUM_FRAME_RECORDS;
214 result.appendFormat("%lld\t%lld\t%lld\n",
215 mFrameRecords[index].desiredPresentTime,
216 mFrameRecords[index].actualPresentTime,
217 mFrameRecords[index].frameReadyTime);
218 }
219 result.append("\n");
220 }
221
222 } // namespace android
223