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