Add start and stop time scheduling for regular time of day running or once off start/stop options.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
diff --git a/main.c b/main.c
index f902014..23e6372 100644
--- a/main.c
+++ b/main.c
@@ -304,6 +304,61 @@ struct thread_q *getq;
static int total_work;
struct work *staged_work = NULL;
+struct schedtime {
+ bool enable;
+ struct tm tm;
+};
+
+struct schedtime schedstart;
+struct schedtime schedstop;
+bool sched_paused;
+
+static bool time_before(struct tm *tm1, struct tm *tm2)
+{
+ if (tm1->tm_hour < tm2->tm_hour)
+ return true;
+ if (tm1->tm_hour == tm2->tm_hour && tm1->tm_min < tm2->tm_min)
+ return true;
+ return false;
+}
+
+static bool should_run(void)
+{
+ struct timeval tv;
+ struct tm tm;
+
+ if (!schedstart.enable && !schedstop.enable)
+ return true;
+
+ gettimeofday(&tv, NULL);
+ localtime_r(&tv.tv_sec, &tm);
+ if (schedstart.enable) {
+ if (!schedstop.enable) {
+ if (time_before(&tm, &schedstart.tm))
+ return false;
+
+ /* This is a once off event with no stop time set */
+ schedstart.enable = false;
+ return true;
+ }
+ if (time_before(&schedstart.tm, &schedstop.tm)) {
+ if (time_before(&tm, &schedstop.tm) && !time_before(&tm, &schedstart.tm))
+ return true;
+ return false;
+ } /* Times are reversed */
+ if (time_before(&tm, &schedstart.tm)) {
+ if (time_before(&tm, &schedstop.tm))
+ return true;
+ return false;
+ }
+ return true;
+ }
+ /* only schedstop.enable == true */
+ if (!time_before(&tm, &schedstop.tm))
+ return false;
+ return true;
+}
+
void get_datestamp(char *f, struct timeval *tv)
{
struct tm tm;
@@ -329,7 +384,6 @@ void get_timestamp(char *f, struct timeval *tv)
tm.tm_sec);
}
-
static void applog_and_exit(const char *fmt, ...)
{
va_list ap;
@@ -1039,6 +1093,14 @@ static char *enable_debug(bool *flag)
return NULL;
}
+static char *set_schedtime(const char *arg, struct schedtime *st)
+{
+ if (!strptime(arg, "%H:%M", &st->tm))
+ return "Invalid time set, should be HH:MM";
+ st->enable = true;
+ return NULL;
+}
+
/* These options are available from config file or commandline */
static struct opt_table opt_config_table[] = {
OPT_WITH_ARG("--algo|-a",
@@ -1154,6 +1216,12 @@ static struct opt_table opt_config_table[] = {
OPT_WITH_ARG("--scan-time|-s",
set_int_0_to_9999, opt_show_intval, &opt_scantime,
"Upper bound on time spent scanning current work, in seconds"),
+ OPT_WITH_ARG("--sched-start",
+ set_schedtime, NULL, &schedstart,
+ "Set a time of day in HH:MM to start mining (a once off without a stop time)"),
+ OPT_WITH_ARG("--sched-stop",
+ set_schedtime, NULL, &schedstop,
+ "Set a time of day in HH:MM to stop mining (will quit without a start time)"),
OPT_WITH_ARG("--shares",
opt_set_intval, NULL, &opt_shares,
"Quit after mining N shares (default: unlimited)"),
@@ -3489,6 +3557,18 @@ static void *miner_thread(void *userdata)
} else if (work_restart[thr_id].restart || stale_work(work) ||
work->blk.nonce >= MAXTHREADS - hashes_done)
needs_work = true;
+
+ if (unlikely(mythr->pause)) {
+ applog(LOG_WARNING, "Thread %d being disabled", thr_id);
+ mythr->rolling = mythr->cgpu->rolling = 0;
+ if (opt_debug)
+ applog(LOG_DEBUG, "Popping wakeup ping in miner thread");
+
+ thread_reportout(mythr);
+ tq_pop(mythr->q, NULL); /* Ignore ping that's popped */
+ thread_reportin(mythr);
+ applog(LOG_WARNING, "Thread %d being re-enabled", thr_id);
+ }
}
out:
@@ -3798,13 +3878,15 @@ static void *gpuminer_thread(void *userdata)
requested = true;
}
}
- if (unlikely(!gpu_devices[gpu])) {
+ if (unlikely(!gpu_devices[gpu] || mythr->pause)) {
applog(LOG_WARNING, "Thread %d being disabled", thr_id);
mythr->rolling = mythr->cgpu->rolling = 0;
if (opt_debug)
applog(LOG_DEBUG, "Popping wakeup ping in gpuminer thread");
+ thread_reportout(mythr);
tq_pop(mythr->q, NULL); /* Ignore ping that's popped */
+ thread_reportin(mythr);
applog(LOG_WARNING, "Thread %d being re-enabled", thr_id);
}
}
@@ -4182,7 +4264,43 @@ static void *watchdog_thread(void *userdata)
switch_pools(NULL);
}
- //for (i = 0; i < mining_threads; i++) {
+ if (!sched_paused && !should_run()) {
+ applog(LOG_WARNING, "Pausing execution as per stop time %02d:%02d scheduled",
+ schedstop.tm.tm_hour, schedstop.tm.tm_min);
+ if (!schedstart.enable) {
+ quit(0, "Terminating execution as planned");
+ break;
+ }
+
+ applog(LOG_WARNING, "Will restart execution as scheduled at %02d:%02d",
+ schedstart.tm.tm_hour, schedstart.tm.tm_min);
+ sched_paused = true;
+ for (i = 0; i < mining_threads; i++) {
+ struct thr_info *thr;
+ thr = &thr_info[i];
+
+ thr->pause = true;
+ }
+ } else if (sched_paused && should_run()) {
+ applog(LOG_WARNING, "Restarting execution as per start time %02d:%02d scheduled",
+ schedstart.tm.tm_hour, schedstart.tm.tm_min);
+ if (schedstop.enable)
+ applog(LOG_WARNING, "Will pause execution as scheduled at %02d:%02d",
+ schedstop.tm.tm_hour, schedstop.tm.tm_min);
+ sched_paused = false;
+
+ for (i = 0; i < mining_threads; i++) {
+ struct thr_info *thr;
+ thr = &thr_info[i];
+
+ /* Don't touch disabled GPUs */
+ if (thr->cgpu->is_gpu && !gpu_devices[thr->cgpu->cpu_gpu])
+ continue;
+ thr->pause = false;
+ tq_push(thr->q, &ping);
+ }
+ }
+
for (i = 0; i < gpu_threads; i++) {
struct thr_info *thr;
int gpu;
diff --git a/miner.h b/miner.h
index a33f452..3a6267f 100644
--- a/miner.h
+++ b/miner.h
@@ -179,6 +179,7 @@ struct thr_info {
struct timeval last;
struct timeval sick;
+ bool pause;
bool getwork;
double rolling;
};