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