Browse Source

Merge branch 'cg_merges_20130619a' into bfgminer

Luke Dashjr 12 years ago
parent
commit
2b9789dfea
11 changed files with 172 additions and 191 deletions
  1. 1 0
      .gitignore
  2. 16 25
      api.c
  3. 1 0
      deviceapi.c
  4. 5 10
      driver-avalon.c
  5. 5 1
      driver-modminer.c
  6. 2 3
      driver-opencl.c
  7. 21 90
      logging.c
  8. 36 10
      logging.h
  9. 67 46
      miner.c
  10. 9 4
      miner.h
  11. 9 2
      util.c

+ 1 - 0
.gitignore

@@ -47,6 +47,7 @@ lib/c++defs.h
 lib/libgnu.a
 lib/signal.h
 lib/string.h
+lib/stdint.h
 lib/warn-on-use.h
 
 mkinstalldirs

+ 16 - 25
api.c

@@ -124,7 +124,6 @@ char *WSAErrorMsg(void) {
 #endif
 
 static const char *UNAVAILABLE = " - API will not be available";
-static const char *INVAPIGROUPS = "Invalid --api-groups parameter";
 
 static const char *BLANK = "";
 static const char *COMMA = ",";
@@ -1485,7 +1484,7 @@ static void devdetail_an(struct io_data *io_data, struct cgpu_info *cgpu, bool i
 	char buf[TMPBUFSIZ];
 	int n = 0, i;
 
-	cgpu->utility = cgpu->accepted / ( total_secs ? total_secs : 1 ) * 60;
+	cgpu_utility(cgpu);
 
 	rd_lock(&devices_lock);
 	for (i = 0; i < total_devices; ++i) {
@@ -1519,7 +1518,7 @@ static void devstatus_an(struct io_data *io_data, struct cgpu_info *cgpu, bool i
 	char buf[TMPBUFSIZ];
 	int n = 0, i;
 
-	cgpu->utility = cgpu->accepted / ( total_secs ? total_secs : 1 ) * 60;
+	cgpu_utility(cgpu);
 
 	rd_lock(&devices_lock);
 	for (i = 0; i < total_devices; ++i) {
@@ -1536,7 +1535,7 @@ static void devstatus_an(struct io_data *io_data, struct cgpu_info *cgpu, bool i
 	root = api_add_string(root, "Status", status2str(cgpu->status), false);
 	if (cgpu->temp)
 		root = api_add_temp(root, "Temperature", &cgpu->temp, false);
-	double mhs = cgpu->total_mhashes / total_secs;
+	double mhs = cgpu->total_mhashes / cgpu_runtime(cgpu);
 	root = api_add_mhs(root, "MHS av", &mhs, false);
 	char mhsname[27];
 	sprintf(mhsname, "MHS %ds", opt_log_interval);
@@ -2768,10 +2767,12 @@ static int itemstats(struct io_data *io_data, int i, char *id, struct cgminer_st
 {
 	struct api_data *root = NULL;
 	char buf[TMPBUFSIZ];
+	double elapsed;
 
 	root = api_add_int(root, "STATS", &i, false);
 	root = api_add_string(root, "ID", id, false);
-	root = api_add_elapsed(root, "Elapsed", &(total_secs), false);
+	elapsed = stats_elapsed(stats);
+	root = api_add_elapsed(root, "Elapsed", &elapsed, false);
 	root = api_add_uint32(root, "Calls", &(stats->getwork_calls), false);
 	root = api_add_timeval(root, "Wait", &(stats->getwork_wait), false);
 	root = api_add_timeval(root, "Max", &(stats->getwork_wait_max), false);
@@ -3359,30 +3360,21 @@ static void setup_groups()
 			colon = strchr(ptr, ':');
 			if (colon)
 				*colon = '\0';
-			applog(LOG_WARNING, "API invalid group name '%s'", ptr);
-			quit(1, "%s", INVAPIGROUPS);
+			quit(1, "API invalid group name '%s'", ptr);
 		}
 
 		group = GROUP(*ptr);
-		if (!VALIDGROUP(group)) {
-			applog(LOG_WARNING, "API invalid group name '%c'", *ptr);
-			quit(1, "%s", INVAPIGROUPS);
-		}
+		if (!VALIDGROUP(group))
+			quit(1, "API invalid group name '%c'", *ptr);
 
-		if (group == PRIVGROUP) {
-			applog(LOG_WARNING, "API group name can't be '%c'", PRIVGROUP);
-			quit(1, "%s", INVAPIGROUPS);
-		}
+		if (group == PRIVGROUP)
+			quit(1, "API group name can't be '%c'", PRIVGROUP);
 
-		if (group == NOPRIVGROUP) {
-			applog(LOG_WARNING, "API group name can't be '%c'", NOPRIVGROUP);
-			quit(1, "%s", INVAPIGROUPS);
-		}
+		if (group == NOPRIVGROUP)
+			quit(1, "API group name can't be '%c'", NOPRIVGROUP);
 
-		if (apigroups[GROUPOFFSET(group)].commands != NULL) {
-			applog(LOG_WARNING, "API duplicate group name '%c'", *ptr);
-			quit(1, "%s", INVAPIGROUPS);
-		}
+		if (apigroups[GROUPOFFSET(group)].commands != NULL)
+			quit(1, "API duplicate group name '%c'", *ptr);
 
 		ptr += 2;
 
@@ -3416,8 +3408,7 @@ static void setup_groups()
 						*cmd = '\0';
 					}
 				} else {
-					applog(LOG_WARNING, "API unknown command '%s' in group '%c'", ptr, group);
-					quit(1, "%s", INVAPIGROUPS);
+					quit(1, "API unknown command '%s' in group '%c'", ptr, group);
 				}
 			}
 

+ 1 - 0
deviceapi.c

@@ -574,6 +574,7 @@ void *miner_thread(void *userdata)
 	applog(LOG_DEBUG, "Popping ping in miner thread");
 	notifier_read(mythr->notifier);  // Wait for a notification to start
 
+	cgtime(&cgpu->cgminer_stats.start_tv);
 	if (drv->minerloop)
 		drv->minerloop(mythr);
 	else

+ 5 - 10
driver-avalon.c

@@ -454,8 +454,7 @@ static void get_options(int this_option_offset, int *baud, int *miner_count,
 		*baud = 19200;
 		break;
 	default:
-		quit(1,
-			"Invalid avalon-options for baud (%s) "
+		quit(1, "Invalid avalon-options for baud (%s) "
 			"must be 115200, 57600, 38400 or 19200", buf);
 	}
 
@@ -469,8 +468,7 @@ static void get_options(int this_option_offset, int *baud, int *miner_count,
 			if (tmp > 0 && tmp <= AVALON_DEFAULT_MINER_NUM) {
 				*miner_count = tmp;
 			} else {
-				quit(1,
-					"Invalid avalon-options for "
+				quit(1, "Invalid avalon-options for "
 					"miner_count (%s) must be 1 ~ %d",
 					colon, AVALON_DEFAULT_MINER_NUM);
 			}
@@ -485,8 +483,7 @@ static void get_options(int this_option_offset, int *baud, int *miner_count,
 			if (tmp > 0 && tmp <= AVALON_DEFAULT_ASIC_NUM)
 				*asic_count = tmp;
 			else {
-				quit(1,
-					"Invalid avalon-options for "
+				quit(1, "Invalid avalon-options for "
 					"asic_count (%s) must be 1 ~ %d",
 					colon2, AVALON_DEFAULT_ASIC_NUM);
 			}
@@ -500,8 +497,7 @@ static void get_options(int this_option_offset, int *baud, int *miner_count,
 				if (tmp > 0 && tmp <= 0xff)
 					*timeout = tmp;
 				else {
-					quit(1,
-						"Invalid avalon-options for "
+					quit(1, "Invalid avalon-options for "
 						"timeout (%s) must be 1 ~ %d",
 						colon3, 0xff);
 				}
@@ -515,8 +511,7 @@ static void get_options(int this_option_offset, int *baud, int *miner_count,
 						*frequency = tmp;
 						break;
 					default:
-						quit(1,
-							"Invalid avalon-options for "
+						quit(1, "Invalid avalon-options for "
 							"frequency must be 256/270/282/300");
 					}
 				}

+ 5 - 1
driver-modminer.c

@@ -85,9 +85,12 @@ _bailout(int fd, struct cgpu_info*modminer, int prio, const char *fmt, ...)
 	}
 
 	va_list ap;
+	char buf[LOGBUFSIZ];
+	
 	va_start(ap, fmt);
-	vapplog(prio, fmt, ap);
+	vsnprintf(buf, sizeof(buf), fmt, ap);
 	va_end(ap);
+	_applog(prio, buf);
 	return false;
 }
 #define bailout(...)  return _bailout(fd, NULL, __VA_ARGS__);
@@ -792,6 +795,7 @@ static void
 modminer_fpga_shutdown(struct thr_info *thr)
 {
 	free(thr->cgpu_data);
+	thr->cgpu_data = NULL;
 }
 
 static char *modminer_set_device(struct cgpu_info *modminer, char *option, char *setting, char *replybuf)

+ 2 - 3
driver-opencl.c

@@ -265,7 +265,6 @@ extern void enable_curses(void);
 #endif
 
 extern int mining_threads;
-extern double total_secs;
 extern int opt_g_threads;
 extern bool ping;
 extern bool opt_loginput;
@@ -856,7 +855,7 @@ retry:
 		bool mhash_base = true;
 
 		displayed_rolling = cgpu->rolling;
-		displayed_total = cgpu->total_mhashes / total_secs;
+		displayed_total = cgpu->total_mhashes / cgpu_runtime(cgpu);
 		if (displayed_rolling < 1) {
 			displayed_rolling *= 1000;
 			displayed_total *= 1000;
@@ -898,7 +897,7 @@ retry:
 				if (powertune != -1)
 					tailsprintf(logline, "P: %d%%", powertune);
 				tailsprintf(logline, "\n");
-				wlog("%s", logline);
+				_wlog(logline);
 			}
 		}
 #endif

+ 21 - 90
logging.c

@@ -1,6 +1,7 @@
 /*
  * Copyright 2011-2012 Con Kolivas
  * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2013 Andrew Smith
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -15,7 +16,6 @@
 #include "compat.h"
 #include "logging.h"
 #include "miner.h"
-// #include "util.h"
 
 bool opt_debug = false;
 bool opt_debug_console = false;  // Only used if opt_debug is also enabled
@@ -25,66 +25,39 @@ bool opt_log_microseconds;
 /* per default priorities higher than LOG_NOTICE are logged */
 int opt_log_level = LOG_NOTICE;
 
-static void my_log_curses(int prio, char *f, va_list ap) FORMAT_SYNTAX_CHECK(printf, 2, 0);
-
-static void my_log_curses(__maybe_unused int prio, char *f, va_list ap)
+static void my_log_curses(int prio, const char *datetime, const char *str)
 {
 	if (opt_quiet && prio != LOG_ERR)
 		return;
 
 #ifdef HAVE_CURSES
 	extern bool use_curses;
-	if (use_curses && log_curses_only(prio, f, ap))
+	if (use_curses && log_curses_only(prio, datetime, str))
 		;
 	else
 #endif
 	{
-		int len = strlen(f);
 		int cancelstate;
 		bool scs;
-
-		strcpy(f + len - 1, "                    \n");
-
 		scs = !pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate);
 		mutex_lock(&console_lock);
-		vprintf(f, ap);
+		printf("%s%s%s", datetime, str, "                    \n");
 		mutex_unlock(&console_lock);
 		if (scs)
 			pthread_setcancelstate(cancelstate, &cancelstate);
 	}
 }
 
-static void log_generic(int prio, const char *fmt, va_list ap) FORMAT_SYNTAX_CHECK(printf, 2, 0);
-
-void vapplog(int prio, const char *fmt, va_list ap)
-{
-	if (!opt_debug && prio == LOG_DEBUG)
-		return;
-
-	log_generic(prio, fmt, ap);
-}
-
-void applog(int prio, const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	vapplog(prio, fmt, ap);
-	va_end(ap);
-}
-
-
-/* high-level logging functions, based on global opt_log_level */
+/* high-level logging function, based on global opt_log_level */
 
 /*
- * generic log function used by priority specific ones
- * equals vapplog() without additional priority checks
+ * log function
  */
-static void log_generic(int prio, const char *fmt, va_list ap)
+void _applog(int prio, const char *str)
 {
 #ifdef HAVE_SYSLOG_H
 	if (use_syslog) {
-		vsyslog(prio, fmt, ap);
+		syslog(prio, "%s", str);
 	}
 #else
 	if (0) {}
@@ -95,8 +68,7 @@ static void log_generic(int prio, const char *fmt, va_list ap)
 		if (!(writetocon || writetofile))
 			return;
 
-		char *f;
-		int len;
+		char datetime[64];
 		struct timeval tv = {0, 0};
 		struct tm _tm;
 		struct tm *tm = &_tm;
@@ -105,72 +77,31 @@ static void log_generic(int prio, const char *fmt, va_list ap)
 
 		localtime_r(&tv.tv_sec, tm);
 
-		// NOTE: my_log_curses appends 20 spaces
-		len = 40 + strlen(fmt) + 22  + 7 /* microseconds */;
-		f = alloca(len);
 		if (opt_log_microseconds)
-			sprintf(f, " [%d-%02d-%02d %02d:%02d:%02d.%06ld] %s\n",
+			sprintf(datetime, " [%d-%02d-%02d %02d:%02d:%02d.%06ld] ",
 				tm->tm_year + 1900,
 				tm->tm_mon + 1,
 				tm->tm_mday,
 				tm->tm_hour,
 				tm->tm_min,
 				tm->tm_sec,
-				(long)tv.tv_usec,
-				fmt);
+				(long)tv.tv_usec);
 		else
-		sprintf(f, " [%d-%02d-%02d %02d:%02d:%02d] %s\n",
-			tm->tm_year + 1900,
-			tm->tm_mon + 1,
-			tm->tm_mday,
-			tm->tm_hour,
-			tm->tm_min,
-			tm->tm_sec,
-			fmt);
+			sprintf(datetime, " [%d-%02d-%02d %02d:%02d:%02d] ",
+				tm->tm_year + 1900,
+				tm->tm_mon + 1,
+				tm->tm_mday,
+				tm->tm_hour,
+				tm->tm_min,
+				tm->tm_sec);
+
 		/* Only output to stderr if it's not going to the screen as well */
 		if (writetofile) {
-			va_list apc;
-
-			va_copy(apc, ap);
-			vfprintf(stderr, f, apc);	/* atomic write to stderr */
-			va_end(apc);
+			fprintf(stderr, "%s%s\n", datetime, str);	/* atomic write to stderr */
 			fflush(stderr);
 		}
 
 		if (writetocon)
-			my_log_curses(prio, f, ap);
+			my_log_curses(prio, datetime, str);
 	}
 }
-/* we can not generalize variable argument list */
-#define LOG_TEMPLATE(PRIO)		\
-	if (PRIO <= opt_log_level) {	\
-		va_list ap;		\
-		va_start(ap, fmt);	\
-		vapplog(PRIO, fmt, ap);	\
-		va_end(ap);		\
-	}
-
-void log_error(const char *fmt, ...)
-{
-	LOG_TEMPLATE(LOG_ERR);
-}
-
-void log_warning(const char *fmt, ...)
-{
-	LOG_TEMPLATE(LOG_WARNING);
-}
-
-void log_notice(const char *fmt, ...)
-{
-	LOG_TEMPLATE(LOG_NOTICE);
-}
-
-void log_info(const char *fmt, ...)
-{
-	LOG_TEMPLATE(LOG_INFO);
-}
-
-void log_debug(const char *fmt, ...)
-{
-	LOG_TEMPLATE(LOG_DEBUG);
-}

+ 36 - 10
logging.h

@@ -26,7 +26,7 @@ enum {
 };
 #endif
 
-/* original / legacy debug flags */
+/* debug flags */
 extern bool opt_debug;
 extern bool opt_debug_console;
 extern bool opt_log_output;
@@ -37,21 +37,47 @@ extern bool want_per_device_stats;
 /* global log_level, messages with lower or equal prio are logged */
 extern int opt_log_level;
 
-/* low-level logging functions with priority parameter */
-extern void vapplog(int prio, const char *fmt, va_list ap) FORMAT_SYNTAX_CHECK(printf, 2, 0);
-extern void applog(int prio, const char *fmt, ...) FORMAT_SYNTAX_CHECK(printf, 2, 3);
+#define LOGBUFSIZ 256
+
+extern void _applog(int prio, const char *str);
+
+#define applog(prio, fmt, ...) do { \
+	if (opt_debug || prio != LOG_DEBUG) { \
+			char tmp42[LOGBUFSIZ]; \
+			snprintf(tmp42, sizeof(tmp42), fmt, ##__VA_ARGS__); \
+			_applog(prio, tmp42); \
+	} \
+} while (0)
 
 #define applogr(rv, prio, ...)  do {  \
 	applog(prio, __VA_ARGS__);  \
 	return rv;  \
 } while (0)
 
-/* high-level logging functions with implicit priority */
-extern void log_error(const char *fmt, ...) FORMAT_SYNTAX_CHECK(printf, 1, 2);
-extern void log_warning(const char *fmt, ...) FORMAT_SYNTAX_CHECK(printf, 1, 2);
-extern void log_notice(const char *fmt, ...) FORMAT_SYNTAX_CHECK(printf, 1, 2);
-extern void log_info(const char *fmt, ...) FORMAT_SYNTAX_CHECK(printf, 1, 2);
-extern void log_debug(const char *fmt, ...) FORMAT_SYNTAX_CHECK(printf, 1, 2);
+#define quit(status, fmt, ...) do { \
+	if (fmt) { \
+		char tmp42[LOGBUFSIZ]; \
+		snprintf(tmp42, sizeof(tmp42), fmt, ##__VA_ARGS__); \
+		_applog(LOG_ERR, tmp42); \
+	} \
+	_quit(status); \
+} while (0)
+
+#ifdef HAVE_CURSES
+
+#define wlog(fmt, ...) do { \
+	char tmp42[LOGBUFSIZ]; \
+	snprintf(tmp42, sizeof(tmp42), fmt, ##__VA_ARGS__); \
+	_wlog(tmp42); \
+} while (0)
+
+#define wlogprint(fmt, ...) do { \
+	char tmp42[LOGBUFSIZ]; \
+	snprintf(tmp42, sizeof(tmp42), fmt, ##__VA_ARGS__); \
+	_wlogprint(tmp42); \
+} while (0)
+
+#endif
 
 extern void hexdump(const void *, unsigned int len);
 

+ 67 - 46
miner.c

@@ -69,7 +69,7 @@
 #include "ft232r.h"
 #endif
 
-#if defined(unix)
+#if defined(unix) || defined(__APPLE__)
 	#include <errno.h>
 	#include <fcntl.h>
 	#include <sys/wait.h>
@@ -324,7 +324,7 @@ static int include_count;
 #define JSON_MAX_DEPTH 10
 #define JSON_MAX_DEPTH_ERR "Too many levels of JSON includes (limit 10) or a loop"
 
-#if defined(unix)
+#if defined(unix) || defined(__APPLE__)
 	static char *opt_stderr_cmd = NULL;
 	static int forkpid;
 #endif // defined(unix)
@@ -408,13 +408,16 @@ void get_timestamp(char *f, struct timeval *tv)
 
 static void applog_and_exit(const char *fmt, ...) FORMAT_SYNTAX_CHECK(printf, 1, 2);
 
+static char exit_buf[512];
+
 static void applog_and_exit(const char *fmt, ...)
 {
 	va_list ap;
 
 	va_start(ap, fmt);
-	vapplog(LOG_ERR, fmt, ap);
+	vsnprintf(exit_buf, sizeof(exit_buf), fmt, ap);
 	va_end(ap);
+	_applog(LOG_ERR, exit_buf);
 	exit(1);
 }
 
@@ -513,6 +516,8 @@ struct pool *add_pool(void)
 
 	/* Make sure the pool doesn't think we've been idle since time 0 */
 	pool->tv_idle.tv_sec = ~0UL;
+	
+	cgtime(&pool->cgminer_stats.start_tv);
 
 	pool->rpc_proxy = NULL;
 
@@ -1374,7 +1379,7 @@ static struct opt_table opt_config_table[] = {
 	OPT_WITHOUT_ARG("--log-microseconds",
 	                opt_set_bool, &opt_log_microseconds,
 	                "Include microseconds in log output"),
-#if defined(unix)
+#if defined(unix) || defined(__APPLE__)
 	OPT_WITH_ARG("--monitor|-m",
 		     opt_set_charp, NULL, &opt_stderr_cmd,
 		     "Use custom pipe cmd for output messages"),
@@ -2071,6 +2076,12 @@ static bool work_decode(struct pool *pool, struct work *work, json_t *val)
 	return ret;
 }
 
+/* Returns whether the pool supports local work generation or not. */
+static bool pool_localgen(struct pool *pool)
+{
+	return (pool->last_work_copy || pool->has_stratum);
+}
+
 int dev_from_id(int thr_id)
 {
 	struct cgpu_info *cgpu = get_thr_cgpu(thr_id);
@@ -2188,6 +2199,30 @@ void tailsprintf(char *f, const char *fmt, ...)
 	va_end(ap);
 }
 
+double stats_elapsed(struct cgminer_stats *stats)
+{
+	struct timeval now;
+	double elapsed;
+
+	if (stats->start_tv.tv_sec == 0)
+		elapsed = total_secs;
+	else {
+		cgtime(&now);
+		elapsed = tdiff(&now, &stats->start_tv);
+	}
+
+	if (elapsed < 1.0)
+		elapsed = 1.0;
+
+	return elapsed;
+}
+
+double cgpu_utility(struct cgpu_info *cgpu)
+{
+	double dev_runtime = cgpu_runtime(cgpu);
+	return cgpu->utility = cgpu->accepted / dev_runtime * 60;
+}
+
 /* Convert a uint64_t value into a truncated string for displaying with its
  * associated suitable for Mega, Giga etc. Buf array needs to be long enough */
 static void suffix_string(uint64_t val, char *buf, int sigdigits)
@@ -2357,12 +2392,14 @@ static void get_statline2(char *buf, struct cgpu_info *cgpu, bool for_curses)
 	enum h2bs_fmt hashrate_style = for_curses ? H2B_SHORT : H2B_SPACED;
 	char cHr[h2bs_fmt_size[H2B_NOUNIT]], aHr[h2bs_fmt_size[H2B_NOUNIT]], uHr[h2bs_fmt_size[hashrate_style]];
 	char rejpcbuf[6];
+	double dev_runtime;
 	
 	if (!opt_show_procs)
 		cgpu = cgpu->device;
 	
-	cgpu->utility = cgpu->accepted / total_secs * 60;
-	cgpu->utility_diff1 = cgpu->diff_accepted / total_secs * 60;
+	dev_runtime = cgpu_runtime(cgpu);
+	cgpu_utility(cgpu);
+	cgpu->utility_diff1 = cgpu->diff_accepted / dev_runtime * 60;
 	
 	double rolling = cgpu->rolling;
 	double mhashes = cgpu->total_mhashes;
@@ -2377,8 +2414,8 @@ static void get_statline2(char *buf, struct cgpu_info *cgpu, bool for_curses)
 	if (!opt_show_procs)
 		for (struct cgpu_info *slave = cgpu; (slave = slave->next_proc); )
 		{
-			slave->utility = slave->accepted / total_secs * 60;
-			slave->utility_diff1 = slave->diff_accepted / total_secs * 60;
+			slave->utility = slave->accepted / dev_runtime * 60;
+			slave->utility_diff1 = slave->diff_accepted / dev_runtime * 60;
 			
 			rolling += slave->rolling;
 			mhashes += slave->total_mhashes;
@@ -2394,7 +2431,7 @@ static void get_statline2(char *buf, struct cgpu_info *cgpu, bool for_curses)
 	ti_hashrate_bufstr(
 		(char*[]){cHr, aHr, uHr},
 		1e6*rolling,
-		1e6*mhashes / total_secs,
+		1e6*mhashes / dev_runtime,
 		utility_to_hashrate(wutil),
 		hashrate_style);
 
@@ -2706,31 +2743,23 @@ static void switch_logsize(void)
 }
 
 /* For mandatory printing when mutex is already locked */
-void wlog(const char *f, ...)
+void _wlog(const char *str)
 {
-	va_list ap;
-
-	va_start(ap, f);
-	vw_printw(logwin, f, ap);
-	va_end(ap);
+	wprintw(logwin, "%s", str);
 }
 
 /* Mandatory printing */
-void wlogprint(const char *f, ...)
+void _wlogprint(const char *str)
 {
-	va_list ap;
-
 	if (curses_active_locked()) {
-		va_start(ap, f);
-		vw_printw(logwin, f, ap);
-		va_end(ap);
+		wprintw(logwin, "%s", str);
 		unlock_curses();
 	}
 }
 #endif
 
 #ifdef HAVE_CURSES
-bool log_curses_only(int prio, const char *f, va_list ap)
+bool log_curses_only(int prio, const char *datetime, const char *str)
 {
 	bool high_prio;
 
@@ -2738,7 +2767,7 @@ bool log_curses_only(int prio, const char *f, va_list ap)
 
 	if (curses_active_locked()) {
 		if (!opt_loginput || high_prio) {
-			vw_printw(logwin, f, ap);
+			wprintw(logwin, "%s%s\n", datetime, str);
 			if (high_prio) {
 				touchwin(logwin);
 				wrefresh(logwin);
@@ -3613,7 +3642,7 @@ void app_restart(void)
 	__kill_work();
 	clean_up();
 
-#if defined(unix)
+#if defined(unix) || defined(__APPLE__)
 	if (forkpid > 0) {
 		kill(forkpid, SIGTERM);
 		forkpid = 0;
@@ -4624,7 +4653,7 @@ void switch_pools(struct pool *selected)
 		pool->block_id = 0;
 		if (pool_strategy != POOL_LOADBALANCE && pool_strategy != POOL_BALANCE) {
 			applog(LOG_WARNING, "Switching to pool %d %s", pool->pool_no, pool->rpc_url);
-			if (pool->last_work_copy || pool->has_stratum || opt_fail_only)
+			if (pool_localgen(pool) || opt_fail_only)
 				clear_pool_work(last_pool);
 		}
 	}
@@ -5251,7 +5280,7 @@ void write_config(FILE *fcfg)
 		fputs(",\n\"round-robin\" : true", fcfg);
 	if (pool_strategy == POOL_ROTATE)
 		fprintf(fcfg, ",\n\"rotate\" : \"%d\"", opt_rotate_period);
-#if defined(unix)
+#if defined(unix) || defined(__APPLE__)
 	if (opt_stderr_cmd && *opt_stderr_cmd)
 		fprintf(fcfg, ",\n\"monitor\" : \"%s\"", json_escape(opt_stderr_cmd));
 #endif // defined(unix)
@@ -5376,6 +5405,7 @@ void zero_stats(void)
 		pool->diff_rejected = 0;
 		pool->diff_stale = 0;
 		pool->last_share_diff = 0;
+		pool->cgminer_stats.start_tv = total_tv_start;
 		pool->cgminer_stats.getwork_calls = 0;
 		pool->cgminer_stats.getwork_wait_min.tv_sec = MIN_SEC_UNSET;
 		pool->cgminer_stats.getwork_wait_max.tv_sec = 0;
@@ -5425,6 +5455,7 @@ void zero_stats(void)
 		cgpu->dev_thermal_cutoff_count = 0;
 		cgpu->dev_comms_error_count = 0;
 		cgpu->dev_throttle_count = 0;
+		cgpu->cgminer_stats.start_tv = total_tv_start;
 		cgpu->cgminer_stats.getwork_calls = 0;
 		cgpu->cgminer_stats.getwork_wait_min.tv_sec = MIN_SEC_UNSET;
 		cgpu->cgminer_stats.getwork_wait_max.tv_sec = 0;
@@ -5744,7 +5775,7 @@ retry:
 
 void default_save_file(char *filename)
 {
-#if defined(unix)
+#if defined(unix) || defined(__APPLE__)
 	if (getenv("HOME") && *getenv("HOME")) {
 	        strcpy(filename, getenv("HOME"));
 		strcat(filename, "/");
@@ -6367,7 +6398,7 @@ static bool cnx_needed(struct pool *pool)
 	cp = current_pool();
 	if (cp == pool)
 		return true;
-	if (!cp->has_stratum && (!opt_fail_only || !cp->hdr_path))
+	if (!pool_localgen(cp) && (!opt_fail_only || !cp->hdr_path))
 		return true;
 
 	/* Keep the connection open to allow any stray shares to be submitted
@@ -8153,30 +8184,20 @@ static void clean_up(void)
 	curl_global_cleanup();
 }
 
-void quit(int status, const char *format, ...)
+void _quit(int status)
 {
-	va_list ap;
-
 	clean_up();
 
-	if (format) {
-		va_start(ap, format);
-		vfprintf(stderr, format, ap);
-		va_end(ap);
-	}
-	fprintf(stderr, "\n");
-	fflush(stderr);
-
 	if (status) {
 		const char *ev = getenv("__BFGMINER_SEGFAULT_ERRQUIT");
 		if (unlikely(ev && ev[0] && ev[0] != '0')) {
-			const char **p = NULL;
+			int *p = NULL;
 			// NOTE debugger can bypass with: p = &p
-			*p = format;  // Segfault, hopefully dumping core
+			*p = status;  // Segfault, hopefully dumping core
 		}
 	}
 
-#if defined(unix)
+#if defined(unix) || defined(__APPLE__)
 	if (forkpid > 0) {
 		kill(forkpid, SIGTERM);
 		forkpid = 0;
@@ -8315,7 +8336,7 @@ out:
 }
 #endif
 
-#if defined(unix)
+#if defined(unix) || defined(__APPLE__)
 static void fork_monitor()
 {
 	// Make a pipe: [readFD, writeFD]
@@ -8930,7 +8951,7 @@ int main(int argc, char *argv[])
 		openlog(PACKAGE, LOG_PID, LOG_USER);
 #endif
 
-	#if defined(unix)
+	#if defined(unix) || defined(__APPLE__)
 		if (opt_stderr_cmd)
 			fork_monitor();
 	#endif // defined(unix)
@@ -9179,13 +9200,13 @@ begin_bench:
 
 		/* If the primary pool is a getwork pool and cannot roll work,
 		 * try to stage one extra work per mining thread */
-		if (!cp->has_stratum && cp->proto != PLP_GETBLOCKTEMPLATE && !staged_rollable)
+		if (!pool_localgen(cp) && !staged_rollable)
 			max_staged += mining_threads;
 
 		mutex_lock(stgd_lock);
 		ts = __total_staged();
 
-		if (!cp->has_stratum && cp->proto != PLP_GETBLOCKTEMPLATE && !ts && !opt_fail_only)
+		if (!pool_localgen(cp) && !ts && !opt_fail_only)
 			lagging = true;
 
 		/* Wait until hash_pop tells us we need to create more work */

+ 9 - 4
miner.h

@@ -384,6 +384,8 @@ enum {
 };
 
 struct cgminer_stats {
+	struct timeval start_tv;
+	
 	uint32_t getwork_calls;
 	struct timeval getwork_wait;
 	struct timeval getwork_wait_max;
@@ -715,7 +717,7 @@ static inline void swab256(void *dest_p, const void *src_p)
 
 #define flip32(dest_p, src_p) swap32yes(dest_p, src_p, 32 / 4)
 
-extern void quit(int status, const char *format, ...) NORETURN FORMAT_SYNTAX_CHECK(printf, 2, 3);
+extern void _quit(int status);
 
 static inline void mutex_lock(pthread_mutex_t *lock)
 {
@@ -1258,10 +1260,13 @@ extern void work_completed(struct cgpu_info *cgpu, struct work *work);
 extern bool abandon_work(struct work *, struct timeval *work_runtime, uint64_t hashes);
 extern void hash_queued_work(struct thr_info *mythr);
 extern void tailsprintf(char *f, const char *fmt, ...) FORMAT_SYNTAX_CHECK(printf, 2, 3);
-extern void wlog(const char *f, ...) FORMAT_SYNTAX_CHECK(printf, 1, 2);
-extern void wlogprint(const char *f, ...) FORMAT_SYNTAX_CHECK(printf, 1, 2);
+extern void _wlog(const char *str);
+extern void _wlogprint(const char *str);
 extern int curses_int(const char *query);
 extern char *curses_input(const char *query);
+extern double stats_elapsed(struct cgminer_stats *);
+#define cgpu_runtime(cgpu)  stats_elapsed(&((cgpu)->cgminer_stats))
+extern double cgpu_utility(struct cgpu_info *);
 extern void kill_work(void);
 extern int prioritize_pools(char *param, int *pid);
 extern void validate_pool_priorities(void);
@@ -1271,7 +1276,7 @@ extern void write_config(FILE *fcfg);
 extern void zero_bestshare(void);
 extern void zero_stats(void);
 extern void default_save_file(char *filename);
-extern bool log_curses_only(int prio, const char *f, va_list ap) FORMAT_SYNTAX_CHECK(printf, 2, 0);
+extern bool log_curses_only(int prio, const char *datetime, const char *str);
 extern void clear_logwin(void);
 extern void logwin_update(void);
 extern bool pool_tclear(struct pool *pool, bool *var);

+ 9 - 2
util.c

@@ -1270,9 +1270,11 @@ bool stratum_send(struct pool *pool, char *s, ssize_t len)
 			break;
 		case SEND_SELECTFAIL:
 			applog(LOG_DEBUG, "Write select failed on pool %d sock", pool->pool_no);
+			suspend_stratum(pool);
 			break;
 		case SEND_SENDFAIL:
-			applog(LOG_DEBUG, "Failed to curl_easy_send in stratum_send");
+			applog(LOG_DEBUG, "Failed to send in stratum_send");
+			suspend_stratum(pool);
 			break;
 		case SEND_INACTIVE:
 			applog(LOG_DEBUG, "Stratum send failed due to no pool stratum_active");
@@ -1319,7 +1321,10 @@ static void clear_sock(struct pool *pool)
 
 	mutex_lock(&pool->stratum_lock);
 	do {
-		n = recv(pool->sock, pool->sockbuf, RECVSIZE, 0);
+		if (pool->sock)
+			n = recv(pool->sock, pool->sockbuf, RECVSIZE, 0);
+		else
+			n = 0;
 	} while (n > 0);
 	mutex_unlock(&pool->stratum_lock);
 
@@ -1372,11 +1377,13 @@ char *recv_line(struct pool *pool)
 			n = recv(pool->sock, s, RECVSIZE, 0);
 			if (!n) {
 				applog(LOG_DEBUG, "Socket closed waiting in recv_line");
+				suspend_stratum(pool);
 				break;
 			}
 			if (n < 0) {
 				if (!sock_blocks() || !socket_full(pool, false)) {
 					applog(LOG_DEBUG, "Failed to recv sock in recv_line");
+					suspend_stratum(pool);
 					break;
 				}
 			} else {