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