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