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