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