Browse Source

Merge pull request #394 from kanoi/main

Last Valid Work + usb_cleanup() + dev_width fix + --hotplug/API
Con Kolivas 13 years ago
parent
commit
2fe415f42e
8 changed files with 181 additions and 42 deletions
  1. 23 1
      API-README
  2. 1 0
      README
  3. 60 6
      api.c
  4. 64 32
      cgminer.c
  5. 4 2
      miner.h
  6. 8 0
      miner.php
  7. 20 1
      usbutils.c
  8. 1 0
      usbutils.h

+ 23 - 1
API-README

@@ -140,6 +140,8 @@ The list of requests - a (*) means it requires privileged access - and replies a
                               Last Share Time=NNN, <- standand long time in seconds
                                (or 0 if none) of last accepted share
                               Last Share Pool=N, <- pool number (or -1 if none)
+                              Last Valid Work=NNN, <- standand long time in seconds
+                               of last work returned that wasn't an HW:
                               Will not report PGAs if PGA mining is disabled
                               Will not report CPUs if CPU mining is disabled
 
@@ -359,6 +361,14 @@ The list of requests - a (*) means it requires privileged access - and replies a
                               shown on the cgminer display like is normally displayed
                               on exit.
 
+ hotplug|N (*) none           There is no reply section just the STATUS section
+                              stating that the hotplug setting succeeded
+                              If the code is not compiled with hotplug in it, the
+                              the warning reply will be 'Hotplug is not available'
+                              If N=0 then hotplug will be disabled
+                              If N>0 && <=9999, then hotplug will check for new
+                              devices every N seconds
+
 When you enable, disable or restart a GPU or PGA, you will also get Thread messages
 in the cgminer status window
 
@@ -412,7 +422,18 @@ miner.php - an example web page to access the API
 Feature Changelog for external applications using the API:
 
 
-API V1.24
+API V1.25
+
+Added API commands:
+ 'hotplug'
+
+Modified API commands:
+ 'devs' 'gpu' and 'pga' - add 'Last Valid Work'
+ 'config' - add 'Hotplug'
+
+----------
+
+API V1.24 (cgminer v2.11.0)
 
 Added API commands:
  'zero'
@@ -420,6 +441,7 @@ Added API commands:
 Modified API commands:
  'pools' - add 'Best Share'
  'devs' and 'pga' - add 'No Device' for PGAs if MMQ or BFL compiled
+ 'stats' - add pool: 'Net Bytes Sent', 'Net Bytes Recv'
 
 ----------
 

+ 1 - 0
README

@@ -149,6 +149,7 @@ Options for both config file and command line:
 --expiry|-E <arg>   Upper bound on how many seconds after getting work we consider a share from it stale (default: 120)
 --failover-only     Don't leak work to backup pools when primary pool is lagging
 --fix-protocol      Do not redirect to a different getwork protocol (eg. stratum)
+--hotplug <arg>     Set hotplug check time to <arg> seconds (0=never default: 5) - only with libusb
 --kernel-path|-K <arg> Specify a path to where bitstream and kernel files are (default: "/usr/local/bin")
 --load-balance      Change multipool strategy from failover to efficiency based balance
 --log|-l <arg>      Interval in seconds between log output (default: 5)

+ 60 - 6
api.c

@@ -133,7 +133,7 @@ static const char SEPARATOR = '|';
 #define SEPSTR "|"
 static const char GPUSEP = ',';
 
-static const char *APIVERSION = "1.24";
+static const char *APIVERSION = "1.25";
 static const char *DEAD = "Dead";
 #if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA)
 static const char *SICK = "Sick";
@@ -149,6 +149,8 @@ static const char *UNKNOWN = "Unknown";
 static const char *DYNAMIC = _DYNAMIC;
 #endif
 
+static __maybe_unused const char *NONE = "None";
+
 static const char *YES = "Y";
 static const char *NO = "N";
 static const char *NULLSTR = "(null)";
@@ -392,6 +394,11 @@ static const char *JSON_PARAMETER = "parameter";
 #define MSG_ZERSUM 96
 #define MSG_ZERNOSUM 97
 #define MSG_USBNODEV 98
