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 31 FrameTracker::FrameTracker() : 32 mOffset(0), 33 mNumFences(0), 34 mDisplayPeriod(0) { 35 resetFrameCountersLocked(); 36 } 37 38 void FrameTracker::setDesiredPresentTime(nsecs_t presentTime) { 39 Mutex::Autolock lock(mMutex); 40 mFrameRecords[mOffset].desiredPresentTime = presentTime; 41 } 42 43 void FrameTracker::setFrameReadyTime(nsecs_t readyTime) { 44 Mutex::Autolock lock(mMutex); 45 mFrameRecords[mOffset].frameReadyTime = readyTime; 46 } 47 48 void FrameTracker::setFrameReadyFence(const sp<Fence>& readyFence) { 49 Mutex::Autolock lock(mMutex); 50 mFrameRecords[mOffset].frameReadyFence = readyFence; 51 mNumFences++; 52 } 53 54 void FrameTracker::setActualPresentTime(nsecs_t presentTime) { 55 Mutex::Autolock lock(mMutex); 56 mFrameRecords[mOffset].actualPresentTime = presentTime; 57 } 58 59 void FrameTracker::setActualPresentFence(const sp<Fence>& readyFence) { 60 Mutex::Autolock lock(mMutex); 61 mFrameRecords[mOffset].actualPresentFence = readyFence; 62 mNumFences++; 63 } 64 65 void FrameTracker::setDisplayRefreshPeriod(nsecs_t displayPeriod) { 66 Mutex::Autolock lock(mMutex); 67 mDisplayPeriod = displayPeriod; 68 } 69 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 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 116 void FrameTracker::logAndResetStats(const String8& name) { 117 Mutex::Autolock lock(mMutex); 118 logStatsLocked(name); 119 resetFrameCountersLocked(); 120 } 121 122 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 156 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 187 void FrameTracker::resetFrameCountersLocked() { 188 for (int i = 0; i < NUM_FRAME_BUCKETS; i++) { 189 mNumFrames[i] = 0; 190 } 191 } 192 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); 197 return; 198 } 199 } 200 } 201 202 bool FrameTracker::isFrameValidLocked(size_t idx) const { 203 return mFrameRecords[idx].actualPresentTime > 0 && 204 mFrameRecords[idx].actualPresentTime < INT64_MAX; 205 } 206 207 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