• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2024 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 #define LOG_TAG "powerhal-libperfmgr"
18 
19 #include "SessionRecords.h"
20 
21 #include <android-base/logging.h>
22 
23 namespace aidl {
24 namespace google {
25 namespace hardware {
26 namespace power {
27 namespace impl {
28 namespace pixel {
29 
SessionRecords(const int32_t maxNumOfRecords,const double jankCheckTimeFactor)30 SessionRecords::SessionRecords(const int32_t maxNumOfRecords, const double jankCheckTimeFactor)
31     : kMaxNumOfRecords(maxNumOfRecords), kJankCheckTimeFactor(jankCheckTimeFactor) {
32     mRecords.resize(maxNumOfRecords);
33 }
34 
addReportedDurations(const std::vector<WorkDuration> & actualDurationsNs,int64_t targetDurationNs)35 void SessionRecords::addReportedDurations(const std::vector<WorkDuration> &actualDurationsNs,
36                                           int64_t targetDurationNs) {
37     for (auto &duration : actualDurationsNs) {
38         int32_t totalDurationUs = duration.durationNanos / 1000;
39 
40         if (mNumOfFrames >= kMaxNumOfRecords) {
41             // Remove the oldest record when the number of records is greater
42             // than allowed.
43             int32_t indexOfRecordToRemove = (mLatestRecordIndex + 1) % kMaxNumOfRecords;
44             mSumOfDurationsUs -= mRecords[indexOfRecordToRemove].totalDurationUs;
45             if (mRecords[indexOfRecordToRemove].isMissedCycle) {
46                 mNumOfMissedCycles--;
47                 if (mNumOfMissedCycles < 0) {
48                     LOG(ERROR) << "Invalid number of missed cycles: " << mNumOfMissedCycles;
49                 }
50             }
51             mNumOfFrames--;
52 
53             // If the record to be removed is the max duration, pop it out of the
54             // descending dequeue of record indexes.
55             if (mRecordsIndQueue.front() == indexOfRecordToRemove) {
56                 mRecordsIndQueue.pop_front();
57             }
58         }
59 
60         mLatestRecordIndex = (mLatestRecordIndex + 1) % kMaxNumOfRecords;
61 
62         // Track start delay
63         auto startTimeNs = duration.timeStampNanos - duration.durationNanos;
64         int32_t startIntervalUs = 0;
65         if (mNumOfFrames > 0) {
66             startIntervalUs = (startTimeNs - mLastStartTimeNs) / 1000;
67         }
68         mLastStartTimeNs = startTimeNs;
69 
70         bool cycleMissed = totalDurationUs > (targetDurationNs / 1000) * kJankCheckTimeFactor;
71         mRecords[mLatestRecordIndex] = CycleRecord{startIntervalUs, totalDurationUs, cycleMissed};
72         mNumOfFrames++;
73         if (cycleMissed) {
74             mNumOfMissedCycles++;
75         }
76 
77         // Pop out the indexes that their related values are not greater than the
78         // latest one.
79         while (!mRecordsIndQueue.empty() &&
80                (mRecords[mRecordsIndQueue.back()].totalDurationUs <= totalDurationUs)) {
81             mRecordsIndQueue.pop_back();
82         }
83         mRecordsIndQueue.push_back(mLatestRecordIndex);
84 
85         mSumOfDurationsUs += totalDurationUs;
86         mAvgDurationUs = mSumOfDurationsUs / mNumOfFrames;
87     }
88 }
89 
getMaxDuration()90 std::optional<int32_t> SessionRecords::getMaxDuration() {
91     if (mRecordsIndQueue.empty()) {
92         return std::nullopt;
93     }
94     return mRecords[mRecordsIndQueue.front()].totalDurationUs;
95 }
96 
getAvgDuration()97 std::optional<int32_t> SessionRecords::getAvgDuration() {
98     if (mNumOfFrames <= 0) {
99         return std::nullopt;
100     }
101     return mAvgDurationUs;
102 }
103 
getNumOfRecords()104 int32_t SessionRecords::getNumOfRecords() {
105     return mNumOfFrames;
106 }
107 
getNumOfMissedCycles()108 int32_t SessionRecords::getNumOfMissedCycles() {
109     return mNumOfMissedCycles;
110 }
111 
isLowFrameRate(int32_t fpsLowRateThreshold)112 bool SessionRecords::isLowFrameRate(int32_t fpsLowRateThreshold) {
113     // Check the last three records. If all of their start delays are larger
114     // than the cycle duration threshold, return "true".
115     auto cycleDurationThresholdUs = 1000000.0 / fpsLowRateThreshold;
116     if (mNumOfFrames >= 3) {  // Todo: make this number as a tunable config
117         int32_t ind1 = mLatestRecordIndex;
118         int32_t ind2 = ind1 == 0 ? (kMaxNumOfRecords - 1) : (ind1 - 1);
119         int32_t ind3 = ind2 == 0 ? (kMaxNumOfRecords - 1) : (ind2 - 1);
120         return (mRecords[ind1].startIntervalUs >= cycleDurationThresholdUs) &&
121                (mRecords[ind2].startIntervalUs >= cycleDurationThresholdUs) &&
122                (mRecords[ind3].startIntervalUs >= cycleDurationThresholdUs);
123     }
124 
125     return false;
126 }
127 
128 }  // namespace pixel
129 }  // namespace impl
130 }  // namespace power
131 }  // namespace hardware
132 }  // namespace google
133 }  // namespace aidl
134