+#define MSG_INVHPLG 99
+#define MSG_HOTPLUG 100
+#define MSG_DISHPLG 101
+#define MSG_NOHPLG 102
+#define MSG_MISHPLG 103
 
 enum code_severity {
 	SEVERITY_ERR,
@@ -421,6 +428,7 @@ enum code_parameters {
 	PARAM_BOTH,
 	PARAM_BOOL,
 	PARAM_SET,
+	PARAM_INT,
 	PARAM_NONE
 };
 
@@ -572,6 +580,11 @@ struct CODES {
 #if defined(USE_MODMINER) || defined(USE_BITFORCE)
  { SEVERITY_ERR,   MSG_USBNODEV, PARAM_PGA,	"PGA%d has no device" },
 #endif
+ { SEVERITY_ERR,   MSG_INVHPLG,	PARAM_STR,	"Invalid value for hotplug (%s) must be 0..9999" },
+ { SEVERITY_SUCC,  MSG_HOTPLUG,	PARAM_INT,	"Hotplug check set to %ds" },
+ { SEVERITY_SUCC,  MSG_DISHPLG,	PARAM_NONE,	"Hotplug disabled" },
+ { SEVERITY_WARN,  MSG_NOHPLG,	PARAM_NONE,	"Hotplug is not available" },
+ { SEVERITY_ERR,   MSG_MISHPLG,	PARAM_NONE,	"Missing hotplug parameter" },
  { SEVERITY_FAIL, 0, 0, NULL }
 };
 
@@ -1148,7 +1161,7 @@ static int numpgas()
 	int count = 0;
 	int i;
 
-	mutex_lock(&devices_lock);
+	rd_lock(&devices_lock);
 	for (i = 0; i < total_devices; i++) {
 #ifdef USE_BITFORCE
 		if (devices[i]->drv->drv_id == DRIVER_BITFORCE)
@@ -1167,7 +1180,7 @@ static int numpgas()
 			count++;
 #endif
 	}
-	mutex_unlock(&devices_lock);
+	rd_unlock(&devices_lock);
 	return count;
 }
 
@@ -1176,7 +1189,7 @@ static int pgadevice(int pgaid)
 	int count = 0;
 	int i;
 
-	mutex_lock(&devices_lock);
+	rd_lock(&devices_lock);
 	for (i = 0; i < total_devices; i++) {
 #ifdef USE_BITFORCE
 		if (devices[i]->drv->drv_id == DRIVER_BITFORCE)
@@ -1198,12 +1211,12 @@ static int pgadevice(int pgaid)
 			goto foundit;
 	}
 
-	mutex_unlock(&devices_lock);
+	rd_unlock(&devices_lock);
 	return -1;
 
 foundit:
 
-	mutex_unlock(&devices_lock);
+	rd_unlock(&devices_lock);
 	return i;
 }
 #endif
