Home | History | Annotate | Download | only in TimeStats
      1 /*
      2  * Copyright 2018 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 #undef LOG_TAG
     17 #define LOG_TAG "TimeStats"
     18 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
     19 
     20 #include "TimeStats.h"
     21 
     22 #include <android-base/stringprintf.h>
     23 
     24 #include <log/log.h>
     25 
     26 #include <utils/String8.h>
     27 #include <utils/Timers.h>
     28 #include <utils/Trace.h>
     29 
     30 #include <algorithm>
     31 #include <regex>
     32 
     33 namespace android {
     34 
     35 namespace impl {
     36 
     37 void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) {
     38     ATRACE_CALL();
     39 
     40     std::unordered_map<std::string, int32_t> argsMap;
     41     for (size_t index = 0; index < args.size(); ++index) {
     42         argsMap[std::string(String8(args[index]).c_str())] = index;
     43     }
     44 
     45     if (argsMap.count("-disable")) {
     46         disable();
     47     }
     48 
     49     if (argsMap.count("-dump")) {
     50         std::optional<uint32_t> maxLayers = std::nullopt;
     51         auto iter = argsMap.find("-maxlayers");
     52         if (iter != argsMap.end() && iter->second + 1 < static_cast<int32_t>(args.size())) {
     53             int64_t value = strtol(String8(args[iter->second + 1]).c_str(), nullptr, 10);
     54             value = std::clamp(value, int64_t(0), int64_t(UINT32_MAX));
     55             maxLayers = static_cast<uint32_t>(value);
     56         }
     57 
     58         dump(asProto, maxLayers, result);
     59     }
     60 
     61     if (argsMap.count("-clear")) {
     62         clear();
     63     }
     64 
     65     if (argsMap.count("-enable")) {
     66         enable();
     67     }
     68 }
     69 
     70 std::string TimeStats::miniDump() {
     71     ATRACE_CALL();
     72 
     73     std::string result = "TimeStats miniDump:\n";
     74     std::lock_guard<std::mutex> lock(mMutex);
     75     android::base::StringAppendF(&result, "Number of tracked layers is %zu\n",
     76                                  mTimeStatsTracker.size());
     77     return result;
     78 }
     79 
     80 void TimeStats::incrementTotalFrames() {
     81     if (!mEnabled.load()) return;
     82 
     83     ATRACE_CALL();
     84 
     85     std::lock_guard<std::mutex> lock(mMutex);
     86     mTimeStats.totalFrames++;
     87 }
     88 
     89 void TimeStats::incrementMissedFrames() {
     90     if (!mEnabled.load()) return;
     91 
     92     ATRACE_CALL();
     93 
     94     std::lock_guard<std::mutex> lock(mMutex);
     95     mTimeStats.missedFrames++;
     96 }
     97 
     98 void TimeStats::incrementClientCompositionFrames() {
     99     if (!mEnabled.load()) return;
    100 
    101     ATRACE_CALL();
    102 
    103     std::lock_guard<std::mutex> lock(mMutex);
    104     mTimeStats.clientCompositionFrames++;
    105 }
    106 
    107 bool TimeStats::recordReadyLocked(int32_t layerID, TimeRecord* timeRecord) {
    108     if (!timeRecord->ready) {
    109         ALOGV("[%d]-[%" PRIu64 "]-presentFence is still not received", layerID,
    110               timeRecord->frameTime.frameNumber);
    111         return false;
    112     }
    113 
    114     if (timeRecord->acquireFence != nullptr) {
    115         if (timeRecord->acquireFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
    116             return false;
    117         }
    118         if (timeRecord->acquireFence->getSignalTime() != Fence::SIGNAL_TIME_INVALID) {
    119             timeRecord->frameTime.acquireTime = timeRecord->acquireFence->getSignalTime();
    120             timeRecord->acquireFence = nullptr;
    121         } else {
    122             ALOGV("[%d]-[%" PRIu64 "]-acquireFence signal time is invalid", layerID,
    123                   timeRecord->frameTime.frameNumber);
    124         }
    125     }
    126 
    127     if (timeRecord->presentFence != nullptr) {
    128         if (timeRecord->presentFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
    129             return false;
    130         }
    131         if (timeRecord->presentFence->getSignalTime() != Fence::SIGNAL_TIME_INVALID) {
    132             timeRecord->frameTime.presentTime = timeRecord->presentFence->getSignalTime();
    133             timeRecord->presentFence = nullptr;
    134         } else {
    135             ALOGV("[%d]-[%" PRIu64 "]-presentFence signal time invalid", layerID,
    136                   timeRecord->frameTime.frameNumber);
    137         }
    138     }
    139 
    140     return true;
    141 }
    142 
    143 static int32_t msBetween(nsecs_t start, nsecs_t end) {
    144     int64_t delta = (end - start) / 1000000;
    145     delta = std::clamp(delta, int64_t(INT32_MIN), int64_t(INT32_MAX));
    146     return static_cast<int32_t>(delta);
    147 }
    148 
    149 // This regular expression captures the following for instance:
    150 // StatusBar in StatusBar#0
    151 // com.appname in com.appname/com.appname.activity#0
    152 // com.appname in SurfaceView - com.appname/com.appname.activity#0
    153 static const std::regex packageNameRegex("(?:SurfaceView[-\\s\\t]+)?([^/]+).*#\\d+");
    154 
    155 static std::string getPackageName(const std::string& layerName) {
    156     std::smatch match;
    157     if (std::regex_match(layerName.begin(), layerName.end(), match, packageNameRegex)) {
    158         // There must be a match for group 1 otherwise the whole string is not
    159         // matched and the above will return false
    160         return match[1];
    161     }
    162     return "";
    163 }
    164 
    165 void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerID) {
    166     ATRACE_CALL();
    167 
    168     LayerRecord& layerRecord = mTimeStatsTracker[layerID];
    169     TimeRecord& prevTimeRecord = layerRecord.prevTimeRecord;
    170     std::deque<TimeRecord>& timeRecords = layerRecord.timeRecords;
    171     while (!timeRecords.empty()) {
    172         if (!recordReadyLocked(layerID, &timeRecords[0])) break;
    173         ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerID,
    174               timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
    175 
    176         const std::string& layerName = layerRecord.layerName;
    177         if (prevTimeRecord.ready) {
    178             if (!mTimeStats.stats.count(layerName)) {
    179                 mTimeStats.stats[layerName].layerName = layerName;
    180                 mTimeStats.stats[layerName].packageName = getPackageName(layerName);
    181             }
    182             TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[layerName];
    183             timeStatsLayer.totalFrames++;
    184             timeStatsLayer.droppedFrames += layerRecord.droppedFrames;
    185             layerRecord.droppedFrames = 0;
    186 
    187             const int32_t postToAcquireMs = msBetween(timeRecords[0].frameTime.postTime,
    188                                                       timeRecords[0].frameTime.acquireTime);
    189             ALOGV("[%d]-[%" PRIu64 "]-post2acquire[%d]", layerID,
    190                   timeRecords[0].frameTime.frameNumber, postToAcquireMs);
    191             timeStatsLayer.deltas["post2acquire"].insert(postToAcquireMs);
    192 
    193             const int32_t postToPresentMs = msBetween(timeRecords[0].frameTime.postTime,
    194                                                       timeRecords[0].frameTime.presentTime);
    195             ALOGV("[%d]-[%" PRIu64 "]-post2present[%d]", layerID,
    196                   timeRecords[0].frameTime.frameNumber, postToPresentMs);
    197             timeStatsLayer.deltas["post2present"].insert(postToPresentMs);
    198 
    199             const int32_t acquireToPresentMs = msBetween(timeRecords[0].frameTime.acquireTime,
    200                                                          timeRecords[0].frameTime.presentTime);
    201             ALOGV("[%d]-[%" PRIu64 "]-acquire2present[%d]", layerID,
    202                   timeRecords[0].frameTime.frameNumber, acquireToPresentMs);
    203             timeStatsLayer.deltas["acquire2present"].insert(acquireToPresentMs);
    204 
    205             const int32_t latchToPresentMs = msBetween(timeRecords[0].frameTime.latchTime,
    206                                                        timeRecords[0].frameTime.presentTime);
    207             ALOGV("[%d]-[%" PRIu64 "]-latch2present[%d]", layerID,
    208                   timeRecords[0].frameTime.frameNumber, latchToPresentMs);
    209             timeStatsLayer.deltas["latch2present"].insert(latchToPresentMs);
    210 
    211             const int32_t desiredToPresentMs = msBetween(timeRecords[0].frameTime.desiredTime,
    212                                                          timeRecords[0].frameTime.presentTime);
    213             ALOGV("[%d]-[%" PRIu64 "]-desired2present[%d]", layerID,
    214                   timeRecords[0].frameTime.frameNumber, desiredToPresentMs);
    215             timeStatsLayer.deltas["desired2present"].insert(desiredToPresentMs);
    216 
    217             const int32_t presentToPresentMs = msBetween(prevTimeRecord.frameTime.presentTime,
    218                                                          timeRecords[0].frameTime.presentTime);
    219             ALOGV("[%d]-[%" PRIu64 "]-present2present[%d]", layerID,
    220                   timeRecords[0].frameTime.frameNumber, presentToPresentMs);
    221             timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
    222         }
    223 
    224         // Output additional trace points to track frame time.
    225         ATRACE_INT64(("TimeStats-Post - " + layerName).c_str(), timeRecords[0].frameTime.postTime);
    226         ATRACE_INT64(("TimeStats-Acquire - " + layerName).c_str(),
    227                      timeRecords[0].frameTime.acquireTime);
    228         ATRACE_INT64(("TimeStats-Latch - " + layerName).c_str(),
    229                      timeRecords[0].frameTime.latchTime);
    230         ATRACE_INT64(("TimeStats-Desired - " + layerName).c_str(),
    231                      timeRecords[0].frameTime.desiredTime);
    232         ATRACE_INT64(("TimeStats-Present - " + layerName).c_str(),
    233                      timeRecords[0].frameTime.presentTime);
    234 
    235         prevTimeRecord = timeRecords[0];
    236         timeRecords.pop_front();
    237         layerRecord.waitData--;
    238     }
    239 }
    240 
    241 // This regular expression captures the following layer names for instance:
    242 // 1) StatusBat#0
    243 // 2) NavigationBar#1
    244 // 3) co(m).*#0
    245 // 4) SurfaceView - co(m).*#0
    246 // Using [-\\s\t]+ for the conjunction part between SurfaceView and co(m).*
    247 // is a bit more robust in case there's a slight change.
    248 // The layer name would only consist of . / $ _ 0-9 a-z A-Z in most cases.
    249 static const std::regex layerNameRegex(
    250         "(((SurfaceView[-\\s\\t]+)?com?\\.[./$\\w]+)|((Status|Navigation)Bar))#\\d+");
    251 
    252 static bool layerNameIsValid(const std::string& layerName) {
    253     return std::regex_match(layerName.begin(), layerName.end(), layerNameRegex);
    254 }
    255 
    256 void TimeStats::setPostTime(int32_t layerID, uint64_t frameNumber, const std::string& layerName,
    257                             nsecs_t postTime) {
    258     if (!mEnabled.load()) return;
    259 
    260     ATRACE_CALL();
    261     ALOGV("[%d]-[%" PRIu64 "]-[%s]-PostTime[%" PRId64 "]", layerID, frameNumber, layerName.c_str(),
    262           postTime);
    263 
    264     std::lock_guard<std::mutex> lock(mMutex);
    265     if (!mTimeStatsTracker.count(layerID) && mTimeStatsTracker.size() < MAX_NUM_LAYER_RECORDS &&
    266         layerNameIsValid(layerName)) {
    267         mTimeStatsTracker[layerID].layerName = layerName;
    268     }
    269     if (!mTimeStatsTracker.count(layerID)) return;
    270     LayerRecord& layerRecord = mTimeStatsTracker[layerID];
    271     if (layerRecord.timeRecords.size() == MAX_NUM_TIME_RECORDS) {
    272         ALOGE("[%d]-[%s]-timeRecords is at its maximum size[%zu]. Ignore this when unittesting.",
    273               layerID, layerRecord.layerName.c_str(), MAX_NUM_TIME_RECORDS);
    274         mTimeStatsTracker.erase(layerID);
    275         return;
    276     }
    277     // For most media content, the acquireFence is invalid because the buffer is
    278     // ready at the queueBuffer stage. In this case, acquireTime should be given
    279     // a default value as postTime.
    280     TimeRecord timeRecord = {
    281             .frameTime =
    282                     {
    283                             .frameNumber = frameNumber,
    284                             .postTime = postTime,
    285                             .latchTime = postTime,
    286                             .acquireTime = postTime,
    287                             .desiredTime = postTime,
    288                     },
    289     };
    290     layerRecord.timeRecords.push_back(timeRecord);
    291     if (layerRecord.waitData < 0 ||
    292         layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
    293         layerRecord.waitData = layerRecord.timeRecords.size() - 1;
    294 }
    295 
    296 void TimeStats::setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime) {
    297     if (!mEnabled.load()) return;
    298 
    299     ATRACE_CALL();
    300     ALOGV("[%d]-[%" PRIu64 "]-LatchTime[%" PRId64 "]", layerID, frameNumber, latchTime);
    301 
    302     std::lock_guard<std::mutex> lock(mMutex);
    303     if (!mTimeStatsTracker.count(layerID)) return;
    304     LayerRecord& layerRecord = mTimeStatsTracker[layerID];
    305     if (layerRecord.waitData < 0 ||
    306         layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
    307         return;
    308     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
    309     if (timeRecord.frameTime.frameNumber == frameNumber) {
    310         timeRecord.frameTime.latchTime = latchTime;
    311     }
    312 }
    313 
    314 void TimeStats::setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime) {
    315     if (!mEnabled.load()) return;
    316 
    317     ATRACE_CALL();
    318     ALOGV("[%d]-[%" PRIu64 "]-DesiredTime[%" PRId64 "]", layerID, frameNumber, desiredTime);
    319 
    320     std::lock_guard<std::mutex> lock(mMutex);
    321     if (!mTimeStatsTracker.count(layerID)) return;
    322     LayerRecord& layerRecord = mTimeStatsTracker[layerID];
    323     if (layerRecord.waitData < 0 ||
    324         layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
    325         return;
    326     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
    327     if (timeRecord.frameTime.frameNumber == frameNumber) {
    328         timeRecord.frameTime.desiredTime = desiredTime;
    329     }
    330 }
    331 
    332 void TimeStats::setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime) {
    333     if (!mEnabled.load()) return;
    334 
    335     ATRACE_CALL();
    336     ALOGV("[%d]-[%" PRIu64 "]-AcquireTime[%" PRId64 "]", layerID, frameNumber, acquireTime);
    337 
    338     std::lock_guard<std::mutex> lock(mMutex);
    339     if (!mTimeStatsTracker.count(layerID)) return;
    340     LayerRecord& layerRecord = mTimeStatsTracker[layerID];
    341     if (layerRecord.waitData < 0 ||
    342         layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
    343         return;
    344     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
    345     if (timeRecord.frameTime.frameNumber == frameNumber) {
    346         timeRecord.frameTime.acquireTime = acquireTime;
    347     }
    348 }
    349 
    350 void TimeStats::setAcquireFence(int32_t layerID, uint64_t frameNumber,
    351                                 const std::shared_ptr<FenceTime>& acquireFence) {
    352     if (!mEnabled.load()) return;
    353 
    354     ATRACE_CALL();
    355     ALOGV("[%d]-[%" PRIu64 "]-AcquireFenceTime[%" PRId64 "]", layerID, frameNumber,
    356           acquireFence->getSignalTime());
    357 
    358     std::lock_guard<std::mutex> lock(mMutex);
    359     if (!mTimeStatsTracker.count(layerID)) return;
    360     LayerRecord& layerRecord = mTimeStatsTracker[layerID];
    361     if (layerRecord.waitData < 0 ||
    362         layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
    363         return;
    364     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
    365     if (timeRecord.frameTime.frameNumber == frameNumber) {
    366         timeRecord.acquireFence = acquireFence;
    367     }
    368 }
    369 
    370 void TimeStats::setPresentTime(int32_t layerID, uint64_t frameNumber, nsecs_t presentTime) {
    371     if (!mEnabled.load()) return;
    372 
    373     ATRACE_CALL();
    374     ALOGV("[%d]-[%" PRIu64 "]-PresentTime[%" PRId64 "]", layerID, frameNumber, presentTime);
    375 
    376     std::lock_guard<std::mutex> lock(mMutex);
    377     if (!mTimeStatsTracker.count(layerID)) return;
    378     LayerRecord& layerRecord = mTimeStatsTracker[layerID];
    379     if (layerRecord.waitData < 0 ||
    380         layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
    381         return;
    382     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
    383     if (timeRecord.frameTime.frameNumber == frameNumber) {
    384         timeRecord.frameTime.presentTime = presentTime;
    385         timeRecord.ready = true;
    386         layerRecord.waitData++;
    387     }
    388 
    389     flushAvailableRecordsToStatsLocked(layerID);
    390 }
    391 
    392 void TimeStats::setPresentFence(int32_t layerID, uint64_t frameNumber,
    393                                 const std::shared_ptr<FenceTime>& presentFence) {
    394     if (!mEnabled.load()) return;
    395 
    396     ATRACE_CALL();
    397     ALOGV("[%d]-[%" PRIu64 "]-PresentFenceTime[%" PRId64 "]", layerID, frameNumber,
    398           presentFence->getSignalTime());
    399 
    400     std::lock_guard<std::mutex> lock(mMutex);
    401     if (!mTimeStatsTracker.count(layerID)) return;
    402     LayerRecord& layerRecord = mTimeStatsTracker[layerID];
    403     if (layerRecord.waitData < 0 ||
    404         layerRecord.waitData >= static_cast<int32_t>(layerRecord.timeRecords.size()))
    405         return;
    406     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
    407     if (timeRecord.frameTime.frameNumber == frameNumber) {
    408         timeRecord.presentFence = presentFence;
    409         timeRecord.ready = true;
    410         layerRecord.waitData++;
    411     }
    412 
    413     flushAvailableRecordsToStatsLocked(layerID);
    414 }
    415 
    416 void TimeStats::onDestroy(int32_t layerID) {
    417     if (!mEnabled.load()) return;
    418 
    419     ATRACE_CALL();
    420     ALOGV("[%d]-onDestroy", layerID);
    421 
    422     std::lock_guard<std::mutex> lock(mMutex);
    423     if (!mTimeStatsTracker.count(layerID)) return;
    424     mTimeStatsTracker.erase(layerID);
    425 }
    426 
    427 void TimeStats::removeTimeRecord(int32_t layerID, uint64_t frameNumber) {
    428     if (!mEnabled.load()) return;
    429 
    430     ATRACE_CALL();
    431     ALOGV("[%d]-[%" PRIu64 "]-removeTimeRecord", layerID, frameNumber);
    432 
    433     std::lock_guard<std::mutex> lock(mMutex);
    434     if (!mTimeStatsTracker.count(layerID)) return;
    435     LayerRecord& layerRecord = mTimeStatsTracker[layerID];
    436     size_t removeAt = 0;
    437     for (const TimeRecord& record : layerRecord.timeRecords) {
    438         if (record.frameTime.frameNumber == frameNumber) break;
    439         removeAt++;
    440     }
    441     if (removeAt == layerRecord.timeRecords.size()) return;
    442     layerRecord.timeRecords.erase(layerRecord.timeRecords.begin() + removeAt);
    443     if (layerRecord.waitData > static_cast<int32_t>(removeAt)) {
    444         layerRecord.waitData--;
    445     }
    446     layerRecord.droppedFrames++;
    447 }
    448 
    449 void TimeStats::flushPowerTimeLocked() {
    450     if (!mEnabled.load()) return;
    451 
    452     nsecs_t curTime = systemTime();
    453     // elapsedTime is in milliseconds.
    454     int64_t elapsedTime = (curTime - mPowerTime.prevTime) / 1000000;
    455 
    456     switch (mPowerTime.powerMode) {
    457         case HWC_POWER_MODE_NORMAL:
    458             mTimeStats.displayOnTime += elapsedTime;
    459             break;
    460         case HWC_POWER_MODE_OFF:
    461         case HWC_POWER_MODE_DOZE:
    462         case HWC_POWER_MODE_DOZE_SUSPEND:
    463         default:
    464             break;
    465     }
    466 
    467     mPowerTime.prevTime = curTime;
    468 }
    469 
    470 void TimeStats::setPowerMode(int32_t powerMode) {
    471     if (!mEnabled.load()) {
    472         std::lock_guard<std::mutex> lock(mMutex);
    473         mPowerTime.powerMode = powerMode;
    474         return;
    475     }
    476 
    477     std::lock_guard<std::mutex> lock(mMutex);
    478     if (powerMode == mPowerTime.powerMode) return;
    479 
    480     flushPowerTimeLocked();
    481     mPowerTime.powerMode = powerMode;
    482 }
    483 
    484 void TimeStats::recordRefreshRate(uint32_t fps, nsecs_t duration) {
    485     std::lock_guard<std::mutex> lock(mMutex);
    486     if (mTimeStats.refreshRateStats.count(fps)) {
    487         mTimeStats.refreshRateStats[fps] += duration;
    488     } else {
    489         mTimeStats.refreshRateStats.insert({fps, duration});
    490     }
    491 }
    492 
    493 void TimeStats::flushAvailableGlobalRecordsToStatsLocked() {
    494     ATRACE_CALL();
    495 
    496     while (!mGlobalRecord.presentFences.empty()) {
    497         const nsecs_t curPresentTime = mGlobalRecord.presentFences.front()->getSignalTime();
    498         if (curPresentTime == Fence::SIGNAL_TIME_PENDING) break;
    499 
    500         if (curPresentTime == Fence::SIGNAL_TIME_INVALID) {
    501             ALOGE("GlobalPresentFence is invalid!");
    502             mGlobalRecord.prevPresentTime = 0;
    503             mGlobalRecord.presentFences.pop_front();
    504             continue;
    505         }
    506 
    507         ALOGV("GlobalPresentFenceTime[%" PRId64 "]",
    508               mGlobalRecord.presentFences.front()->getSignalTime());
    509 
    510         if (mGlobalRecord.prevPresentTime != 0) {
    511             const int32_t presentToPresentMs =
    512                     msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
    513             ALOGV("Global present2present[%d] prev[%" PRId64 "] curr[%" PRId64 "]",
    514                   presentToPresentMs, mGlobalRecord.prevPresentTime, curPresentTime);
    515             mTimeStats.presentToPresent.insert(presentToPresentMs);
    516         }
    517 
    518         mGlobalRecord.prevPresentTime = curPresentTime;
    519         mGlobalRecord.presentFences.pop_front();
    520     }
    521 }
    522 
    523 void TimeStats::setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) {
    524     if (!mEnabled.load()) return;
    525 
    526     ATRACE_CALL();
    527     std::lock_guard<std::mutex> lock(mMutex);
    528     if (presentFence == nullptr || !presentFence->isValid()) {
    529         mGlobalRecord.prevPresentTime = 0;
    530         return;
    531     }
    532 
    533     if (mPowerTime.powerMode != HWC_POWER_MODE_NORMAL) {
    534         // Try flushing the last present fence on HWC_POWER_MODE_NORMAL.
    535         flushAvailableGlobalRecordsToStatsLocked();
    536         mGlobalRecord.presentFences.clear();
    537         mGlobalRecord.prevPresentTime = 0;
    538         return;
    539     }
    540 
    541     if (mGlobalRecord.presentFences.size() == MAX_NUM_TIME_RECORDS) {
    542         // The front presentFence must be trapped in pending status in this
    543         // case. Try dequeuing the front one to recover.
    544         ALOGE("GlobalPresentFences is already at its maximum size[%zu]", MAX_NUM_TIME_RECORDS);
    545         mGlobalRecord.prevPresentTime = 0;
    546         mGlobalRecord.presentFences.pop_front();
    547     }
    548 
    549     mGlobalRecord.presentFences.emplace_back(presentFence);
    550     flushAvailableGlobalRecordsToStatsLocked();
    551 }
    552 
    553 void TimeStats::enable() {
    554     if (mEnabled.load()) return;
    555 
    556     ATRACE_CALL();
    557 
    558     std::lock_guard<std::mutex> lock(mMutex);
    559     mEnabled.store(true);
    560     mTimeStats.statsStart = static_cast<int64_t>(std::time(0));
    561     mPowerTime.prevTime = systemTime();
    562     ALOGD("Enabled");
    563 }
    564 
    565 void TimeStats::disable() {
    566     if (!mEnabled.load()) return;
    567 
    568     ATRACE_CALL();
    569 
    570     std::lock_guard<std::mutex> lock(mMutex);
    571     flushPowerTimeLocked();
    572     mEnabled.store(false);
    573     mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
    574     ALOGD("Disabled");
    575 }
    576 
    577 void TimeStats::clear() {
    578     ATRACE_CALL();
    579 
    580     std::lock_guard<std::mutex> lock(mMutex);
    581     mTimeStatsTracker.clear();
    582     mTimeStats.stats.clear();
    583     mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
    584     mTimeStats.statsEnd = 0;
    585     mTimeStats.totalFrames = 0;
    586     mTimeStats.missedFrames = 0;
    587     mTimeStats.clientCompositionFrames = 0;
    588     mTimeStats.displayOnTime = 0;
    589     mTimeStats.presentToPresent.hist.clear();
    590     mTimeStats.refreshRateStats.clear();
    591     mPowerTime.prevTime = systemTime();
    592     mGlobalRecord.prevPresentTime = 0;
    593     mGlobalRecord.presentFences.clear();
    594     ALOGD("Cleared");
    595 }
    596 
    597 bool TimeStats::isEnabled() {
    598     return mEnabled.load();
    599 }
    600 
    601 void TimeStats::dump(bool asProto, std::optional<uint32_t> maxLayers, std::string& result) {
    602     ATRACE_CALL();
    603 
    604     std::lock_guard<std::mutex> lock(mMutex);
    605     if (mTimeStats.statsStart == 0) {
    606         return;
    607     }
    608 
    609     mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
    610 
    611     flushPowerTimeLocked();
    612 
    613     if (asProto) {
    614         ALOGD("Dumping TimeStats as proto");
    615         SFTimeStatsGlobalProto timeStatsProto = mTimeStats.toProto(maxLayers);
    616         result.append(timeStatsProto.SerializeAsString().c_str(), timeStatsProto.ByteSize());
    617     } else {
    618         ALOGD("Dumping TimeStats as text");
    619         result.append(mTimeStats.toString(maxLayers));
    620         result.append("\n");
    621     }
    622 }
    623 
    624 } // namespace impl
    625 
    626 } // namespace android
    627