7#include "greedyscheduler.h"
9#include <ekos_scheduler_debug.h>
14#include "ui_scheduler.h"
15#include "schedulerjob.h"
16#include "schedulerutils.h"
18#define TEST_PRINT if (false) fprintf
21constexpr int SCHEDULE_RESOLUTION_MINUTES = 2;
26GreedyScheduler::GreedyScheduler()
30void GreedyScheduler::setParams(
bool restartImmediately,
bool restartQueue,
31 bool rescheduleErrors,
int abortDelay,
32 int errorHandlingDelay)
34 setRescheduleAbortsImmediate(restartImmediately);
35 setRescheduleAbortsQueue(restartQueue);
36 setRescheduleErrors(rescheduleErrors);
37 setAbortDelaySeconds(abortDelay);
38 setErrorDelaySeconds(errorHandlingDelay);
47void GreedyScheduler::scheduleJobs(
const QList<SchedulerJob *> &jobs,
49 const QMap<QString, uint16_t> &capturedFramesCount,
58 scheduledJob =
nullptr;
61 prepareJobsForEvaluation(jobs, now, capturedFramesCount, logger);
64 const QList<SchedulerJob *> leadJobs = SchedulerUtils::filterLeadJobs(jobs);
66 scheduledJob = selectNextJob(leadJobs, now,
nullptr, SIMULATE, &when,
nullptr,
nullptr, &capturedFramesCount);
67 auto schedule = getSchedule();
68 if (logger !=
nullptr)
70 if (!schedule.empty())
75 for (
int i = schedule.size() - 1; i >= 0; i--)
76 logger->appendLogText(GreedyScheduler::jobScheduleString(schedule[i]));
77 logger->appendLogText(QString(
"Greedy Scheduler plan for the next 48 hours starting %1 (%2)s:")
80 else logger->appendLogText(QString(
"Greedy Scheduler: empty plan (%1s)").arg(timer.
elapsed() / 1000.0));
82 if (scheduledJob !=
nullptr)
84 qCDebug(KSTARS_EKOS_SCHEDULER)
85 << QString(
"Greedy Scheduler scheduling next job %1 at %2")
86 .arg(scheduledJob->getName(), when.
toString(
"hh:mm"));
88 scheduledJob->setStartupTime(when);
98bool GreedyScheduler::checkJob(
const QList<SchedulerJob *> &jobs,
100 const SchedulerJob *
const currentJob)
103 if (currentJob && currentJob->getStateTime().secsTo(now) < 5)
110 SimulationType simType = SIMULATE_EACH_JOB_ONCE;
111 if (m_SimSeconds > 0.2 ||
112 (m_LastCheckJobSim.isValid() && m_LastCheckJobSim.secsTo(now) < 60))
113 simType = DONT_SIMULATE;
115 const SchedulerJob *
next = selectNextJob(jobs, now, currentJob, simType, &startTime);
116 if (next == currentJob && now.
secsTo(startTime) <= 1)
118 if (simType != DONT_SIMULATE)
119 m_LastCheckJobSim = now;
126 qCDebug(KSTARS_EKOS_SCHEDULER)
127 << QString(
"Greedy Scheduler bumping current job %1 for %2 at %3")
128 .arg(currentJob->getName(), next ?
next->getName() :
"---", now.
toString(
"hh:mm"));
147void GreedyScheduler::prepareJobsForEvaluation(
148 const QList<SchedulerJob *> &jobs,
const QDateTime &now,
149 const QMap<QString, uint16_t> &capturedFramesCount, ModuleLogger *logger,
bool reestimateJobTimes)
const
152 foreach (SchedulerJob *job, jobs)
154 switch (job->getCompletionCondition())
158 if (job->getFinishAtTime().isValid() && job->getFinishAtTime() < now)
168 if (job->getRepeatsRemaining() == 0)
170 if (logger !=
nullptr)
logger->appendLogText(
i18n(
"Job '%1' has no more batches remaining.", job->getName()));
172 job->setEstimatedTime(0);
183 foreach (SchedulerJob *job, jobs)
185 switch (job->getState())
207 foreach (SchedulerJob *job, jobs)
215 if (reestimateJobTimes)
217 job->setEstimatedTime(-1);
218 if (SchedulerUtils::estimateJobTime(job, capturedFramesCount, logger) ==
false)
224 if (job->getEstimatedTime() == 0)
226 job->setRepeatsRemaining(0);
231 TEST_PRINT(stderr,
"JOB %s estimated time: %ld state %d\n", job->getName().toLatin1().data(), job->getEstimatedTime(),
241bool allowJob(
const SchedulerJob *job,
bool rescheduleAbortsImmediate,
bool rescheduleAbortsQueue,
bool rescheduleErrors)
245 if (job->getState() ==
SCHEDJOB_ABORTED && !rescheduleAbortsImmediate && !rescheduleAbortsQueue)
255QDateTime firstPossibleStart(
const SchedulerJob *job,
const QDateTime &now,
256 bool rescheduleAbortsQueue,
int abortDelaySeconds,
257 bool rescheduleErrors,
int errorDelaySeconds)
259 QDateTime possibleStart = now;
260 const QDateTime &abortTime = job->getLastAbortTime();
261 const QDateTime &errorTime = job->getLastErrorTime();
263 if (abortTime.
isValid() && rescheduleAbortsQueue)
265 auto abortStartTime = abortTime.
addSecs(abortDelaySeconds);
266 if (abortStartTime > now)
267 possibleStart = abortStartTime;
271 if (errorTime.
isValid() && rescheduleErrors)
273 auto errorStartTime = errorTime.
addSecs(errorDelaySeconds);
274 if (errorStartTime > now)
275 possibleStart = errorStartTime;
278 if (!possibleStart.
isValid() || possibleStart < now)
280 return possibleStart;
302SchedulerJob *GreedyScheduler::selectNextJob(
const QList<SchedulerJob *> &jobs,
const QDateTime &now,
303 const SchedulerJob *
const currentJob, SimulationType simType, QDateTime *when,
304 QDateTime *nextInterruption, QString *interruptReason,
305 const QMap<QString, uint16_t> *capturedFramesCount)
309 constexpr int MIN_RUN_SECS = 10 * 60;
312 constexpr int MAX_INTERRUPT_SECS = 30;
315 bool currentJobIsStartAt = (currentJob && currentJob->getFileStartupCondition() == START_AT &&
316 currentJob->getStartAtTime().isValid());
318 SchedulerJob * nextJob =
nullptr;
319 QString interruptStr;
321 for (
int i = 0; i < jobs.
size(); ++i)
323 SchedulerJob *
const job = jobs[i];
324 const bool evaluatingCurrentJob = (currentJob && (job == currentJob));
326 TEST_PRINT(stderr,
" considering %s (%s)\n", job->getName().toLatin1().data(), evaluatingCurrentJob ?
"evaluating" :
"");
328 if (!allowJob(job, rescheduleAbortsImmediate, rescheduleAbortsQueue, rescheduleErrors))
330 TEST_PRINT(stderr,
" not allowed\n");
335 QDateTime startSearchingtAt = firstPossibleStart(
336 job, now, rescheduleAbortsQueue, abortDelaySeconds, rescheduleErrors, errorDelaySeconds);
342 const QDateTime startTime = job->getNextPossibleStartTime(startSearchingtAt, SCHEDULE_RESOLUTION_MINUTES,
343 evaluatingCurrentJob);
348 if (nextJob ==
nullptr)
351 nextStart = startTime;
353 if (nextInterruption) *nextInterruption = QDateTime();
356 else if (Options::greedyScheduling())
360 const int runSecs = evaluatingCurrentJob ? MAX_INTERRUPT_SECS : MIN_RUN_SECS;
363 if (evaluatingCurrentJob && currentJobIsStartAt)
365 if (nextInterruption) *nextInterruption = QDateTime();
366 nextStart = startTime;
370 else if (startTime.
secsTo(nextStart) > runSecs)
374 if (nextInterruption) *nextInterruption = nextStart;
375 interruptStr = QString(
"interrupted by %1").
arg(nextJob->getName());
376 nextStart = startTime;
382 if (!currentJob && nextStart.
isValid() && now.
secsTo(nextStart) < MIN_RUN_SECS)
385 else if (evaluatingCurrentJob)
393 if (evaluatingCurrentJob)
break;
395 if (nextJob !=
nullptr)
401 for (
int i = 0; i < jobs.
size(); ++i)
403 SchedulerJob *
const atJob = jobs[i];
404 if (atJob == nextJob)
406 const QDateTime atTime = atJob->getStartAtTime();
407 if (atJob->getFileStartupCondition() == START_AT && atTime.
isValid())
409 if (!allowJob(atJob, rescheduleAbortsImmediate, rescheduleAbortsQueue, rescheduleErrors))
412 QDateTime startSearchingtAt = firstPossibleStart(
413 atJob, now, rescheduleAbortsQueue, abortDelaySeconds, rescheduleErrors,
417 const QDateTime atJobStartTime = atJob->getNextPossibleStartTime(startSearchingtAt, SCHEDULE_RESOLUTION_MINUTES, currentJob
418 && (atJob == currentJob));
422 const double startDelta = atJobStartTime.
secsTo(atTime);
423 if (fabs(startDelta) < 20 * 60)
429 const int gap = currentJob ==
nullptr ? MIN_RUN_SECS : 30;
430 if (nextStart.
secsTo(atJobStartTime) <= gap)
433 nextStart = atJobStartTime;
434 if (nextInterruption) *nextInterruption = QDateTime();
436 else if (nextInterruption)
440 if (!nextInterruption->
isValid() ||
441 atJobStartTime.
secsTo(*nextInterruption) < 0)
443 *nextInterruption = atJobStartTime;
444 interruptStr = QString(
"interrupted by %1").
arg(atJob->getName());
456 if (nextJob && !nextJob->getGroup().isEmpty() && Options::greedyScheduling() && nextJob->getCompletedIterations() > 0)
458 TEST_PRINT(stderr,
" Considering GROUPS (%d jobs) selected %s\n", jobs.
size(), nextJob->getName().toLatin1().data());
460 bool foundSelectedJob =
false;
461 for (
int i = 0; i < jobs.
size(); ++i)
463 SchedulerJob *
const job = jobs[i];
466 foundSelectedJob =
true;
470 TEST_PRINT(stderr,
" Job %s (group %s) %s (%d vs %d iterations) %s\n",
471 job->getName().toLatin1().data(), (job->getGroup() != nextJob->getGroup()) ?
"Different" :
"Same",
472 foundSelectedJob ?
"Found" :
"not found yet",
473 job->getCompletedIterations(), nextJob->getCompletedIterations(),
474 allowJob(job, rescheduleAbortsImmediate, rescheduleAbortsQueue, rescheduleErrors) ?
"allowed" :
"not allowed");
479 if (!foundSelectedJob ||
480 (job->getGroup() != nextJob->getGroup()) ||
481 (job->getCompletedIterations() >= nextJob->getCompletedIterations()) ||
482 !allowJob(job, rescheduleAbortsImmediate, rescheduleAbortsQueue, rescheduleErrors))
485 const bool evaluatingCurrentJob = (currentJob && (job == currentJob));
488 QDateTime startSearchingtAt = firstPossibleStart(
489 job, now, rescheduleAbortsQueue, abortDelaySeconds, rescheduleErrors, errorDelaySeconds);
492 const QDateTime startTime = job->getNextPossibleStartTime(startSearchingtAt, SCHEDULE_RESOLUTION_MINUTES,
493 evaluatingCurrentJob);
496 if (!startTime.
isValid() || startTime.
secsTo(nextStart) > MAX_INTERRUPT_SECS)
500 if (evaluatingCurrentJob && currentJobIsStartAt)
502 if (nextInterruption) *nextInterruption = QDateTime();
503 nextStart = startTime;
507 else if (startTime.
secsTo(nextStart) >= -MAX_INTERRUPT_SECS)
510 nextStart = startTime;
516 if (when !=
nullptr) *when = nextStart;
517 if (interruptReason !=
nullptr) *interruptReason = interruptStr;
524 unsetEvaluation(jobs);
526 QElapsedTimer simTimer;
528 constexpr int twoDays = 48 * 3600;
529 if (simType != DONT_SIMULATE && nextJob !=
nullptr)
531 QDateTime simulationLimit = now.
addSecs(twoDays);
533 QDateTime simEnd = simulate(jobs, now, simulationLimit, capturedFramesCount, simType);
537 if (!Options::rememberJobProgress() && Options::schedulerRepeatEverything())
539 int repeats = 0, maxRepeats = 5;
540 while (simEnd.
isValid() && simEnd.
secsTo(simulationLimit) > 0 && ++repeats < maxRepeats)
543 simEnd = simulate(jobs, simEnd, simulationLimit,
nullptr, simType);
547 m_SimSeconds = simTimer.
elapsed() / 1000.0;
553QDateTime GreedyScheduler::simulate(
const QList<SchedulerJob *> &jobs,
const QDateTime &time,
const QDateTime &endTime,
554 const QMap<QString, uint16_t> *capturedFramesCount, SimulationType simType)
556 TEST_PRINT(stderr,
"%d simulate()\n", __LINE__);
558 QList<SchedulerJob *> copiedJobs;
559 QList<SchedulerJob *> scheduledJobs;
560 QDateTime simEndTime;
562 foreach (SchedulerJob *job, jobs)
564 SchedulerJob *newJob =
new SchedulerJob();
568 newJob->followerJobs().clear();
569 newJob->clearSimulatedSchedule();
570 copiedJobs.
append(newJob);
571 job->setStopTime(QDateTime());
576 int numStartupCandidates = 0, numStartups = 0;
578 foreach (SchedulerJob *job, copiedJobs)
580 job->setStartupTime(QDateTime());
581 const auto state = job->getState();
584 numStartupCandidates++;
587 QMap<QString, uint16_t> capturedFramesCopy;
588 if (capturedFramesCount !=
nullptr)
589 capturedFramesCopy = *capturedFramesCount;
590 QList<SchedulerJob *>simJobs = copiedJobs;
591 prepareJobsForEvaluation(copiedJobs, time, capturedFramesCopy,
nullptr,
false);
593 QDateTime simTime = time;
595 bool exceededIterations =
false;
596 QHash<SchedulerJob*, int> workDone;
597 QHash<SchedulerJob*, int> originalIteration, originalSecsLeftIteration;
599 for(
int i = 0; i < simJobs.
size(); ++i)
600 workDone[simJobs[i]] = 0.0;
604 QDateTime jobStartTime;
605 QDateTime jobInterruptTime;
606 QString interruptReason;
610 SchedulerJob *selectedJob =
611 selectNextJob(simJobs, simTime,
nullptr, DONT_SIMULATE, &jobStartTime, &jobInterruptTime, &interruptReason);
612 if (selectedJob ==
nullptr)
615 TEST_PRINT(stderr,
"%d %s\n", __LINE__, QString(
"%1 starting at %2 interrupted at \"%3\" reason \"%4\"")
616 .arg(selectedJob->getName()).arg(jobStartTime.
toString(
"MM/dd hh:mm"))
617 .arg(jobInterruptTime.
toString(
"MM/dd hh:mm")).arg(interruptReason).toLatin1().data());
619 if (endTime.
isValid() && jobStartTime.
secsTo(endTime) < 0)
break;
624 QDateTime nextStartAtTime;
625 foreach (SchedulerJob *job, simJobs)
627 if (job != selectedJob &&
628 job->getStartupCondition() == START_AT &&
629 jobStartTime.
secsTo(job->getStartupTime()) > 0 &&
633 QDateTime startAtTime = job->getStartupTime();
634 if (!nextStartAtTime.
isValid() || nextStartAtTime.
secsTo(startAtTime) < 0)
635 nextStartAtTime = startAtTime;
639 QDateTime constraintStopTime = jobInterruptTime;
640 if (nextStartAtTime.
isValid() &&
641 (!constraintStopTime.
isValid() ||
642 nextStartAtTime.
secsTo(constraintStopTime) < 0))
644 constraintStopTime = nextStartAtTime;
645 TEST_PRINT(stderr,
"%d %s\n", __LINE__, QString(
" job will be interrupted by a START_AT job").toLatin1().data());
648 QString constraintReason;
650 QDateTime jobConstraintTime = selectedJob->getNextEndTime(jobStartTime, SCHEDULE_RESOLUTION_MINUTES, &constraintReason,
653 std::abs(jobConstraintTime.
secsTo(nextStartAtTime)) < 2 * SCHEDULE_RESOLUTION_MINUTES)
654 constraintReason =
"interrupted by start-at job";
655 TEST_PRINT(stderr,
"%d %s\n", __LINE__, QString(
" constraint \"%1\" reason \"%2\"")
656 .arg(jobConstraintTime.
toString(
"MM/dd hh:mm")).arg(constraintReason).toLatin1().data());
657 QDateTime jobCompletionTime;
658 TEST_PRINT(stderr,
"%d %s\n", __LINE__,
659 QString(
" estimated time = %1").arg(selectedJob->getEstimatedTime()).toLatin1().data());
660 if (selectedJob->getEstimatedTime() > 0)
663 const int timeLeft = selectedJob->getEstimatedTime() - workDone[selectedJob];
664 jobCompletionTime = jobStartTime.
addSecs(timeLeft);
665 TEST_PRINT(stderr,
"%d %s\n", __LINE__, QString(
" completion \"%1\" time left %2s")
666 .arg(jobCompletionTime.
toString(
"MM/dd hh:mm")).arg(timeLeft).toLatin1().data());
670 QDateTime jobStopTime = jobInterruptTime;
671 QString stopReason = jobStopTime.
isValid() ? interruptReason :
"";
672 if (jobConstraintTime.
isValid() && (!jobStopTime.
isValid() || jobStopTime.
secsTo(jobConstraintTime) < 0))
674 stopReason = constraintReason;
675 jobStopTime = jobConstraintTime;
676 TEST_PRINT(stderr,
"%d %s\n", __LINE__, QString(
" picked constraint").toLatin1().data());
678 if (jobCompletionTime.
isValid() && (!jobStopTime.
isValid() || jobStopTime.
secsTo(jobCompletionTime) < 0))
680 stopReason =
"job completion";
681 jobStopTime = jobCompletionTime;
682 TEST_PRINT(stderr,
"%d %s\n", __LINE__, QString(
" picked completion").toLatin1().data());
687 if (!selectedJob->getGroup().isEmpty() &&
688 (selectedJob->getCompletionCondition() == FINISH_LOOP ||
689 selectedJob->getCompletionCondition() == FINISH_REPEAT ||
690 selectedJob->getCompletionCondition() == FINISH_AT))
692 if (originalIteration.
find(selectedJob) == originalIteration.
end())
693 originalIteration[selectedJob] = selectedJob->getCompletedIterations();
694 if (originalSecsLeftIteration.
find(selectedJob) == originalSecsLeftIteration.
end())
695 originalSecsLeftIteration[selectedJob] = selectedJob->getEstimatedTimeLeftThisRepeat();
698 int leftThisRepeat = selectedJob->getEstimatedTimeLeftThisRepeat();
699 int secsPerRepeat = selectedJob->getEstimatedTimePerRepeat();
700 int secsLeftThisRepeat = (workDone[selectedJob] < leftThisRepeat) ?
701 leftThisRepeat - workDone[selectedJob] : secsPerRepeat;
703 TEST_PRINT(stderr,
"%d %s\n", __LINE__, QString(
" sec per repeat %1 sec left this repeat %2")
704 .arg(secsPerRepeat).arg(secsLeftThisRepeat).toLatin1().data());
706 if (workDone[selectedJob] == 0)
708 secsLeftThisRepeat += selectedJob->getEstimatedStartupTime();
709 TEST_PRINT(stderr,
"%d %s\n", __LINE__, QString(
" adding %1 to secsLeftThisRepeat")
710 .arg(selectedJob->getEstimatedStartupTime()).arg(secsLeftThisRepeat).toLatin1().data());
714 if (secsLeftThisRepeat > 0 &&
715 (!jobStopTime.
isValid() || secsLeftThisRepeat < jobStartTime.
secsTo(jobStopTime)))
717 auto tempStart = jobStartTime;
718 auto tempInterrupt = jobInterruptTime;
719 auto tempReason = stopReason;
720 SchedulerJob keepJob = *selectedJob;
722 auto t = jobStartTime.
addSecs(secsLeftThisRepeat);
723 int iteration = selectedJob->getCompletedIterations();
724 int iters = 0, maxIters = 20;
725 while ((!jobStopTime.
isValid() || t.secsTo(jobStopTime) > 0) && iters++ < maxIters)
727 selectedJob->setCompletedIterations(++iteration);
728 TEST_PRINT(stderr,
"%d %s\n", __LINE__, QString(
" iteration=%1").arg(iteration).toLatin1().data());
729 SchedulerJob *
next = selectNextJob(simJobs, t,
nullptr, DONT_SIMULATE, &tempStart, &tempInterrupt, &tempReason);
730 if (next != selectedJob)
732 stopReason =
"interrupted for group member";
734 TEST_PRINT(stderr,
"%d %s\n", __LINE__, QString(
" switched to group member %1 at %2")
735 .arg(next ==
nullptr ?
"null" :
next->getName()).arg(t.toString(
"MM/dd hh:mm")).toLatin1().data());
739 t = t.addSecs(secsPerRepeat);
741 *selectedJob = keepJob;
748 const int secondsRun = jobStartTime.
secsTo(jobStopTime);
749 workDone[selectedJob] += secondsRun;
751 if ((originalIteration.
find(selectedJob) != originalIteration.
end()) &&
752 (originalSecsLeftIteration.
find(selectedJob) != originalSecsLeftIteration.
end()))
754 int completedIterations = originalIteration[selectedJob];
755 if (workDone[selectedJob] >= originalSecsLeftIteration[selectedJob] &&
756 selectedJob->getEstimatedTimePerRepeat() > 0)
757 completedIterations +=
758 1 + (workDone[selectedJob] - originalSecsLeftIteration[selectedJob]) / selectedJob->getEstimatedTimePerRepeat();
759 TEST_PRINT(stderr,
"%d %s\n", __LINE__,
760 QString(
" work sets interations=%1").arg(completedIterations).toLatin1().data());
761 selectedJob->setCompletedIterations(completedIterations);
767 if (!selectedJob->getStartupTime().isValid())
770 selectedJob->setStartupTime(jobStartTime);
771 selectedJob->setStopTime(jobStopTime);
772 selectedJob->setStopReason(stopReason);
774 scheduledJobs.
append(selectedJob);
775 TEST_PRINT(stderr,
"%d %s\n", __LINE__, QString(
" Scheduled: %1 %2 -> %3 %4 work done %5s")
776 .arg(selectedJob->getName()).arg(selectedJob->getStartupTime().toString(
"MM/dd hh:mm"))
777 .arg(selectedJob->getStopTime().toString(
"MM/dd hh:mm")).arg(selectedJob->getStopReason())
778 .arg(workDone[selectedJob]).toLatin1().data());
782 TEST_PRINT(stderr,
"%d %s\n", __LINE__, QString(
" Added: %1 %2 -> %3 %4 work done %5s")
783 .arg(selectedJob->getName()).arg(jobStartTime.
toString(
"MM/dd hh:mm"))
784 .arg(jobStopTime.
toString(
"MM/dd hh:mm")).arg(stopReason)
785 .arg(workDone[selectedJob]).toLatin1().data());
789 if (selectedJob->getEstimatedTime() >= 0 &&
790 workDone[selectedJob] >= selectedJob->getEstimatedTime())
793 TEST_PRINT(stderr,
"%d %s\n", __LINE__, QString(
" job %1 is complete")
794 .arg(selectedJob->getName()).toLatin1().data());
796 selectedJob->appendSimulatedSchedule(JobSchedule(
nullptr, jobStartTime, jobStopTime, stopReason));
797 schedule.
append(JobSchedule(jobs[copiedJobs.
indexOf(selectedJob)], jobStartTime, jobStopTime, stopReason));
798 simEndTime = jobStopTime;
799 simTime = jobStopTime.
addSecs(60);
806 if (++iterations > std::max(20, numStartupCandidates))
808 exceededIterations =
true;
809 TEST_PRINT(stderr,
"%d %s\n", __LINE__, QString(
"ending simulation after %1 iterations")
810 .arg(iterations).toLatin1().data());
814 if (simType == SIMULATE_EACH_JOB_ONCE)
816 bool allJobsProcessedOnce =
true;
817 for (
const auto job : simJobs)
819 if (allowJob(job, rescheduleAbortsImmediate, rescheduleAbortsQueue, rescheduleErrors) &&
820 !job->getStartupTime().isValid())
822 allJobsProcessedOnce =
false;
826 if (allJobsProcessedOnce)
828 TEST_PRINT(stderr,
"%d ending simulation, all jobs processed once\n", __LINE__);
837 for (
int i = 0; i < jobs.
size(); ++i)
839 if (scheduledJobs.
indexOf(copiedJobs[i]) >= 0)
845 jobs[i]->setStartupTime(copiedJobs[i]->getStartupTime());
848 jobs[i]->setStopTime(copiedJobs[i]->getStopTime());
849 jobs[i]->setStopReason(copiedJobs[i]->getStopReason());
850 if (simType == SIMULATE)
851 jobs[i]->setSimulatedSchedule(copiedJobs[i]->getSimulatedSchedule());
856 unsetEvaluation(jobs);
858 return exceededIterations ? QDateTime() : simEndTime;
861void GreedyScheduler::unsetEvaluation(
const QList<SchedulerJob *> &jobs)
const
863 for (
int i = 0; i < jobs.
size(); ++i)
870QString GreedyScheduler::jobScheduleString(
const JobSchedule &jobSchedule)
872 return QString(
"%1\t%2 --> %3 \t%4")
873 .arg(jobSchedule.job->getName(), -10)
874 .arg(jobSchedule.startTime.toString(
"MM/dd hh:mm"),
875 jobSchedule.stopTime.toString(
"hh:mm"), jobSchedule.stopReason);
878void GreedyScheduler::printSchedule(
const QList<JobSchedule> &schedule)
880 foreach (
auto &line, schedule)
882 fprintf(stderr,
"%s\n", QString(
"%1 %2 --> %3 (%4)")
883 .arg(jobScheduleString(line)).toLatin1().data());
QString i18n(const char *text, const TYPE &arg...)
Ekos is an advanced Astrophotography tool for Linux.
@ SCHEDJOB_ABORTED
Job encountered a transitory issue while processing, and will be rescheduled.
@ SCHEDJOB_INVALID
Job has an incorrect configuration, and cannot proceed.
@ SCHEDJOB_ERROR
Job encountered a fatal issue while processing, and must be reset manually.
@ SCHEDJOB_COMPLETE
Job finished all required captures.
@ SCHEDJOB_EVALUATION
Job is being evaluated.
@ SCHEDJOB_SCHEDULED
Job was evaluated, and has a schedule.
@ SCHEDJOB_BUSY
Job is being processed.
@ SCHEDJOB_IDLE
Job was just created, and is not evaluated yet.
const QList< QKeySequence > & next()
QCA_EXPORT Logger * logger()
QDateTime addSecs(qint64 s) const const
bool isValid() const const
qint64 secsTo(const QDateTime &other) const const
QString toString(QStringView format, QCalendar cal) const const
qint64 elapsed() const const
iterator find(const Key &key)
void append(QList< T > &&value)
qsizetype indexOf(const AT &value, qsizetype from) const const
qsizetype size() const const
QString & append(QChar ch)
QString arg(Args &&... args) const const
QByteArray toLatin1() const const