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