@@ -1254,6 +1267,7 @@ static void message(struct io_data *io_data, int messageid, int paramid, char *p
 				case PARAM_PGA:
 				case PARAM_CPU:
 				case PARAM_PID:
+				case PARAM_INT:
 					sprintf(buf, codes[i].description, paramid);
 					break;
 				case PARAM_POOL:
@@ -1426,6 +1440,14 @@ static void minerconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __
 	root = api_add_int(root, "ScanTime", &opt_scantime, false);
 	root = api_add_int(root, "Queue", &opt_queue, false);
 	root = api_add_int(root, "Expiry", &opt_expiry, false);
+#if defined(USE_MODMINER) || defined(USE_BITFORCE)
+	if (hotplug_time == 0)
+		root = api_add_const(root, "Hotplug", DISABLED, false);
+	else
+		root = api_add_int(root, "Hotplug", &hotplug_time, false);
+#else
+	root = api_add_const(root, "Hotplug", NONE, false);
+#endif
 
 	root = print_data(root, buf, isjson, false);
 	io_add(io_data, buf);
@@ -1516,6 +1538,7 @@ static void gpustatus(struct io_data *io_data, int gpu, bool isjson, bool precom
 		root = api_add_diff(root, "Difficulty Accepted", &(cgpu->diff_accepted), false);
 		root = api_add_diff(root, "Difficulty Rejected", &(cgpu->diff_rejected), false);
 		root = api_add_diff(root, "Last Share Difficulty", &(cgpu->last_share_diff), false);
+		root = api_add_time(root, "Last Valid Work", &(cgpu->last_device_valid_work), false);
 
 		root = print_data(root, buf, isjson, precom);
 		io_add(io_data, buf);
@@ -1587,6 +1610,7 @@ static void pgastatus(struct io_data *io_data, int pga, bool isjson, bool precom
 #if defined(USE_MODMINER) || defined(USE_BITFORCE)
 		root = api_add_bool(root, "No Device", &(cgpu->usbinfo.nodev), false);
 #endif
+		root = api_add_time(root, "Last Valid Work", &(cgpu->last_device_valid_work), false);
 
 		root = print_data(root, buf, isjson, precom);
 		io_add(io_data, buf);
@@ -1623,6 +1647,7 @@ static void cpustatus(struct io_data *io_data, int cpu, bool isjson, bool precom
 		root = api_add_diff(root, "Difficulty Accepted", &(cgpu->diff_accepted), false);
 		root = api_add_diff(root, "Difficulty Rejected", &(cgpu->diff_rejected), false);
 		root = api_add_diff(root, "Last Share Difficulty", &(cgpu->last_share_diff), false);
+		root = api_add_time(root, "Last Valid Work", &(cgpu->last_device_valid_work), false);
 
 		root = print_data(root, buf, isjson, precom);
 		io_add(io_data, buf);
@@ -3305,6 +3330,34 @@ static void dozero(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *p
 		message(io_data, MSG_ZERNOSUM, 0, all ? "All" : "BestShare", isjson);
 }
 
+static void dohotplug(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
+{
+#if defined(USE_MODMINER) || defined(USE_BITFORCE)
+	int value;
+
+	if (param == NULL || *param == '\0') {
+		message(io_data, MSG_MISHPLG, 0, NULL, isjson);
+		return;
+	}
+
+	value = atoi(param);
+	if (value < 0 || value > 9999) {
+		message(io_data, MSG_INVHPLG, 0, param, isjson);
+		return;
+	}
+
+	hotplug_time = value;
+
+	if (value)
+		message(io_data, MSG_HOTPLUG, value, NULL, isjson);
+	else
+		message(io_data, MSG_DISHPLG, 0, NULL, isjson);
+#else
+	message(io_data, MSG_NOHPLG, 0, NULL, isjson);
+	return;
+#endif
+}
+
 static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, char group);
 
 struct CMDS {
@@ -3365,6 +3418,7 @@ struct CMDS {
 	{ "pgaset",		pgaset,		true },
 #endif
 	{ "zero",		dozero,		true },
+	{ "hotplug",		dohotplug,	true },
 	{ NULL,			NULL,		false }
 };
 

+ 64 - 32
cgminer.c

@@ -165,6 +165,7 @@ bool hotplug_mode;
 static int new_devices;
 static int new_threads;
 static int start_devices;
+int hotplug_time = 5;
 
 #ifdef HAVE_LIBUSB
 pthread_mutex_t cgusb_lock;
@@ -179,8 +180,8 @@ static pthread_rwlock_t blk_lock;
 static pthread_mutex_t sshare_lock;
 
 pthread_rwlock_t netacc_lock;
-pthread_mutex_t mining_thr_lock;
-pthread_mutex_t devices_lock;
+pthread_rwlock_t mining_thr_lock;
+pthread_rwlock_t devices_lock;
 
 static pthread_mutex_t lp_lock;
 static pthread_cond_t lp_cond;
@@ -378,9 +379,9 @@ struct thr_info *get_thread(int thr_id)
 {
 	struct thr_info *thr;
 
-	mutex_lock(&mining_thr_lock);
+	rd_lock(&mining_thr_lock);
 	thr = mining_thr[thr_id];
-	mutex_unlock(&mining_thr_lock);
+	rd_unlock(&mining_thr_lock);
 	return thr;
 }
 
@@ -395,9 +396,9 @@ struct cgpu_info *get_devices(int id)
 {
 	struct cgpu_info *cgpu;
 
-	mutex_lock(&devices_lock);
+	rd_lock(&devices_lock);
 	cgpu = devices[id];
-	mutex_unlock(&devices_lock);
+	rd_unlock(&devices_lock);
 	return cgpu;
 }
 
@@ -761,24 +762,24 @@ static void load_temp_cutoffs()
 			if (val < 0 || val > 200)
 				quit(1, "Invalid value passed to set temp cutoff");
 
-			mutex_lock(&devices_lock);
+			rd_lock(&devices_lock);
 			devices[device]->cutofftemp = val;
-			mutex_unlock(&devices_lock);
+			rd_unlock(&devices_lock);
 		}
 	} else {
-		mutex_lock(&devices_lock);
+		rd_lock(&devices_lock);
 		for (i = device; i < total_devices; ++i) {
 			if (!devices[i]->cutofftemp)
 				devices[i]->cutofftemp = opt_cutofftemp;
 		}
-		mutex_unlock(&devices_lock);
+		rd_unlock(&devices_lock);
 		return;
 	}
 	if (device <= 1) {
-		mutex_lock(&devices_lock);
+		rd_lock(&devices_lock);
 		for (i = device; i < total_devices; ++i)
 			devices[i]->cutofftemp = val;
-		mutex_unlock(&devices_lock);
+		rd_unlock(&devices_lock);
 	}
 }
 
@@ -984,6 +985,14 @@ static struct opt_table opt_config_table[] = {
 		     set_intensity, NULL, NULL,
 		     "Intensity of GPU scanning (d or " _MIN_INTENSITY_STR " -> " _MAX_INTENSITY_STR ", default: d to maintain desktop interactivity)"),
 #endif
+	OPT_WITH_ARG("--hotplug",
+		     set_int_0_to_9999, NULL, &hotplug_time,
+#if defined(USE_MODMINER) || defined(USE_BITFORCE)
+		     "Seconds between hotplug checks (0 means never check)"
+#else
+		     opt_hidden
+#endif
+		    ),
 #if defined(HAVE_OPENCL) || defined(HAVE_MODMINER)
 	OPT_WITH_ARG("--kernel-path|-K",
 		     opt_set_charp, opt_show_charp, &opt_kernel_path,
@@ -2842,6 +2851,16 @@ static void __kill_work(void)
 	applog(LOG_DEBUG, "Killing off API thread");
 	thr = &control_thr[api_thr_id];
 	thr_info_cancel(thr);
+
+#if defined(USE_MODMINER) || defined(USE_BITFORCE)
+	/* Release USB resources in case it's a restart
+	 * and not a QUIT */
+	if (!opt_scrypt) {
+		applog(LOG_DEBUG, "Releasing all USB devices");
+		usb_cleanup();
+	}
+#endif
+
 }
 
 /* This should be the common exit path */
@@ -3477,10 +3496,10 @@ static void restart_threads(void)
 	/* Discard staged work that is now stale */
 	discard_stale();
 
-	mutex_lock(&mining_thr_lock);
+	rd_lock(&mining_thr_lock);
 	for (i = 0; i < mining_threads; i++)
 		mining_thr[i]->work_restart = true;
-	mutex_unlock(&mining_thr_lock);
+	rd_unlock(&mining_thr_lock);
 
 	mutex_lock(&restart_lock);
 	pthread_cond_broadcast(&restart_cond);
@@ -5406,6 +5425,10 @@ static bool hashtest(struct thr_info *thr, struct work *work)
 		goto out;
 	}
 
+	mutex_lock(&stats_lock);
+	thr->cgpu->last_device_valid_work = time(NULL);
+	mutex_unlock(&stats_lock);
+
 	ret = fulltest(hash2, work->target);
 	if (!ret) {
 		applog(LOG_INFO, "Share below target");
@@ -6129,10 +6152,10 @@ static void *watchdog_thread(void __maybe_unused *userdata)
 			applog(LOG_WARNING, "Will restart execution as scheduled at %02d:%02d",
 			       schedstart.tm.tm_hour, schedstart.tm.tm_min);
 			sched_paused = true;
-			mutex_lock(&mining_thr_lock);
+			rd_lock(&mining_thr_lock);
 			for (i = 0; i < mining_threads; i++)
 				mining_thr[i]->pause = true;
-			mutex_unlock(&mining_thr_lock);
+			rd_unlock(&mining_thr_lock);
 		} 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);
