2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 // This is needed for stdint.h to define INT64_MAX in C++
18 #define __STDC_LIMIT_MACROS
20 #include <cutils/log.h>
24 #include <utils/String8.h>
26 #include "FrameTracker.h"
27 #include "EventLog/EventLog.h"
31 FrameTracker::FrameTracker() :
35 resetFrameCountersLocked();
38 void FrameTracker::setDesiredPresentTime(nsecs_t presentTime) {
39 Mutex::Autolock lock(mMutex);
40 mFrameRecords[mOffset].desiredPresentTime = presentTime;
43 void FrameTracker::setFrameReadyTime(nsecs_t readyTime) {
44 Mutex::Autolock lock(mMutex);
45 mFrameRecords[mOffset].frameReadyTime = readyTime;
48 void FrameTracker::setFrameReadyFence(const sp<Fence>& readyFence) {
49 Mutex::Autolock lock(mMutex);
50 mFrameRecords[mOffset].frameReadyFence = readyFence;
54 void FrameTracker::setActualPresentTime(nsecs_t presentTime) {
55 Mutex::Autolock lock(mMutex);
56 mFrameRecords[mOffset].actualPresentTime = presentTime;
59 void FrameTracker::setActualPresentFence(const sp<Fence>& readyFence) {
60 Mutex::Autolock lock(mMutex);
61 mFrameRecords[mOffset].actualPresentFence = readyFence;
65 void FrameTracker::setDisplayRefreshPeriod(nsecs_t displayPeriod) {
66 Mutex::Autolock lock(mMutex);
67 mDisplayPeriod = displayPeriod;
70 void FrameTracker::advanceFrame() {
71 Mutex::Autolock lock(mMutex);
73 // Update the statistic to include the frame we just finished.
74 updateStatsLocked(mOffset);
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;
82 if (mFrameRecords[mOffset].frameReadyFence != NULL) {
83 // We're clobbering an unsignaled fence, so we need to decrement the
85 mFrameRecords[mOffset].frameReadyFence = NULL;
89 if (mFrameRecords[mOffset].actualPresentFence != NULL) {
90 // We're clobbering an unsignaled fence, so we need to decrement the
92 mFrameRecords[mOffset].actualPresentFence = NULL;
96 // Clean up the signaled fences to keep the number of open fence FDs in
97 // this process reasonable.
98 processFencesLocked();
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();
111 mFrameRecords[mOffset].desiredPresentTime = INT64_MAX;
112 mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
113 mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
116 void FrameTracker::logAndResetStats(const String8& name) {
117 Mutex::Autolock lock(mMutex);
118 logStatsLocked(name);
119 resetFrameCountersLocked();
122 void FrameTracker::processFencesLocked() const {
123 FrameRecord* records = const_cast<FrameRecord*>(mFrameRecords);
124 int& numFences = const_cast<int&>(mNumFences);
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;
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;
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;
151 updateStatsLocked(idx);
156 void FrameTracker::updateStatsLocked(size_t newFrameIdx) const {
157 int* numFrames = const_cast<int*>(mNumFrames);
159 if (mDisplayPeriod > 0 && isFrameValidLocked(newFrameIdx)) {
160 size_t prevFrameIdx = (newFrameIdx+NUM_FRAME_RECORDS-1) %
163 if (isFrameValidLocked(prevFrameIdx)) {
164 nsecs_t newPresentTime =
165 mFrameRecords[newFrameIdx].actualPresentTime;
166 nsecs_t prevPresentTime =
167 mFrameRecords[prevFrameIdx].actualPresentTime;
169 nsecs_t duration = newPresentTime - prevPresentTime;
170 int numPeriods = int((duration + mDisplayPeriod/2) /
173 for (int i = 0; i < NUM_FRAME_BUCKETS-1; i++) {
174 int nextBucket = 1 << (i+1);
175 if (numPeriods < nextBucket) {
181 // The last duration bucket is a catch-all.
182 numFrames[NUM_FRAME_BUCKETS-1]++;
187 void FrameTracker::resetFrameCountersLocked() {
188 for (int i = 0; i < NUM_FRAME_BUCKETS; i++) {
193 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);
202 bool FrameTracker::isFrameValidLocked(size_t idx) const {
203 return mFrameRecords[idx].actualPresentTime > 0 &&
204 mFrameRecords[idx].actualPresentTime < INT64_MAX;
207 void FrameTracker::dump(String8& result) const {
208 Mutex::Autolock lock(mMutex);
209 processFencesLocked();
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);
222 } // namespace android