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