blob: 76e1caf4084ce38a15620f9c2d334345c98c469c [file] [log] [blame]
Kevin DuBoise4f27a82019-11-12 11:41:41 -08001/*
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 <functional>
21#include <memory>
22#include <mutex>
23#include <string>
24#include <string_view>
25#include <unordered_map>
26
27#include "VSyncDispatch.h"
28
29namespace android::scheduler {
30
31// VSyncDispatchTimerQueueEntry is a helper class representing internal state for each entry in
32// VSyncDispatchTimerQueue hoisted to public for unit testing.
33class VSyncDispatchTimerQueueEntry {
34public:
35 // This is the state of the entry. There are 3 states, armed, running, disarmed.
36 // Valid transition: disarmed -> armed ( when scheduled )
37 // Valid transition: armed -> running -> disarmed ( when timer is called)
38 // Valid transition: armed -> disarmed ( when cancelled )
Kevin DuBois2968afc2020-01-14 09:48:50 -080039 VSyncDispatchTimerQueueEntry(std::string const& name, VSyncDispatch::Callback const& fn,
Kevin DuBoisc94ca832019-11-26 12:56:24 -080040 nsecs_t minVsyncDistance);
Kevin DuBoise4f27a82019-11-12 11:41:41 -080041 std::string_view name() const;
42
43 // Start: functions that are not threadsafe.
44 // Return the last vsync time this callback was invoked.
45 std::optional<nsecs_t> lastExecutedVsyncTarget() const;
46
47 // This moves the state from disarmed->armed and will calculate the wakeupTime.
Ady Abraham9c53ee72020-07-22 21:16:18 -070048 ScheduleResult schedule(VSyncDispatch::ScheduleTiming timing, VSyncTracker& tracker,
Kevin DuBois2311b1a2019-11-18 16:19:08 -080049 nsecs_t now);
Kevin DuBoise4f27a82019-11-12 11:41:41 -080050 // This will update armed entries with the latest vsync information. Entry remains armed.
51 void update(VSyncTracker& tracker, nsecs_t now);
52
53 // This will return empty if not armed, or the next calculated wakeup time if armed.
54 // It will not update the wakeupTime.
55 std::optional<nsecs_t> wakeupTime() const;
56
Ady Abraham9c53ee72020-07-22 21:16:18 -070057 std::optional<nsecs_t> readyTime() const;
58
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -080059 std::optional<nsecs_t> targetVsync() const;
60
Kevin DuBoise4f27a82019-11-12 11:41:41 -080061 // 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();
Kevin DuBois5c18c1c2020-05-27 15:50:50 -070067
68 // Adds a pending upload of the earliestVSync and workDuration that will be applied on the next
69 // call to update()
Ady Abraham9c53ee72020-07-22 21:16:18 -070070 void addPendingWorkloadUpdate(VSyncDispatch::ScheduleTiming);
Kevin DuBois5c18c1c2020-05-27 15:50:50 -070071
72 // Checks if there is a pending update to the workload, returning true if so.
73 bool hasPendingWorkloadUpdate() const;
Kevin DuBoise4f27a82019-11-12 11:41:41 -080074 // End: functions that are not threadsafe.
75
Kevin DuBois2968afc2020-01-14 09:48:50 -080076 // Invoke the callback with the two given timestamps, moving the state from running->disarmed.
Ady Abraham9c53ee72020-07-22 21:16:18 -070077 void callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp, nsecs_t deadlineTimestamp);
Kevin DuBoise4f27a82019-11-12 11:41:41 -080078 // Block calling thread while the callback is executing.
79 void ensureNotRunning();
80
Ady Abraham5e7371c2020-03-24 14:47:24 -070081 void dump(std::string& result) const;
82
Kevin DuBoise4f27a82019-11-12 11:41:41 -080083private:
Kevin DuBoise4f27a82019-11-12 11:41:41 -080084 std::string const mName;
Kevin DuBois2968afc2020-01-14 09:48:50 -080085 VSyncDispatch::Callback const mCallback;
Kevin DuBoise4f27a82019-11-12 11:41:41 -080086
Ady Abraham9c53ee72020-07-22 21:16:18 -070087 VSyncDispatch::ScheduleTiming mScheduleTiming;
Kevin DuBoisc94ca832019-11-26 12:56:24 -080088 nsecs_t const mMinVsyncDistance;
Kevin DuBoise4f27a82019-11-12 11:41:41 -080089
90 struct ArmingInfo {
91 nsecs_t mActualWakeupTime;
92 nsecs_t mActualVsyncTime;
Ady Abraham9c53ee72020-07-22 21:16:18 -070093 nsecs_t mActualReadyTime;
Kevin DuBoise4f27a82019-11-12 11:41:41 -080094 };
95 std::optional<ArmingInfo> mArmedInfo;
96 std::optional<nsecs_t> mLastDispatchTime;
97
Ady Abraham9c53ee72020-07-22 21:16:18 -070098 std::optional<VSyncDispatch::ScheduleTiming> mWorkloadUpdateInfo;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -070099
Ady Abraham5e7371c2020-03-24 14:47:24 -0700100 mutable std::mutex mRunningMutex;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800101 std::condition_variable mCv;
102 bool mRunning GUARDED_BY(mRunningMutex) = false;
103};
104
105/*
106 * VSyncDispatchTimerQueue is a class that will dispatch callbacks as per VSyncDispatch interface
107 * using a single timer queue.
108 */
109class VSyncDispatchTimerQueue : public VSyncDispatch {
110public:
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800111 // Constructs a VSyncDispatchTimerQueue.
112 // \param[in] tk A timekeeper.
113 // \param[in] tracker A tracker.
114 // \param[in] timerSlack The threshold at which different similarly timed callbacks
115 // should be grouped into one wakeup.
116 // \param[in] minVsyncDistance The minimum distance between two vsync estimates before the
117 // vsyncs are considered the same vsync event.
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800118 explicit VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk, VSyncTracker& tracker,
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800119 nsecs_t timerSlack, nsecs_t minVsyncDistance);
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800120 ~VSyncDispatchTimerQueue();
121
Kevin DuBois2968afc2020-01-14 09:48:50 -0800122 CallbackToken registerCallback(Callback const& callbackFn, std::string callbackName) final;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800123 void unregisterCallback(CallbackToken token) final;
Ady Abraham9c53ee72020-07-22 21:16:18 -0700124 ScheduleResult schedule(CallbackToken token, ScheduleTiming scheduleTiming) final;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800125 CancelResult cancel(CallbackToken token) final;
Ady Abraham5e7371c2020-03-24 14:47:24 -0700126 void dump(std::string& result) const final;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800127
128private:
129 VSyncDispatchTimerQueue(VSyncDispatchTimerQueue const&) = delete;
130 VSyncDispatchTimerQueue& operator=(VSyncDispatchTimerQueue const&) = delete;
131
Ady Abraham2139f732019-11-13 18:56:40 -0800132 using CallbackMap =
133 std::unordered_map<CallbackToken, std::shared_ptr<VSyncDispatchTimerQueueEntry>>;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800134
135 void timerCallback();
136 void setTimer(nsecs_t, nsecs_t) REQUIRES(mMutex);
137 void rearmTimer(nsecs_t now) REQUIRES(mMutex);
138 void rearmTimerSkippingUpdateFor(nsecs_t now, CallbackMap::iterator const& skipUpdate)
139 REQUIRES(mMutex);
140 void cancelTimer() REQUIRES(mMutex);
141
142 static constexpr nsecs_t kInvalidTime = std::numeric_limits<int64_t>::max();
143 std::unique_ptr<TimeKeeper> const mTimeKeeper;
144 VSyncTracker& mTracker;
145 nsecs_t const mTimerSlack;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800146 nsecs_t const mMinVsyncDistance;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800147
148 std::mutex mutable mMutex;
149 size_t mCallbackToken GUARDED_BY(mMutex) = 0;
150
151 CallbackMap mCallbacks GUARDED_BY(mMutex);
152 nsecs_t mIntendedWakeupTime GUARDED_BY(mMutex) = kInvalidTime;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800153
Ady Abraham75398722020-04-07 14:08:45 -0700154 // For debugging purposes
155 nsecs_t mLastTimerCallback GUARDED_BY(mMutex) = kInvalidTime;
156 nsecs_t mLastTimerSchedule GUARDED_BY(mMutex) = kInvalidTime;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800157};
158
159} // namespace android::scheduler