• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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-adaptivecpu"
18 #define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
19 
20 #include "WorkDurationProcessor.h"
21 
22 #include <android-base/logging.h>
23 #include <utils/Trace.h>
24 
25 using std::chrono_literals::operator""ms;
26 using std::chrono_literals::operator""ns;
27 
28 // The standard target duration, based on 60 FPS. Durations submitted with different targets are
29 // normalized against this target. For example, a duration that was at 80% of its target will be
30 // scaled to 0.8 * kNormalTargetDuration.
31 constexpr std::chrono::nanoseconds kNormalTargetDuration = 16666666ns;
32 
33 // All durations shorter than this are ignored.
34 constexpr std::chrono::nanoseconds kMinDuration = 0ns;
35 
36 // All durations longer than this are ignored.
37 constexpr std::chrono::nanoseconds kMaxDuration = 600 * kNormalTargetDuration;
38 
39 // If we haven't processed a lot of batches, stop accepting new ones. In cases where the processing
40 // thread has crashed, but the reporting thread is still reporting, this prevents consuming large
41 // amounts of memory.
42 // TODO(b/213160386): Move to AdaptiveCpuConfig.
43 constexpr size_t kMaxUnprocessedBatches = 1000;
44 
45 namespace aidl {
46 namespace google {
47 namespace hardware {
48 namespace power {
49 namespace impl {
50 namespace pixel {
51 
ReportWorkDurations(const std::vector<WorkDuration> & workDurations,std::chrono::nanoseconds targetDuration)52 bool WorkDurationProcessor::ReportWorkDurations(const std::vector<WorkDuration> &workDurations,
53                                                 std::chrono::nanoseconds targetDuration) {
54     ATRACE_CALL();
55     LOG(VERBOSE) << "Received " << workDurations.size() << " work durations with target "
56                  << targetDuration.count() << "ns";
57     std::unique_lock<std::mutex> lock(mMutex);
58     if (mWorkDurationBatches.size() >= kMaxUnprocessedBatches) {
59         LOG(ERROR) << "Adaptive CPU isn't processing work durations fast enough";
60         mWorkDurationBatches.clear();
61         return false;
62     }
63     mWorkDurationBatches.emplace_back(workDurations, targetDuration);
64     return true;
65 }
66 
GetFeatures()67 WorkDurationFeatures WorkDurationProcessor::GetFeatures() {
68     ATRACE_CALL();
69 
70     std::vector<WorkDurationBatch> workDurationBatches;
71     {
72         ATRACE_NAME("lock");
73         std::unique_lock<std::mutex> lock(mMutex);
74         mWorkDurationBatches.swap(workDurationBatches);
75     }
76 
77     std::chrono::nanoseconds durationsSum = 0ns;
78     std::chrono::nanoseconds maxDuration = 0ns;
79     uint32_t numMissedDeadlines = 0;
80     uint32_t numDurations = 0;
81     for (const WorkDurationBatch &batch : workDurationBatches) {
82         for (const WorkDuration workDuration : batch.workDurations) {
83             std::chrono::nanoseconds duration(workDuration.durationNanos);
84             if (duration < kMinDuration || duration > kMaxDuration) {
85                 continue;
86             }
87 
88             // Normalise the duration and add it to the total.
89             // kMaxDuration * kStandardTarget.count() fits comfortably within int64_t.
90             std::chrono::nanoseconds durationNormalized =
91                     (duration * kNormalTargetDuration.count()) / batch.targetDuration.count();
92             durationsSum += durationNormalized;
93             maxDuration = std::max(maxDuration, durationNormalized);
94             if (duration > batch.targetDuration) {
95                 ++numMissedDeadlines;
96             }
97             ++numDurations;
98         }
99     }
100 
101     std::chrono::nanoseconds averageDuration = durationsSum / numDurations;
102     return {
103             .averageDuration = averageDuration,
104             .maxDuration = maxDuration,
105             .numMissedDeadlines = numMissedDeadlines,
106             .numDurations = numDurations,
107     };
108 }
109 
HasWorkDurations()110 bool WorkDurationProcessor::HasWorkDurations() {
111     std::unique_lock<std::mutex> lock(mMutex);
112     return !mWorkDurationBatches.empty();
113 }
114 
115 }  // namespace pixel
116 }  // namespace impl
117 }  // namespace power
118 }  // namespace hardware
119 }  // namespace google
120 }  // namespace aidl
121