• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 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 <memory>
20 #include <mutex>
21 #include <string>
22 #include <string_view>
23 
24 #include <android-base/thread_annotations.h>
25 #include <ftl/small_map.h>
26 
27 #include "VSyncDispatch.h"
28 #include "VsyncSchedule.h"
29 
30 namespace android::scheduler {
31 
32 class TimeKeeper;
33 
34 // VSyncDispatchTimerQueueEntry is a helper class representing internal state for each entry in
35 // VSyncDispatchTimerQueue hoisted to public for unit testing.
36 class VSyncDispatchTimerQueueEntry {
37 public:
38     // This is the state of the entry. There are 3 states, armed, running, disarmed.
39     // Valid transition: disarmed -> armed ( when scheduled )
40     // Valid transition: armed -> running -> disarmed ( when timer is called)
41     // Valid transition: armed -> disarmed ( when cancelled )
42     VSyncDispatchTimerQueueEntry(std::string name, VSyncDispatch::Callback,
43                                  nsecs_t minVsyncDistance);
44     std::string_view name() const;
45 
46     // Start: functions that are not threadsafe.
47     // Return the last vsync time this callback was invoked.
48     std::optional<nsecs_t> lastExecutedVsyncTarget() const;
49 
50     // This moves the state from disarmed->armed and will calculate the wakeupTime.
51     ScheduleResult schedule(VSyncDispatch::ScheduleTiming, VSyncTracker&, nsecs_t now);
52     // This will update armed entries with the latest vsync information. Entry remains armed.
53     void update(VSyncTracker&, nsecs_t now);
54 
55     // This will return empty if not armed, or the next calculated wakeup time if armed.
56     // It will not update the wakeupTime.
57     std::optional<nsecs_t> wakeupTime() const;
58 
59     std::optional<nsecs_t> readyTime() const;
60 
61     std::optional<nsecs_t> targetVsync() const;
62 
63     // This moves state from armed->disarmed.
64     void disarm();
65 
66     // This moves the state from armed->running.
67     // Store the timestamp that this was intended for as the last called timestamp.
68     nsecs_t executing();
69 
70     // Adds a pending upload of the earliestVSync and workDuration that will be applied on the next
71     // call to update()
72     ScheduleResult addPendingWorkloadUpdate(VSyncTracker&, nsecs_t now,
73                                             VSyncDispatch::ScheduleTiming);
74 
75     // Checks if there is a pending update to the workload, returning true if so.
76     bool hasPendingWorkloadUpdate() const;
77     // End: functions that are not threadsafe.
78 
79     // Invoke the callback with the two given timestamps, moving the state from running->disarmed.
80     void callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp, nsecs_t deadlineTimestamp);
81     // Block calling thread while the callback is executing.
82     void ensureNotRunning();
83 
84     void dump(std::string& result) const;
85 
86 private:
87     struct ArmingInfo {
88         nsecs_t mActualWakeupTime;
89         nsecs_t mActualVsyncTime;
90         nsecs_t mActualReadyTime;
91     };
92 
93     nsecs_t adjustVsyncIfNeeded(VSyncTracker& tracker, nsecs_t nextVsyncTime) const;
94     ArmingInfo getArmedInfo(VSyncTracker&, nsecs_t now, VSyncDispatch::ScheduleTiming,
95                             std::optional<ArmingInfo>) const;
96 
97     const std::string mName;
98     const VSyncDispatch::Callback mCallback;
99 
100     VSyncDispatch::ScheduleTiming mScheduleTiming;
101     const nsecs_t mMinVsyncDistance;
102 
103     std::optional<ArmingInfo> mArmedInfo;
104     std::optional<nsecs_t> mLastDispatchTime;
105 
106     std::optional<VSyncDispatch::ScheduleTiming> mWorkloadUpdateInfo;
107 
108     mutable std::mutex mRunningMutex;
109     std::condition_variable mCv;
110     bool mRunning GUARDED_BY(mRunningMutex) = false;
111 };
112 
113 /*
114  * VSyncDispatchTimerQueue is a class that will dispatch callbacks as per VSyncDispatch interface
115  * using a single timer queue.
116  */
117 class VSyncDispatchTimerQueue : public VSyncDispatch {
118 public:
119     // Constructs a VSyncDispatchTimerQueue.
120     // \param[in] tk                    A timekeeper.
121     // \param[in] tracker               A tracker.
122     // \param[in] timerSlack            The threshold at which different similarly timed callbacks
123     //                                  should be grouped into one wakeup.
124     // \param[in] minVsyncDistance      The minimum distance between two vsync estimates before the
125     //                                  vsyncs are considered the same vsync event.
126     VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper>, VsyncSchedule::TrackerPtr,
127                             nsecs_t timerSlack, nsecs_t minVsyncDistance);
128     ~VSyncDispatchTimerQueue();
129 
130     CallbackToken registerCallback(Callback, std::string callbackName) final;
131     void unregisterCallback(CallbackToken) final;
132     std::optional<ScheduleResult> schedule(CallbackToken, ScheduleTiming) final;
133     std::optional<ScheduleResult> update(CallbackToken, ScheduleTiming) final;
134     CancelResult cancel(CallbackToken) final;
135     void dump(std::string&) const final;
136 
137 private:
138     VSyncDispatchTimerQueue(const VSyncDispatchTimerQueue&) = delete;
139     VSyncDispatchTimerQueue& operator=(const VSyncDispatchTimerQueue&) = delete;
140 
141     // The static capacity was chosen to exceed the expected number of callbacks.
142     using CallbackMap =
143             ftl::SmallMap<CallbackToken, std::shared_ptr<VSyncDispatchTimerQueueEntry>, 5>;
144 
145     void timerCallback();
146     void setTimer(nsecs_t, nsecs_t) REQUIRES(mMutex);
147     void rearmTimer(nsecs_t now) REQUIRES(mMutex);
148     void rearmTimerSkippingUpdateFor(nsecs_t now, CallbackMap::const_iterator skipUpdate)
149             REQUIRES(mMutex);
150     void cancelTimer() REQUIRES(mMutex);
151     std::optional<ScheduleResult> scheduleLocked(CallbackToken, ScheduleTiming) REQUIRES(mMutex);
152 
153     std::mutex mutable mMutex;
154 
155     // During VSyncDispatchTimerQueue deconstruction, skip timerCallback to
156     // avoid crash
157     bool mRunning = true;
158 
159     static constexpr nsecs_t kInvalidTime = std::numeric_limits<int64_t>::max();
160     std::unique_ptr<TimeKeeper> const mTimeKeeper;
161     VsyncSchedule::TrackerPtr mTracker;
162     nsecs_t const mTimerSlack;
163     nsecs_t const mMinVsyncDistance;
164 
165     CallbackToken mCallbackToken GUARDED_BY(mMutex);
166 
167     CallbackMap mCallbacks GUARDED_BY(mMutex);
168     nsecs_t mIntendedWakeupTime GUARDED_BY(mMutex) = kInvalidTime;
169 
170     // For debugging purposes
171     nsecs_t mLastTimerCallback GUARDED_BY(mMutex) = kInvalidTime;
172     nsecs_t mLastTimerSchedule GUARDED_BY(mMutex) = kInvalidTime;
173 };
174 
175 } // namespace android::scheduler
176