blob: fd0a034423e9710956223c4aab6eaf4f823f64c0 [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>
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -080020#include <array>
Kevin DuBoise4f27a82019-11-12 11:41:41 -080021#include <functional>
22#include <memory>
23#include <mutex>
24#include <string>
25#include <string_view>
26#include <unordered_map>
27
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -080028#include "SchedulerUtils.h"
Kevin DuBoise4f27a82019-11-12 11:41:41 -080029#include "VSyncDispatch.h"
30
31namespace android::scheduler {
32
33// VSyncDispatchTimerQueueEntry is a helper class representing internal state for each entry in
34// VSyncDispatchTimerQueue hoisted to public for unit testing.
35class VSyncDispatchTimerQueueEntry {
36public:
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 )
Kevin DuBois2968afc2020-01-14 09:48:50 -080041 VSyncDispatchTimerQueueEntry(std::string const& name, VSyncDispatch::Callback const& fn,
Kevin DuBoisc94ca832019-11-26 12:56:24 -080042 nsecs_t minVsyncDistance);
Kevin DuBoise4f27a82019-11-12 11:41:41 -080043 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.
Kevin DuBois2311b1a2019-11-18 16:19:08 -080050 ScheduleResult schedule(nsecs_t workDuration, nsecs_t earliestVsync, VSyncTracker& tracker,
51 nsecs_t now);
Kevin DuBoise4f27a82019-11-12 11:41:41 -080052 // 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
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();
67 // End: functions that are not threadsafe.
68
Kevin DuBois2968afc2020-01-14 09:48:50 -080069 // Invoke the callback with the two given timestamps, moving the state from running->disarmed.
70 void callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp);
Kevin DuBoise4f27a82019-11-12 11:41:41 -080071 // Block calling thread while the callback is executing.
72 void ensureNotRunning();
73
74private:
Kevin DuBoise4f27a82019-11-12 11:41:41 -080075 std::string const mName;
Kevin DuBois2968afc2020-01-14 09:48:50 -080076 VSyncDispatch::Callback const mCallback;
Kevin DuBoise4f27a82019-11-12 11:41:41 -080077
78 nsecs_t mWorkDuration;
79 nsecs_t mEarliestVsync;
Kevin DuBoisc94ca832019-11-26 12:56:24 -080080 nsecs_t const mMinVsyncDistance;
Kevin DuBoise4f27a82019-11-12 11:41:41 -080081
82 struct ArmingInfo {
83 nsecs_t mActualWakeupTime;
84 nsecs_t mActualVsyncTime;
85 };
86 std::optional<ArmingInfo> mArmedInfo;
87 std::optional<nsecs_t> mLastDispatchTime;
88
89 std::mutex mRunningMutex;
90 std::condition_variable mCv;
91 bool mRunning GUARDED_BY(mRunningMutex) = false;
92};
93
94/*
95 * VSyncDispatchTimerQueue is a class that will dispatch callbacks as per VSyncDispatch interface
96 * using a single timer queue.
97 */
98class VSyncDispatchTimerQueue : public VSyncDispatch {
99public:
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800100 // Constructs a VSyncDispatchTimerQueue.
101 // \param[in] tk A timekeeper.
102 // \param[in] tracker A tracker.
103 // \param[in] timerSlack The threshold at which different similarly timed callbacks
104 // should be grouped into one wakeup.
105 // \param[in] minVsyncDistance The minimum distance between two vsync estimates before the
106 // vsyncs are considered the same vsync event.
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800107 explicit VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk, VSyncTracker& tracker,
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800108 nsecs_t timerSlack, nsecs_t minVsyncDistance);
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800109 ~VSyncDispatchTimerQueue();
110
Kevin DuBois2968afc2020-01-14 09:48:50 -0800111 CallbackToken registerCallback(Callback const& callbackFn, std::string callbackName) final;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800112 void unregisterCallback(CallbackToken token) final;
113 ScheduleResult schedule(CallbackToken token, nsecs_t workDuration, nsecs_t earliestVsync) final;
114 CancelResult cancel(CallbackToken token) final;
115
116private:
117 VSyncDispatchTimerQueue(VSyncDispatchTimerQueue const&) = delete;
118 VSyncDispatchTimerQueue& operator=(VSyncDispatchTimerQueue const&) = delete;
119
Ady Abraham2139f732019-11-13 18:56:40 -0800120 using CallbackMap =
121 std::unordered_map<CallbackToken, std::shared_ptr<VSyncDispatchTimerQueueEntry>>;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800122
123 void timerCallback();
124 void setTimer(nsecs_t, nsecs_t) REQUIRES(mMutex);
125 void rearmTimer(nsecs_t now) REQUIRES(mMutex);
126 void rearmTimerSkippingUpdateFor(nsecs_t now, CallbackMap::iterator const& skipUpdate)
127 REQUIRES(mMutex);
128 void cancelTimer() REQUIRES(mMutex);
129
130 static constexpr nsecs_t kInvalidTime = std::numeric_limits<int64_t>::max();
131 std::unique_ptr<TimeKeeper> const mTimeKeeper;
132 VSyncTracker& mTracker;
133 nsecs_t const mTimerSlack;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800134 nsecs_t const mMinVsyncDistance;
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800135
136 std::mutex mutable mMutex;
137 size_t mCallbackToken GUARDED_BY(mMutex) = 0;
138
139 CallbackMap mCallbacks GUARDED_BY(mMutex);
140 nsecs_t mIntendedWakeupTime GUARDED_BY(mMutex) = kInvalidTime;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800141
142 struct TraceBuffer {
143 static constexpr char const kTraceNamePrefix[] = "-alarm in:";
144 static constexpr char const kTraceNameSeparator[] = " for vs:";
145 static constexpr size_t kMaxNamePrint = 4;
146 static constexpr size_t kNumTsPrinted = 2;
147 static constexpr size_t maxlen = kMaxNamePrint + arrayLen(kTraceNamePrefix) +
148 arrayLen(kTraceNameSeparator) - 1 + (kNumTsPrinted * max64print);
149 std::array<char, maxlen> str_buffer;
150 void note(std::string_view name, nsecs_t in, nsecs_t vs);
151 } mTraceBuffer GUARDED_BY(mMutex);
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800152};
153
154} // namespace android::scheduler