File indexing completed on 2024-04-28 03:43:42
0001 /* Ekos Scheduler Greedy Algorithm 0002 SPDX-FileCopyrightText: Hy Murveit <hy@murveit.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #include <QList> 0010 #include <QMap> 0011 #include <QDateTime> 0012 #include <QObject> 0013 #include <QString> 0014 #include <QVector> 0015 0016 namespace Ekos 0017 { 0018 0019 class Scheduler; 0020 class SchedulerJob; 0021 class ModuleLogger; 0022 0023 class GreedyScheduler : public QObject 0024 { 0025 Q_OBJECT 0026 0027 public: 0028 0029 // Result of a scheduling operation. Mostly useful for testing 0030 // or logging, as the true schedule is stored in the Qlist<SchedulerJob*> 0031 // returned by scheduleJobs(). 0032 struct JobSchedule 0033 { 0034 SchedulerJob *job; 0035 QDateTime startTime; 0036 QDateTime stopTime; 0037 QString stopReason; 0038 JobSchedule(SchedulerJob *j, const QDateTime &start, const QDateTime &stop, const QString &r = "") 0039 : job(j), startTime(start), stopTime(stop), stopReason(r) {} 0040 }; 0041 0042 GreedyScheduler(); 0043 /** 0044 * @brief setParams Sets parameters, usually stored as KStars Options to the scheduler. 0045 * @param restartImmediately Aborted jobs should attempt to be restarted right after they were suspended. 0046 * @param restartQueue Aborted jobs should attempt to be restarted after a delay, given below. 0047 * @param rescheduleErrors Jobs that failed because of errors should be restarted after a delay. 0048 * @param abortDelay The minimum delay (seconds) for restarting aborted jobs. 0049 * @param errorHandlingDelay The minimum delay (seconds) for restarting jobs that failed with errors. 0050 */ 0051 void setParams(bool restartImmediately, bool restartQueue, 0052 bool rescheduleErrors, int abortDelay, 0053 int errorHandlingDelay); 0054 /** 0055 * @brief scheduleJobs Computes the schedule for job to be run. 0056 * @param jobs A list of SchedulerJobs 0057 * @param now The time at which the scheduling should start. 0058 * @param capturedFramesCount A structure, computed by the scheduler, which keeps track of previous job progress. 0059 * @param scheduler A pointer to the module logging, useful for notifying the user. Can be nullptr. 0060 */ 0061 void scheduleJobs(const QList<SchedulerJob *> &jobs, 0062 const QDateTime &now, 0063 const QMap<QString, uint16_t> &capturedFramesCount, 0064 ModuleLogger *logger); 0065 /** 0066 * @brief checkJob Checks to see if a job should continue running. 0067 * @param jobs A list of SchedulerJobs 0068 * @param now The time at which the decision should be made. 0069 * @param currentJob The currently running job, which may be continued or aborted. 0070 * @return returns true if the job should continue to run. 0071 */ 0072 bool checkJob(const QList<SchedulerJob *> &jobs, 0073 const QDateTime &now, 0074 const SchedulerJob * const currentJob); 0075 /** 0076 * @brief getScheduledJob Returns the first job scheduled. Must be called after scheduleJobs(). 0077 * @return returns the first job scheduled by scheduleJobs(), or nullptr. 0078 */ 0079 SchedulerJob *getScheduledJob() const 0080 { 0081 return scheduledJob; 0082 } 0083 /** 0084 * @brief getSchedule Returns the QList<JobSchedule> computed by scheduleJobs(). 0085 * @return returns the previously computed schedule. 0086 */ 0087 const QList<JobSchedule> &getSchedule() const 0088 { 0089 return schedule; 0090 } 0091 /** 0092 * @brief setRescheduleAbortsImmediate sets the rescheduleAbortsImmediate parameter. 0093 */ 0094 void setRescheduleAbortsImmediate(bool value) 0095 { 0096 rescheduleAbortsImmediate = value; 0097 } 0098 /** 0099 * @brief setRescheduleAbortsQueue sets the rescheduleAbortsQueue parameter. 0100 */ 0101 void setRescheduleAbortsQueue(bool value) 0102 { 0103 rescheduleAbortsQueue = value; 0104 } 0105 /** 0106 * @brief setRescheduleErrors sets the rescheduleErrors parameter. 0107 */ 0108 void setRescheduleErrors(bool value) 0109 { 0110 rescheduleErrors = value; 0111 } 0112 /** 0113 * @brief setAbortDelaySeconds sets the abortDelaySeconds parameter. 0114 */ 0115 void setAbortDelaySeconds(int value) 0116 { 0117 abortDelaySeconds = value; 0118 } 0119 /** 0120 * @brief setErrorDelaySeconds sets the errorDelaySeconds parameter. 0121 */ 0122 void setErrorDelaySeconds(int value) 0123 { 0124 errorDelaySeconds = value; 0125 } 0126 0127 // For debugging 0128 static void printJobs(const QList<SchedulerJob *> &jobs, const QDateTime &time, const QString &label = ""); 0129 static void printSchedule(const QList<JobSchedule> &schedule); 0130 static QString jobScheduleString(const JobSchedule &jobSchedule); 0131 0132 private: 0133 0134 // Changes the states of the jobs on the list, deciding which ones 0135 // can be scheduled by scheduleJobs(). This includes setting runnable 0136 // jobs to the JOB_EVALUATION state and updating their estimated time. 0137 // In addition, jobs with no remaining time are marked JOB_COMPLETED, 0138 // jobs with invalid sequence file as JOB_INVALID. 0139 void prepareJobsForEvaluation(const QList<SchedulerJob *> &jobs, const QDateTime &now, 0140 const QMap<QString, uint16_t> &capturedFramesCount, ModuleLogger *scheduler, bool reestimateJobTime = true) const; 0141 0142 // Removes the EVALUATION state, after eval is done. 0143 void unsetEvaluation(const QList<SchedulerJob *> &jobs) const; 0144 0145 typedef enum { 0146 DONT_SIMULATE = 0, 0147 SIMULATE, 0148 SIMULATE_EACH_JOB_ONCE 0149 } SimulationType; 0150 0151 // If currentJob is nullptr, this is used to find the next job 0152 // to schedule. It returns a pointer to a job in jobs, or nullptr. 0153 // If currentJob is a pointer to a job in jobs, then it will return 0154 // either currentJob if it shouldn't be interrupted, or a pointer 0155 // to a job that should interrupt it. If simType is not DONT_SIMULATE, 0156 // {@see #simulate()} is invoked to update the schedule. 0157 SchedulerJob *selectNextJob(const QList<SchedulerJob *> &jobs, 0158 const QDateTime &now, 0159 const SchedulerJob * const currentJob, 0160 SimulationType simType, 0161 QDateTime *when = nullptr, 0162 QDateTime *nextInterruption = nullptr, 0163 QString *interruptReason = nullptr, 0164 const QMap<QString, uint16_t> *capturedFramesCount = nullptr); 0165 0166 // Simulate the running of the scheduler from time to endTime by appending 0167 // JobSchedule entries to the schedule. 0168 // Used to find which jobs will be run in the future. 0169 // Returns the end time of the simulation. 0170 QDateTime simulate(const QList<SchedulerJob *> &jobs, const QDateTime &time, 0171 const QDateTime &endTime, 0172 const QMap<QString, uint16_t> *capturedFramesCount, 0173 SimulationType simType); 0174 0175 // Error/Abort restart parameters. 0176 // Defaults don't matter much, will be set by UI. 0177 bool rescheduleAbortsImmediate { false }; 0178 bool rescheduleAbortsQueue { true }; 0179 bool rescheduleErrors {false}; 0180 int abortDelaySeconds { 3600 }; 0181 int errorDelaySeconds { 3600 }; 0182 0183 // These are values computed by scheduleJobs(), stored, and returned 0184 // by getScheduledJob() and getSchedule(). 0185 SchedulerJob *scheduledJob { nullptr }; 0186 QList<JobSchedule> schedule; 0187 0188 // The amount of time it took to simulate. 0189 // If it's quick, we may do it in checkJob to keep the schedule up-to-date. 0190 double m_SimSeconds = 0; 0191 // The time of the last simulation in checkJob(). 0192 // We don't simulate too frequently. 0193 QDateTime m_LastCheckJobSim; 0194 }; 0195 0196 } // namespace Ekos