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