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 
17 #pragma once
18 
19 #include <atomic>
20 #include <chrono>
21 #include <unordered_map>
22 #include <unordered_set>
23 
24 #include <ui/DisplayId.h>
25 #include <ui/FenceTime.h>
26 #include <utils/Mutex.h>
27 
28 // FMQ library in IPower does questionable conversions
29 #pragma clang diagnostic push
30 #pragma clang diagnostic ignored "-Wconversion"
31 #include <aidl/android/hardware/power/IPower.h>
32 #include <fmq/AidlMessageQueue.h>
33 #include <powermanager/PowerHalController.h>
34 #pragma clang diagnostic pop
35 
36 #include <compositionengine/impl/OutputCompositionState.h>
37 #include <scheduler/Time.h>
38 #include <ui/DisplayIdentification.h>
39 #include "../Scheduler/OneShotTimer.h"
40 
41 using namespace std::chrono_literals;
42 
43 namespace android {
44 
45 class SurfaceFlinger;
46 
47 namespace Hwc2 {
48 
49 class PowerAdvisor {
50 public:
51     virtual ~PowerAdvisor();
52 
53     // Initializes resources that cannot be initialized on construction
54     virtual void init() = 0;
55     // Used to indicate that power hints can now be reported
56     virtual void onBootFinished() = 0;
57     virtual void setExpensiveRenderingExpected(DisplayId displayId, bool expected) = 0;
58     virtual bool isUsingExpensiveRendering() = 0;
59     // Checks both if it's supported and if it's enabled; this is thread-safe since its values are
60     // set before onBootFinished, which gates all methods that run on threads other than SF main
61     virtual bool usePowerHintSession() = 0;
62     virtual bool supportsPowerHintSession() = 0;
63     virtual bool supportsGpuReporting() = 0;
64 
65     // Sends a power hint that updates to the target work duration for the frame
66     virtual void updateTargetWorkDuration(Duration targetDuration) = 0;
67     // Sends a power hint for the actual known work duration at the end of the frame
68     virtual void reportActualWorkDuration() = 0;
69     // Sets whether the power hint session is enabled
70     virtual void enablePowerHintSession(bool enabled) = 0;
71     // Initializes the power hint session
72     virtual bool startPowerHintSession(std::vector<int32_t>&& threadIds) = 0;
73     // Provides PowerAdvisor with gpu start time
74     virtual void setGpuStartTime(DisplayId displayId, TimePoint startTime) = 0;
75     // Provides PowerAdvisor with a copy of the gpu fence so it can determine the gpu end time
76     virtual void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) = 0;
77     // Reports the start and end times of a hwc validate call this frame for a given display
78     virtual void setHwcValidateTiming(DisplayId displayId, TimePoint validateStartTime,
79                                       TimePoint validateEndTime) = 0;
80     // Reports the start and end times of a hwc present call this frame for a given display
81     virtual void setHwcPresentTiming(DisplayId displayId, TimePoint presentStartTime,
82                                      TimePoint presentEndTime) = 0;
83     // Reports the expected time that the current frame will present to the display
84     virtual void setExpectedPresentTime(TimePoint expectedPresentTime) = 0;
85     // Reports the most recent present fence time and end time once known
86     virtual void setSfPresentTiming(TimePoint presentFenceTime, TimePoint presentEndTime) = 0;
87     // Reports whether a display requires RenderEngine to draw
88     virtual void setRequiresRenderEngine(DisplayId displayId, bool requiresRenderEngine) = 0;
89     // Reports whether a given display skipped validation this frame
90     virtual void setSkippedValidate(DisplayId displayId, bool skipped) = 0;
91     // Reports when a hwc present is delayed, and the time that it will resume
92     virtual void setHwcPresentDelayedTime(DisplayId displayId,
93                                           TimePoint earliestFrameStartTime) = 0;
94     // Reports the start delay for SurfaceFlinger this frame
95     virtual void setFrameDelay(Duration frameDelayDuration) = 0;
96     // Reports the SurfaceFlinger commit start time this frame
97     virtual void setCommitStart(TimePoint commitStartTime) = 0;
98     // Reports the SurfaceFlinger composite end time this frame
99     virtual void setCompositeEnd(TimePoint compositeEndTime) = 0;
100     // Reports the list of the currently active displays
101     virtual void setDisplays(std::vector<DisplayId>& displayIds) = 0;
102     // Sets the target duration for the entire pipeline including the gpu
103     virtual void setTotalFrameTargetWorkDuration(Duration targetDuration) = 0;
104 
105     // --- The following methods may run on threads besides SF main ---
106     // Send a hint about an upcoming increase in the CPU workload
107     virtual void notifyCpuLoadUp() = 0;
108     // Send a hint about the imminent start of a new CPU workload
109     virtual void notifyDisplayUpdateImminentAndCpuReset() = 0;
110 };
111 
112 namespace impl {
113 
114 // PowerAdvisor is a wrapper around IPower HAL which takes into account the
115 // full state of the system when sending out power hints to things like the GPU.
116 class PowerAdvisor final : public Hwc2::PowerAdvisor {
117 public:
118     PowerAdvisor(SurfaceFlinger& flinger);
119     ~PowerAdvisor() override;
120 
121     void init() override;
122     void onBootFinished() override;
123     void setExpensiveRenderingExpected(DisplayId displayId, bool expected) override;
isUsingExpensiveRendering()124     bool isUsingExpensiveRendering() override { return mNotifiedExpensiveRendering; };
125     bool usePowerHintSession() override;
126     bool supportsPowerHintSession() override;
127     bool supportsGpuReporting() override;
128     void updateTargetWorkDuration(Duration targetDuration) override;
129     void reportActualWorkDuration() override;
130     void enablePowerHintSession(bool enabled) override;
131     bool startPowerHintSession(std::vector<int32_t>&& threadIds) override;
132     void setGpuStartTime(DisplayId displayId, TimePoint startTime) override;
133     void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) override;
134     void setHwcValidateTiming(DisplayId displayId, TimePoint validateStartTime,
135                               TimePoint validateEndTime) override;
136     void setHwcPresentTiming(DisplayId displayId, TimePoint presentStartTime,
137                              TimePoint presentEndTime) override;
138     void setSkippedValidate(DisplayId displayId, bool skipped) override;
139     void setRequiresRenderEngine(DisplayId displayId, bool requiresRenderEngine);
140     void setExpectedPresentTime(TimePoint expectedPresentTime) override;
141     void setSfPresentTiming(TimePoint presentFenceTime, TimePoint presentEndTime) override;
142     void setHwcPresentDelayedTime(DisplayId displayId, TimePoint earliestFrameStartTime) override;
143     void setFrameDelay(Duration frameDelayDuration) override;
144     void setCommitStart(TimePoint commitStartTime) override;
145     void setCompositeEnd(TimePoint compositeEndTime) override;
146     void setDisplays(std::vector<DisplayId>& displayIds) override;
147     void setTotalFrameTargetWorkDuration(Duration targetDuration) override;
148 
149     // --- The following methods may run on threads besides SF main ---
150     void notifyCpuLoadUp() override;
151     void notifyDisplayUpdateImminentAndCpuReset() override;
152 
153 private:
154     friend class PowerAdvisorTest;
155 
156     std::unique_ptr<power::PowerHalController> mPowerHal;
157     std::atomic_bool mBootFinished = false;
158 
159     std::unordered_set<DisplayId> mExpensiveDisplays;
160     bool mNotifiedExpensiveRendering = false;
161 
162     SurfaceFlinger& mFlinger;
163     std::atomic_bool mSendUpdateImminent = true;
164     std::atomic<nsecs_t> mLastScreenUpdatedTime = 0;
165     std::optional<scheduler::OneShotTimer> mScreenUpdateTimer;
166 
167     // Higher-level timing data used for estimation
168     struct DisplayTimeline {
169         // The start of hwc present, or the start of validate if it happened there instead
170         TimePoint hwcPresentStartTime;
171         // The end of hwc present or validate, whichever one actually presented
172         TimePoint hwcPresentEndTime;
173         // How long the actual hwc present was delayed after hwcPresentStartTime
174         Duration hwcPresentDelayDuration{0ns};
175         // When we think we started waiting for the present fence after calling into hwc present and
176         // after potentially waiting for the earliest present time
177         TimePoint presentFenceWaitStartTime;
178         // How long we ran after we finished waiting for the fence but before hwc present finished
179         Duration postPresentFenceHwcPresentDuration{0ns};
180         // Are we likely to have waited for the present fence during composition
181         bool probablyWaitsForPresentFence = false;
182     };
183 
184     struct GpuTimeline {
185         Duration duration{0ns};
186         TimePoint startTime;
187     };
188 
189     // Power hint session data recorded from the pipeline
190     struct DisplayTimingData {
191         std::unique_ptr<FenceTime> gpuEndFenceTime;
192         std::optional<TimePoint> gpuStartTime;
193         std::optional<TimePoint> lastValidGpuEndTime;
194         std::optional<TimePoint> lastValidGpuStartTime;
195         std::optional<TimePoint> hwcPresentStartTime;
196         std::optional<TimePoint> hwcPresentEndTime;
197         std::optional<TimePoint> hwcValidateStartTime;
198         std::optional<TimePoint> hwcValidateEndTime;
199         std::optional<TimePoint> hwcPresentDelayedTime;
200         bool requiresRenderEngine = false;
201         bool skippedValidate = false;
202         // Calculate high-level timing milestones from more granular display timing data
203         DisplayTimeline calculateDisplayTimeline(TimePoint fenceTime);
204         // Estimate the gpu duration for a given display from previous gpu timing data
205         std::optional<GpuTimeline> estimateGpuTiming(std::optional<TimePoint> previousEndTime);
206     };
207 
208     template <class T, size_t N>
209     class RingBuffer {
210         std::array<T, N> elements = {};
211         size_t mIndex = 0;
212         size_t numElements = 0;
213 
214     public:
append(T item)215         void append(T item) {
216             mIndex = (mIndex + 1) % N;
217             numElements = std::min(N, numElements + 1);
218             elements[mIndex] = item;
219         }
isFull()220         bool isFull() const { return numElements == N; }
221         // Allows access like [0] == current, [-1] = previous, etc..
222         T& operator[](int offset) {
223             size_t positiveOffset =
224                     static_cast<size_t>((offset % static_cast<int>(N)) + static_cast<int>(N));
225             return elements[(mIndex + positiveOffset) % N];
226         }
227     };
228 
229     // Filter and sort the display ids by a given property
230     std::vector<DisplayId> getOrderedDisplayIds(
231             std::optional<TimePoint> DisplayTimingData::*sortBy);
232     // Estimates a frame's total work duration including gpu and gpu time.
233     std::optional<aidl::android::hardware::power::WorkDuration> estimateWorkDuration();
234     // There are two different targets and actual work durations we care about,
235     // this normalizes them together and takes the max of the two
236     Duration combineTimingEstimates(Duration totalDuration, Duration flingerDuration);
237     // Whether to use the new "createHintSessionWithConfig" method
238     bool shouldCreateSessionWithConfig() REQUIRES(mHintSessionMutex);
239 
240     bool ensurePowerHintSessionRunning() REQUIRES(mHintSessionMutex);
241     void setUpFmq() REQUIRES(mHintSessionMutex);
242     std::unordered_map<DisplayId, DisplayTimingData> mDisplayTimingData;
243     // Current frame's delay
244     Duration mFrameDelayDuration{0ns};
245     // Last frame's post-composition duration
246     Duration mLastPostcompDuration{0ns};
247     // Buffer of recent commit start times
248     RingBuffer<TimePoint, 2> mCommitStartTimes;
249     // Buffer of recent expected present times
250     RingBuffer<TimePoint, 2> mExpectedPresentTimes;
251     // Most recent present fence time, provided by SF after composition engine finishes presenting
252     TimePoint mLastPresentFenceTime;
253     // Most recent composition engine present end time, returned with the present fence from SF
254     TimePoint mLastSfPresentEndTime;
255     // Target duration for the entire pipeline including gpu
256     std::optional<Duration> mTotalFrameTargetDuration;
257     // Updated list of display IDs
258     std::vector<DisplayId> mDisplayIds;
259 
260     // Ensure powerhal connection is initialized
261     power::PowerHalController& getPowerHal();
262 
263     // These variables are set before mBootFinished and never mutated after, so it's safe to access
264     // from threaded methods.
265     std::optional<bool> mHintSessionEnabled;
266     std::optional<bool> mSupportsHintSession;
267 
268     std::mutex mHintSessionMutex;
269     std::shared_ptr<power::PowerHintSessionWrapper> mHintSession GUARDED_BY(mHintSessionMutex) =
270             nullptr;
271 
272     // Initialize to true so we try to call, to check if it's supported
273     bool mHasExpensiveRendering = true;
274     bool mHasDisplayUpdateImminent = true;
275     // Queue of actual durations saved to report
276     std::vector<aidl::android::hardware::power::WorkDuration> mHintSessionQueue;
277     std::unique_ptr<::android::AidlMessageQueue<
278             aidl::android::hardware::power::ChannelMessage,
279             ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>>
280             mMsgQueue GUARDED_BY(mHintSessionMutex);
281     std::unique_ptr<::android::AidlMessageQueue<
282             int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>>
283             mFlagQueue GUARDED_BY(mHintSessionMutex);
284     android::hardware::EventFlag* mEventFlag;
285     uint32_t mFmqWriteMask;
286     // The latest values we have received for target and actual
287     Duration mTargetDuration = kDefaultTargetDuration;
288     // The list of thread ids, stored so we can restart the session from this class if needed
289     std::vector<int32_t> mHintSessionThreadIds;
290     Duration mLastTargetDurationSent = kDefaultTargetDuration;
291 
292     // Used to manage the execution ordering of reportActualWorkDuration for concurrency testing
293     std::promise<bool> mDelayReportActualMutexAcquisitonPromise;
294     bool mTimingTestingMode = false;
295 
296     // Hint session configuration data
297     aidl::android::hardware::power::SessionConfig mSessionConfig;
298 
299     // Whether createHintSessionWithConfig is supported, assume true until it fails
300     bool mSessionConfigSupported = true;
301     bool mFirstConfigSupportCheck = true;
302 
303     // Whether we should emit ATRACE_INT data for hint sessions
304     static const bool sTraceHintSessionData;
305 
306     // Default target duration for the hint session
307     static constexpr const Duration kDefaultTargetDuration{16ms};
308 
309     // An adjustable safety margin which pads the "actual" value sent to PowerHAL,
310     // encouraging more aggressive boosting to give SurfaceFlinger a larger margin for error
311     static const Duration sTargetSafetyMargin;
312     static constexpr const Duration kDefaultTargetSafetyMargin{1ms};
313 
314     // Whether we should send reportActualWorkDuration calls
315     static const bool sUseReportActualDuration;
316 
317     // How long we expect hwc to run after the present call until it waits for the fence
318     static constexpr const Duration kFenceWaitStartDelayValidated{150us};
319     static constexpr const Duration kFenceWaitStartDelaySkippedValidate{250us};
320 
321     void sendHintSessionHint(aidl::android::hardware::power::SessionHint hint);
322 
323     template <aidl::android::hardware::power::ChannelMessage::ChannelMessageContents::Tag T,
324               class In>
325     bool writeHintSessionMessage(In* elements, size_t count) REQUIRES(mHintSessionMutex);
326 };
327 
328 } // namespace impl
329 } // namespace Hwc2
330 } // namespace android
331