Home | History | Annotate | Download | only in surfaceflinger
      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