@@ -6696,12 +6719,14 @@ void fill_device_drv(struct cgpu_info *cgpu)
 void enable_device(struct cgpu_info *cgpu)
 {
 	cgpu->deven = DEV_ENABLED;
-	mutex_lock(&devices_lock);
+	wr_lock(&devices_lock);
 	devices[cgpu->cgminer_id = cgminer_id_count++] = cgpu;
-	mutex_unlock(&devices_lock);
+	wr_unlock(&devices_lock);
 	if (hotplug_mode) {
 		new_threads += cgpu->threads;
+#ifdef HAVE_CURSES
 		adj_width(mining_threads + new_threads, &dev_width);
+#endif
 	} else {
 		mining_threads += cgpu->threads;
 #ifdef HAVE_CURSES
@@ -6739,9 +6764,9 @@ bool add_cgpu(struct cgpu_info*cgpu)
 		cgpu->device_id = d->lastid = 0;
 		HASH_ADD_STR(devids, name, d);
 	}
-	mutex_lock(&devices_lock);
+	wr_lock(&devices_lock);
 	devices = realloc(devices, sizeof(struct cgpu_info *) * (total_devices + new_devices + 2));
-	mutex_unlock(&devices_lock);
+	wr_unlock(&devices_lock);
 	if (hotplug_mode)
 		devices[total_devices + new_devices++] = cgpu;
 	else
@@ -6777,9 +6802,9 @@ static void hotplug_process()
 		cgpu->rolling = cgpu->total_mhashes = 0;
 	}
 
