blob: 252c09ce536f0f9e06beda4c538c9b03905f3daf [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
Kevin DuBoise4f27a82019-11-12 11:41:41 -080019#include <memory>
20#include <mutex>
21#include <string>
22#include <string_view>
Kevin DuBoise4f27a82019-11-12 11:41:41 -080023
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080024#include <android-base/thread_annotations.h>
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -050025#include <ftl/small_map.h>
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080026
Kevin DuBoise4f27a82019-11-12 11:41:41 -080027#include "VSyncDispatch.h"
Leon Scroggins III67388622023-02-06 20:36:20 -050028#include "VsyncSchedule.h"
Kevin DuBoise4f27a82019-11-12 11:41:41 -080029
30namespace android::scheduler {
31
Dominik Laskowskib0054a22022-03-03 09:03:06 -080032class TimeKeeper;
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080033
Kevin DuBoise4f27a82019-11-12 11:41:41 -080034// VSyncDispatchTimerQueueEntry is a helper class representing internal state for each entry in
35// VSyncDispatchTimerQueue hoisted to public for unit testing.
36class VSyncDispatchTimerQueueEntry {
37public:
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 )
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080042 VSyncDispatchTimerQueueEntry(std::string name, VSyncDispatch::Callback,
Kevin DuBoisc94ca832019-11-26 12:56:24 -080043 nsecs_t minVsyncDistance);
Kevin DuBoise4f27a82019-11-12 11:41:41 -080044 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.
ramindani558f4a92024-02-16 15:49:23 -080051 ScheduleResult schedule(VSyncDispatch::ScheduleTiming, VSyncTracker&, nsecs_t now);
Kevin DuBoise4f27a82019-11-12 11:41:41 -080052 // This will update armed entries with the latest vsync information. Entry remains armed.
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080053 void update(VSyncTracker&, nsecs_t now);
Kevin DuBoise4f27a82019-11-12 11:41:41 -080054
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
Ady Abraham9c53ee72020-07-22 21:16:18 -070059 std::optional<nsecs_t> readyTime() const;
60
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -080061 std::optional<nsecs_t> targetVsync() const;
62
Kevin DuBoise4f27a82019-11-12 11:41:41 -080063 // 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();
Kevin DuBois5c18c1c2020-05-27 15:50:50 -070069
70 // Adds a pending upload of the earliestVSync and workDuration that will be applied on the next
71 // call to update()
ramindani32a88b12024-01-31 18:45:30 -080072 ScheduleResult addPendingWorkloadUpdate(VSyncTracker&, nsecs_t now,
73 VSyncDispatch::ScheduleTiming);
Kevin DuBois5c18c1c2020-05-27 15:50:50 -070074
75 // Checks if there is a pending update to the workload, returning true if so.
76 bool hasPendingWorkloadUpdate() const;
Kevin DuBoise4f27a82019-11-12 11:41:41 -080077 // End: functions that are not threadsafe.
78
Kevin DuBois2968afc2020-01-14 09:48:50 -080079 // Invoke the callback with the two given timestamps, moving the state from running->disarmed.
Ady Abraham9c53ee72020-07-22 21:16:18 -070080 void callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp, nsecs_t deadlineTimestamp);
Kevin DuBoise4f27a82019-11-12 11:41:41 -080081 // Block calling thread while the callback is executing.
82 void ensureNotRunning();
83
Ady Abraham5e7371c2020-03-24 14:47:24 -070084 void dump(std::string& result) const;
85
Kevin DuBoise4f27a82019-11-12 11:41:41 -080086private:
Ady Abrahamda8af4c2024-02-14 00:24:34 +000087 struct ArmingInfo {
88 nsecs_t mActualWakeupTime;
89 nsecs_t mActualVsyncTime;
90 nsecs_t mActualReadyTime;
91 };
92
Ady Abraham3fcfd8b2022-07-12 12:31:00 -070093 nsecs_t adjustVsyncIfNeeded(VSyncTracker& tracker, nsecs_t nextVsyncTime) const;
Ady Abrahamda8af4c2024-02-14 00:24:34 +000094 ArmingInfo update(VSyncTracker&, nsecs_t now, VSyncDispatch::ScheduleTiming,
95 std::optional<ArmingInfo>) const;
Ady Abraham3fcfd8b2022-07-12 12:31:00 -070096
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080097 const std::string mName;
98 const VSyncDispatch::Callback mCallback;
Kevin DuBoise4f27a82019-11-12 11:41:41 -080099
Ady Abraham9c53ee72020-07-22 21:16:18 -0700100 VSyncDispatch::ScheduleTiming mScheduleTiming;
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800101 const nsecs_t mMinVsyncDistance;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800102
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800103 std::optional<ArmingInfo> mArmedInfo;
104 std::optional<nsecs_t> mLastDispatchTime;
105
Ady Abraham9c53ee72020-07-22 21:16:18 -0700106 std::optional<VSyncDispatch::ScheduleTiming> mWorkloadUpdateInfo;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700107
Ady Abraham5e7371c2020-03-24 14:47:24 -0700108 mutable std::mutex mRunningMutex;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800109 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 */
117class VSyncDispatchTimerQueue : public VSyncDispatch {
118public:
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800119 // 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.
Leon Scroggins III67388622023-02-06 20:36:20 -0500126 VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper>, VsyncSchedule::TrackerPtr,
127 nsecs_t timerSlack, nsecs_t minVsyncDistance);
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800128 ~VSyncDispatchTimerQueue();
129
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800130 CallbackToken registerCallback(Callback, std::string callbackName) final;
131 void unregisterCallback(CallbackToken) final;
ramindani32a88b12024-01-31 18:45:30 -0800132 std::optional<ScheduleResult> schedule(CallbackToken, ScheduleTiming) final;
133 std::optional<ScheduleResult> update(CallbackToken, ScheduleTiming) final;
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800134 CancelResult cancel(CallbackToken) final;
135 void dump(std::string&) const final;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800136
137private:
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800138 VSyncDispatchTimerQueue(const VSyncDispatchTimerQueue&) = delete;
139 VSyncDispatchTimerQueue& operator=(const VSyncDispatchTimerQueue&) = delete;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800140
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500141 // The static capacity was chosen to exceed the expected number of callbacks.
Ady Abraham2139f732019-11-13 18:56:40 -0800142 using CallbackMap =
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500143 ftl::SmallMap<CallbackToken, std::shared_ptr<VSyncDispatchTimerQueueEntry>, 5>;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800144
145 void timerCallback();
146 void setTimer(nsecs_t, nsecs_t) REQUIRES(mMutex);
147 void rearmTimer(nsecs_t now) REQUIRES(mMutex);
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500148 void rearmTimerSkippingUpdateFor(nsecs_t now, CallbackMap::const_iterator skipUpdate)
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800149 REQUIRES(mMutex);
150 void cancelTimer() REQUIRES(mMutex);
ramindani32a88b12024-01-31 18:45:30 -0800151 std::optional<ScheduleResult> scheduleLocked(CallbackToken, ScheduleTiming) REQUIRES(mMutex);
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800152
Ray Chin7a1e7422023-07-17 16:39:22 +0800153 std::mutex mutable mMutex;
154
en.liu07e0e292023-07-05 19:01:52 +0800155 // During VSyncDispatchTimerQueue deconstruction, skip timerCallback to
156 // avoid crash
157 bool mRunning = true;
158
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800159 static constexpr nsecs_t kInvalidTime = std::numeric_limits<int64_t>::max();
160 std::unique_ptr<TimeKeeper> const mTimeKeeper;
Leon Scroggins III67388622023-02-06 20:36:20 -0500161 VsyncSchedule::TrackerPtr mTracker;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800162 nsecs_t const mTimerSlack;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800163 nsecs_t const mMinVsyncDistance;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800164
Dominik Laskowski43baf902023-11-17 18:13:11 -0500165 CallbackToken mCallbackToken GUARDED_BY(mMutex);
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800166
167 CallbackMap mCallbacks GUARDED_BY(mMutex);
168 nsecs_t mIntendedWakeupTime GUARDED_BY(mMutex) = kInvalidTime;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800169
Ady Abraham75398722020-04-07 14:08:45 -0700170 // For debugging purposes
171 nsecs_t mLastTimerCallback GUARDED_BY(mMutex) = kInvalidTime;
172 nsecs_t mLastTimerSchedule GUARDED_BY(mMutex) = kInvalidTime;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800173};
174
175} // namespace android::scheduler