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(VSyncDispatch::ScheduleTiming timing, 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> 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 void addPendingWorkloadUpdate(VSyncDispatch::ScheduleTiming); 73 74 // Checks if there is a pending update to the workload, returning true if so. 75 bool hasPendingWorkloadUpdate() const; 76 // End: functions that are not threadsafe. 77 78 // Invoke the callback with the two given timestamps, moving the state from running->disarmed. 79 void callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp, nsecs_t deadlineTimestamp); 80 // Block calling thread while the callback is executing. 81 void ensureNotRunning(); 82 83 void dump(std::string& result) const; 84 85 private: 86 std::string const mName; 87 VSyncDispatch::Callback const mCallback; 88 89 VSyncDispatch::ScheduleTiming mScheduleTiming; 90 nsecs_t const mMinVsyncDistance; 91 92 struct ArmingInfo { 93 nsecs_t mActualWakeupTime; 94 nsecs_t mActualVsyncTime; 95 nsecs_t mActualReadyTime; 96 }; 97 std::optional<ArmingInfo> mArmedInfo; 98 std::optional<nsecs_t> mLastDispatchTime; 99 100 std::optional<VSyncDispatch::ScheduleTiming> mWorkloadUpdateInfo; 101 102 mutable std::mutex mRunningMutex; 103 std::condition_variable mCv; 104 bool mRunning GUARDED_BY(mRunningMutex) = false; 105 }; 106 107 /* 108 * VSyncDispatchTimerQueue is a class that will dispatch callbacks as per VSyncDispatch interface 109 * using a single timer queue. 110 */ 111 class VSyncDispatchTimerQueue : public VSyncDispatch { 112 public: 113 // Constructs a VSyncDispatchTimerQueue. 114 // \param[in] tk A timekeeper. 115 // \param[in] tracker A tracker. 116 // \param[in] timerSlack The threshold at which different similarly timed callbacks 117 // should be grouped into one wakeup. 118 // \param[in] minVsyncDistance The minimum distance between two vsync estimates before the 119 // vsyncs are considered the same vsync event. 120 explicit VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk, VSyncTracker& tracker, 121 nsecs_t timerSlack, nsecs_t minVsyncDistance); 122 ~VSyncDispatchTimerQueue(); 123 124 CallbackToken registerCallback(Callback const& callbackFn, std::string callbackName) final; 125 void unregisterCallback(CallbackToken token) final; 126 ScheduleResult schedule(CallbackToken token, ScheduleTiming scheduleTiming) final; 127 CancelResult cancel(CallbackToken token) final; 128 void dump(std::string& result) const final; 129 130 private: 131 VSyncDispatchTimerQueue(VSyncDispatchTimerQueue const&) = delete; 132 VSyncDispatchTimerQueue& operator=(VSyncDispatchTimerQueue const&) = delete; 133 134 using CallbackMap = 135 std::unordered_map<CallbackToken, std::shared_ptr<VSyncDispatchTimerQueueEntry>>; 136 137 void timerCallback(); 138 void setTimer(nsecs_t, nsecs_t) REQUIRES(mMutex); 139 void rearmTimer(nsecs_t now) REQUIRES(mMutex); 140 void rearmTimerSkippingUpdateFor(nsecs_t now, CallbackMap::iterator const& skipUpdate) 141 REQUIRES(mMutex); 142 void cancelTimer() REQUIRES(mMutex); 143 144 static constexpr nsecs_t kInvalidTime = std::numeric_limits<int64_t>::max(); 145 std::unique_ptr<TimeKeeper> const mTimeKeeper; 146 VSyncTracker& mTracker; 147 nsecs_t const mTimerSlack; 148 nsecs_t const mMinVsyncDistance; 149 150 std::mutex mutable mMutex; 151 size_t mCallbackToken GUARDED_BY(mMutex) = 0; 152 153 CallbackMap mCallbacks GUARDED_BY(mMutex); 154 nsecs_t mIntendedWakeupTime GUARDED_BY(mMutex) = kInvalidTime; 155 156 struct TraceBuffer { 157 static constexpr char const kTraceNamePrefix[] = "-alarm in:"; 158 static constexpr char const kTraceNameSeparator[] = " for vs:"; 159 static constexpr size_t kMaxNamePrint = 4; 160 static constexpr size_t kNumTsPrinted = 2; 161 static constexpr size_t maxlen = kMaxNamePrint + arrayLen(kTraceNamePrefix) + 162 arrayLen(kTraceNameSeparator) - 1 + (kNumTsPrinted * max64print); 163 std::array<char, maxlen> str_buffer; 164 void note(std::string_view name, nsecs_t in, nsecs_t vs); 165 } mTraceBuffer GUARDED_BY(mMutex); 166 167 // For debugging purposes 168 nsecs_t mLastTimerCallback GUARDED_BY(mMutex) = kInvalidTime; 169 nsecs_t mLastTimerSchedule GUARDED_BY(mMutex) = kInvalidTime; 170 }; 171 172 } // namespace android::scheduler 173