-	mutex_lock(&mining_thr_lock);
+	wr_lock(&mining_thr_lock);
 	mining_thr = realloc(mining_thr, sizeof(thr) * (mining_threads + new_threads + 1));
-	mutex_unlock(&mining_thr_lock);
+	wr_unlock(&mining_thr_lock);
 	if (!mining_thr)
 		quit(1, "Failed to hotplug realloc mining_thr");
 	for (i = 0; i < new_threads; i++) {
@@ -6837,24 +6862,31 @@ static void *hotplug_thread(void __maybe_unused *userdata)
 
 	hotplug_mode = true;
 
-	while (0x2a) {
-		nmsleep(5000);
+	nmsleep(5000);
 
+	while (0x2a) {
 // Version 0.1 just add the devices on - worry about using nodev later
 
-		new_devices = 0;
-		new_threads = 0;
+		if (hotplug_time == 0)
+			nmsleep(5000);
+		else {
+			new_devices = 0;
+			new_threads = 0;
 
 #ifdef USE_BITFORCE
-		bitforce_drv.drv_detect();
+			bitforce_drv.drv_detect();
 #endif
 
 #ifdef USE_MODMINER
-		modminer_drv.drv_detect();
+			modminer_drv.drv_detect();
 #endif
 
-		if (new_devices)
-			hotplug_process();
+			if (new_devices)
+				hotplug_process();
+
+			// hotplug_time >0 && <=9999
+			nmsleep(hotplug_time * 1000);
+		}
 	}
 
 	return NULL;
@@ -6901,8 +6933,8 @@ int main(int argc, char *argv[])
 	mutex_init(&sshare_lock);
 	rwlock_init(&blk_lock);
 	rwlock_init(&netacc_lock);
-	mutex_init(&mining_thr_lock);
-	mutex_init(&devices_lock);
+	rwlock_init(&mining_thr_lock);
+	rwlock_init(&devices_lock);
 
 	mutex_init(&lp_lock);
 	if (unlikely(pthread_cond_init(&lp_cond, NULL)))

+ 4 - 2
miner.h

@@ -497,6 +497,7 @@ struct cgpu_info {
 	int last_share_pool;
 	time_t last_share_pool_time;
 	double last_share_diff;
+	time_t last_device_valid_work;
 
 	time_t device_last_well;
 	time_t device_last_not_well;
@@ -756,8 +757,8 @@ extern pthread_mutex_t cgusb_lock;
 extern pthread_mutex_t hash_lock;
 extern pthread_mutex_t console_lock;
 extern pthread_mutex_t ch_lock;
-extern pthread_mutex_t mining_thr_lock;
-extern pthread_mutex_t devices_lock;
+extern pthread_rwlock_t mining_thr_lock;
+extern pthread_rwlock_t devices_lock;
 
 extern pthread_mutex_t restart_lock;
 extern pthread_cond_t restart_cond;
@@ -800,6 +801,7 @@ extern void add_pool_details(struct pool *pool, bool live, char *url, char *user
 #endif
 
 extern bool hotplug_mode;
+extern int hotplug_time;
 extern struct list_head scan_devices;
 extern int nDevs;
 extern int opt_n_threads;

+ 8 - 0
miner.php

@@ -641,6 +641,14 @@ function fmt($section, $name, $value, $when, $alldata)
 			$class = classlastshare($when, $alldata, $warnclass, $errorclass);
 		}
 		break;
+	case 'GPU.Last Valid Work':
+	case 'PGA.Last Valid Work':
+	case 'DEVS.Last Valid Work':
+		if ($value == 0)
+			$ret = 'Never';
+		else
+			$ret = ($value - $when) . 's';
+		break;
 	case 'POOL.Last Share Time':
 		if ($value == 0)
 			$ret = 'Never';

+ 20 - 1
usbutils.c

@@ -184,6 +184,7 @@ static const char *C_SETFLOW_S = "SetFlowCtrl";
 static const char *C_SETMODEM_S = "SetModemCtrl";
 static const char *C_PURGERX_S = "PurgeRx";
 static const char *C_PURGETX_S = "PurgeTx";
+static const char *C_FLASHREPLY_S = "FlashReply";
 
 #ifdef EOL
 #undef EOL
@@ -572,6 +573,7 @@ static void cgusb_check_init()
 		usb_commands[C_SETMODEM] = C_SETMODEM_S;
 		usb_commands[C_PURGERX] = C_PURGERX_S;
 		usb_commands[C_PURGETX] = C_PURGETX_S;
+		usb_commands[C_FLASHREPLY] = C_FLASHREPLY_S;
 
 		stats_initialised = true;
 	}
@@ -857,6 +859,10 @@ static void release_cgpu(struct cgpu_info *cgpu)
 	struct cgpu_info *lookcgpu;
 	int i;
 
+	// It has already been done
+	if (cgpu->usbinfo.nodev)
+		return;
+
 	cgpu->usbinfo.nodev = true;
 	cgpu->usbinfo.nodev_count++;
 	gettimeofday(&(cgpu->usbinfo.last_nodev), NULL);
@@ -1522,5 +1528,18 @@ int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest
 
 void usb_cleanup()
 {
-	// TODO:
+	struct cgpu_info *cgpu;
+	int i;
+
+	for (i = 0; i < total_devices; i++) {
+		cgpu = get_devices(i);
+		switch (cgpu->drv->drv_id) {
+			case DRIVER_BITFORCE:
+			case DRIVER_MODMINER:
+				release_cgpu(cgpu);
+				break;
+			default:
+				break;
+		}
+	}
 }

+ 1 - 0
usbutils.h

@@ -122,6 +122,7 @@ enum usb_cmds {
 	C_SETMODEM,
 	C_PURGERX,
 	C_PURGETX,
+	C_FLASHREPLY,
 	C_MAX
 };