Browse Source

Merge branch 'cg_merges_20121214' into bfgminer

Luke Dashjr 13 years ago
parent
commit
3539af676c
9 changed files with 552 additions and 235 deletions
  1. 15 1
      API-README
  2. 2 0
      ChangeLog
  3. 23 0
      NEWS
  4. 320 200
      api.c
  5. 2 2
      driver-ztex.c
  6. 2 2
      miner.c
  7. 8 0
      miner.h
  8. 134 8
      miner.php
  9. 46 22
      util.c

+ 15 - 1
API-README

@@ -384,6 +384,19 @@ miner.php - an example web page to access the API
 Feature Changelog for external applications using the API:
 
 
+API V1.22
+
+Enforced output limitation:
+ all extra records beyond the output limit of the API (~64k) are ignored
+  and chopped off at the record boundary before the limit is reached
+  however, JSON brackets will be correctly closed and the JSON id will be
+  set to 0 (instead of 1) if any data was truncated
+
+Modified API commands:
+ 'stats' - add 'Times Sent', 'Bytes Sent', 'Times Recv'
+
+----------
+
 API V1.21 (BFGMiner v2.10.0)
 
 Modified API commands:
@@ -725,7 +738,8 @@ On Fedora 17:
  systemctl enable httpd.service --system
 
 On windows there are a few options.
-Try one of these (I've never used either one)
+Try one of these (apparently the first one is easiest - thanks jborkl)
+ http://www.easyphp.org/
  http://www.apachefriends.org/en/xampp.html
  http://www.wampserver.com/en/
 

+ 2 - 0
ChangeLog

@@ -2,3 +2,5 @@ See git repository ('git log') for full changelog.
 
 Git repo can be found at:
 https://github.com/luke-jr/bfgminer
+
+The NEWS file contains most of the changelog

+ 23 - 0
NEWS

@@ -1,3 +1,26 @@
+BFGMiner Version 2.10.1 - Future
+
+- Check for EWOULDBLOCK when supported in send and recv as well.
+- Use the raw send() command instead of curl_easy_send since curl raw socket
+usage introduces random bugs on windows.
+- Use raw recv() command in place of curl_easy_recv since the curl
+implementation introduces random bugs on windows builds when the recv fails.
+- miner.php when displaying a single rig, add prev/next rig buttons if they
+exist, next to refresh
+- miner.php allow custom page joins for STATS
+- RPC: Remove "Bytes Recv" since it is incorrect
+- miner.php - include windows easyphp link
+- driver-ztex: use the correct size for the swap array
+- API stats - display pool byte transfer stats
+- Pool store data transfer stats
+- Benchmark incorrect work size
+- ChangeLog refer to NEWS
+- driver-ztex: search the complete noncerange based on the actual speed
+- API-README update
+- api use a dynamic io buffer, truncated before it reaches the current ~64k
+limit
+
+
 BFGMiner Version 2.10.0 - December 11, 2012
 
 - Bugfix: Free work before replacing it with clone

File diff suppressed because it is too large
+ 320 - 200
api.c


+ 2 - 2
driver-ztex.c

@@ -150,7 +150,7 @@ static bool ztex_checkNonce(struct libztex_device *ztex,
                             struct libztex_hash_data *hdata)
 {
 	uint32_t *data32 = (uint32_t *)(work->data);
-	unsigned char swap[128];
+	unsigned char swap[80];
 	uint32_t *swap32 = (uint32_t *)swap;
 	unsigned char hash1[32];
 	unsigned char hash2[32];
@@ -271,7 +271,7 @@ static int64_t ztex_scanhash(struct thr_info *thr, struct work *work,
 			nonce = le32toh(nonce);
 			if (nonce > noncecnt)
 				noncecnt = nonce;
-			if (((nonce & 0x7fffffff) >> 4) < ((lastnonce[i] & 0x7fffffff) >> 4)) {
+			if (((0xffffffff - nonce) < (nonce - lastnonce[i])) || nonce < lastnonce[i]) {
 				applog(LOG_DEBUG, "%s: overflow nonce=%0.8x lastnonce=%0.8x", ztex->repr, nonce, lastnonce[i]);
 				overflow = true;
 			} else

+ 2 - 2
miner.c

@@ -2834,10 +2834,10 @@ static void get_benchmark_work(struct work *work)
 	// Use a random work block pulled from a pool
 	static uint8_t bench_block[] = { CGMINER_BENCHMARK_BLOCK };
 
-	size_t bench_size = sizeof(work);
+	size_t bench_size = sizeof(*work);
 	size_t work_size = sizeof(bench_block);
 	size_t min_size = (work_size < bench_size ? work_size : bench_size);
-	memset(work, 0, sizeof(work));
+	memset(work, 0, sizeof(*work));
 	memcpy(work, &bench_block, min_size);
 	work->mandatory = true;
 	work->pool = pools[0];

+ 8 - 0
miner.h

@@ -60,6 +60,10 @@ static inline int fsync (int fd)
 	return (FlushFileBuffers ((HANDLE) _get_osfhandle (fd))) ? 0 : -1;
 }
 
+#ifndef EWOULDBLOCK
+# define EWOULDBLOCK EAGAIN
+#endif
+
 #ifndef MSG_DONTWAIT
 # define MSG_DONTWAIT 0x1000000
 #endif
@@ -395,6 +399,10 @@ struct cgminer_pool_stats {
 	double last_diff;
 	uint32_t min_diff_count;
 	uint32_t max_diff_count;
+	uint64_t times_sent;
+	uint64_t bytes_sent;
+	uint64_t times_received;
+	uint64_t bytes_received;
 };
 
 struct cgpu_info {

+ 134 - 8
miner.php

@@ -1197,7 +1197,7 @@ function process($cmds, $rig)
  }
 }
 #
-function rigbutton($rig, $rigname, $when, $row)
+function rigname($rig, $rigname)
 {
  global $rigs;
 
@@ -1208,12 +1208,21 @@ function rigbutton($rig, $rigname, $when, $row)
 		$rigname = $parts[2];
  }
 
- list($value, $class) = fmt('BUTTON', 'Rig', '', $when, $row);
+ return $rigname;
+}
+#
+function riginput($rig, $rigname)
+{
+ $rigname = rigname($rig, $rigname);
 
- $button = "<td align=middle$class><input type=button value='$rigname'";
- $button .= " onclick='pr(\"&rig=$rig\",null)'></td>";
+ return "<input type=button value='$rigname' onclick='pr(\"&rig=$rig\",null)'>";
+}
+#
+function rigbutton($rig, $rigname, $when, $row)
+{
+ list($value, $class) = fmt('BUTTON', 'Rig', '', $when, $row);
 
- return $button;
+ return "<td align=middle$class>".riginput($rig, $rigname).'</td>';
 }
 #
 function showrigs($anss, $headname, $rigname)
@@ -1435,16 +1444,43 @@ function pagebuttons($rig, $pg)
 
  if ($rig === null)
  {
+	$prev = null;
+	$next = null;
+
 	if ($pg === null)
 		$refresh = '';
 	else
 		$refresh = "&pg=$pg";
  }
  else
+ {
+	switch (count($rigs))
+	{
+	case 0:
+	case 1:
+		$prev = null;
+		$next = null;
+		break;
+	case 2:
+		$prev = null;
+		$next = ($rig + 1) % count($rigs);
+		break;
+	default:
+		$prev = ($rig - 1) % count($rigs);
+		$next = ($rig + 1) % count($rigs);
+		break;
+	}
+
 	$refresh = "&rig=$rig";
+ }
 
  echo '<tr><td><table cellpadding=0 cellspacing=0 border=0><tr><td nowrap>';
+ if ($prev !== null)
+	echo riginput($prev, 'Prev').'&nbsp;';
  echo "<input type=button value='Refresh' onclick='pr(\"$refresh\",null)'>&nbsp;";
+ if ($next !== null)
+	echo riginput($next, 'Next').'&nbsp;';
+ echo '&nbsp;';
  if (count($rigs) > 1)
 	echo "<input type=button value='Summary' onclick='pr(\"\",null)'>&nbsp;";
 
@@ -1574,6 +1610,79 @@ function joinfields($section1, $section2, $join, $results)
  return $newres;
 }
 #
+function joinlr($section1, $section2, $join, $results)
+{
+ global $sectionmap;
+
+ $name1 = $sectionmap[$section1];
+ $name2 = $sectionmap[$section2];
+ $newres = array();
+
+ // foreach rig in section1
+ foreach ($results[$name1] as $rig => $result)
+ {
+	$status = null;
+
+	// foreach answer section in the rig api call
+	foreach ($result as $name1b => $fields1b)
+	{
+		if ($name1b == 'STATUS')
+		{
+			// remember the STATUS from section1
+			$status = $result[$name1b];
+			continue;
+		}
+
+		// Build L string to be matched
+		// : means a string constant otherwise it's a field name
+		$Lval = '';
+		foreach ($join['L'] as $field)
+		{
+			if (substr($field, 0, 1) == ':')
+				$Lval .= substr($field, 1);
+			else
+				$Lval .= $fields1b[$field];
+		}
+
+		// foreach answer section in the rig api call (for the other api command)
+		foreach ($results[$name2][$rig] as $name2b => $fields2b)
+		{
+			if ($name2b == 'STATUS')
+				continue;
+
+			// Build R string and compare
+			// : means a string constant otherwise it's a field name
+			$Rval = '';
+			foreach ($join['R'] as $field)
+			{
+				if (substr($field, 0, 1) == ':')
+					$Rval .= substr($field, 1);
+				else
+					$Rval .= $fields2b[$field];
+			}
+
+			if ($Lval === $Rval)
+			{
+				if ($status != null)
+				{
+					$newres[$rig]['STATUS'] = $status;
+					$status = null;
+				}
+
+				$subsection = $section1.'+'.$section2;
+				$subsection .= preg_replace('/[^0-9]/', '', $name1b.$name2b);
+
+				foreach ($fields1b as $nam => $val)
+					$newres[$rig][$subsection]["$section1.$nam"] = $val;
+				foreach ($fields2b as $nam => $val)
+					$newres[$rig][$subsection]["$section2.$nam"] = $val;
+			}
+		}
+	}
+ }
+ return $newres;
+}
+#
 function joinall($section1, $section2, $results)
 {
  global $sectionmap;
@@ -1618,8 +1727,6 @@ function joinsections($sections, $results, $errors)
 {
  global $sectionmap;
 
-#echo "results['pools']=".print_r($results['pools'],true)."<br>";
-
  // GPU's don't have Name,ID fields - so create them
  foreach ($results as $section => $res)
 	foreach ($res as $rig => $result)
@@ -1657,14 +1764,33 @@ function joinsections($sections, $results, $errors)
 				}
 				break;
 			case 'DEVS':
-				$join = array('Name', 'ID');
 				switch($both[1])
 				{
 				case 'NOTIFY':
 				case 'DEVDETAILS':
+				case 'USBSTATS':
+					$join = array('Name', 'ID');
 					$sectionmap[$section] = $section;
 					$results[$section] = joinfields($both[0], $both[1], $join, $results);
 					break;
+				case 'STATS':
+					$join = array('L' => array('Name','ID'), 'R' => array('ID'));
+					$sectionmap[$section] = $section;
+					$results[$section] = joinlr($both[0], $both[1], $join, $results);
+					break;
+				default:
+					$errors[] = "Error: Invalid section '$section'";
+					break;
+				}
+				break;
+			case 'POOL':
+				switch($both[1])
+				{
+				case 'STATS':
+					$join = array('L' => array(':POOL','POOL'), 'R' => array('ID'));
+					$sectionmap[$section] = $section;
+					$results[$section] = joinlr($both[0], $both[1], $join, $results);
+					break;
 				default:
 					$errors[] = "Error: Invalid section '$section'";
 					break;

+ 46 - 22
util.c

@@ -433,6 +433,7 @@ json_t *json_rpc_call_completed(CURL *curl, int rc, bool probe, int *rolltime, v
 		*(void**)out_priv = state->priv;
 
 	json_t *val, *err_val, *res_val;
+	double byte_count;
 	json_error_t err;
 	struct pool *pool = state->pool;
 	bool probing = probe && !pool->probed;
@@ -447,6 +448,13 @@ json_t *json_rpc_call_completed(CURL *curl, int rc, bool probe, int *rolltime, v
 		goto err_out;
 	}
 
+	pool->cgminer_pool_stats.times_sent++;
+	if (curl_easy_getinfo(curl, CURLINFO_SIZE_UPLOAD, &byte_count) == CURLE_OK)
+		pool->cgminer_pool_stats.bytes_sent += byte_count;
+	pool->cgminer_pool_stats.times_received++;
+	if (curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &byte_count) == CURLE_OK)
+		pool->cgminer_pool_stats.bytes_received += byte_count;
+
 	if (probing) {
 		pool->probed = true;
 		/* If X-Long-Polling was found, activate long polling */
@@ -931,8 +939,7 @@ static bool __stratum_send(struct pool *pool, char *s, ssize_t len)
 
 	while (len > 0 ) {
 		struct timeval timeout = {0, 0};
-		size_t sent = 0;
-		CURLcode rc;
+		ssize_t sent;
 		fd_set wd;
 
 		FD_ZERO(&wd);
@@ -941,15 +948,20 @@ static bool __stratum_send(struct pool *pool, char *s, ssize_t len)
 			applog(LOG_DEBUG, "Write select failed on pool %d sock", pool->pool_no);
 			return false;
 		}
-		rc = curl_easy_send(pool->stratum_curl, s + ssent, len, &sent);
-		if (rc != CURLE_OK) {
-			applog(LOG_DEBUG, "Failed to curl_easy_send in stratum_send");
-			return false;
+		sent = send(pool->sock, s + ssent, len, 0);
+		if (sent < 0) {
+			if (errno != EAGAIN && errno != EWOULDBLOCK) {
+				applog(LOG_DEBUG, "Failed to curl_easy_send in stratum_send");
+				return false;
+			}
+			sent = 0;
 		}
 		ssent += sent;
 		len -= ssent;
 	}
 
+	pool->cgminer_pool_stats.times_sent++;
+	pool->cgminer_pool_stats.bytes_sent += ssent;
 	return true;
 }
 
@@ -967,17 +979,6 @@ bool stratum_send(struct pool *pool, char *s, ssize_t len)
 	return ret;
 }
 
-static void clear_sock(struct pool *pool)
-{
-	size_t n = 0;
-	char buf[RECVSIZE];
-
-	mutex_lock(&pool->stratum_lock);
-	while (CURLE_OK == curl_easy_recv(pool->stratum_curl, buf, RECVSIZE, &n))
-	{}
-	mutex_unlock(&pool->stratum_lock);
-}
-
 /* Check to see if Santa's been good to you */
 static bool sock_full(struct pool *pool, bool wait)
 {
@@ -1000,17 +1001,29 @@ static bool sock_full(struct pool *pool, bool wait)
 	return false;
 }
 
+static void clear_sock(struct pool *pool)
+{
+	ssize_t n;
+	char buf[RECVSIZE];
+
+	mutex_lock(&pool->stratum_lock);
+	do
+		n = recv(pool->sock, buf, RECVSIZE, 0);
+	while (n > 0);
+	mutex_unlock(&pool->stratum_lock);
+	pool->readbuf.len = 0;
+}
+
 /* Peeks at a socket to find the first end of line and then reads just that
  * from the socket and returns that as a malloced char */
 char *recv_line(struct pool *pool)
 {
 	ssize_t len;
 	char *tok, *sret = NULL;
-	size_t n = 0;
+	ssize_t n;
 
 	while (!(pool->readbuf.buf && memchr(pool->readbuf.buf, '\n', pool->readbuf.len))) {
 		char s[RBUFSIZE];
-		CURLcode rc;
 
 		if (!sock_full(pool, true)) {
 			applog(LOG_DEBUG, "Timed out waiting for data on sock_full");
@@ -1019,11 +1032,11 @@ char *recv_line(struct pool *pool)
 		memset(s, 0, RBUFSIZE);
 
 		mutex_lock(&pool->stratum_lock);
-		rc = curl_easy_recv(pool->stratum_curl, s, RECVSIZE, &n);
+		n = recv(pool->sock, s, RECVSIZE, 0);
 		mutex_unlock(&pool->stratum_lock);
 
-		if (rc != CURLE_OK) {
-			applog(LOG_DEBUG, "Failed to recv sock in recv_line: %d", rc);
+		if (n < 1 && errno != EAGAIN && errno != EWOULDBLOCK) {
+			applog(LOG_DEBUG, "Failed to recv sock in recv_line: %d", errno);
 			goto out;
 		}
 
@@ -1043,6 +1056,9 @@ char *recv_line(struct pool *pool)
 	sret = realloc(pool->readbuf.buf, len + 1);
 	pool->readbuf.buf = tok;
 
+	pool->cgminer_pool_stats.times_received++;
+	pool->cgminer_pool_stats.bytes_received += len;
+
 out:
 	if (!sret)
 		clear_sock(pool);
@@ -1374,6 +1390,7 @@ bool initiate_stratum(struct pool *pool)
 	char curl_err_str[CURL_ERROR_SIZE];
 	char s[RBUFSIZE], *sret = NULL;
 	CURL *curl = NULL;
+	double byte_count;
 	json_error_t err;
 	bool ret = false;
 
@@ -1413,6 +1430,13 @@ bool initiate_stratum(struct pool *pool)
 	curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, (long *)&pool->sock);
 	keep_sockalive(pool->sock);
 
+	pool->cgminer_pool_stats.times_sent++;
+	if (curl_easy_getinfo(curl, CURLINFO_SIZE_UPLOAD, &byte_count) == CURLE_OK)
+		pool->cgminer_pool_stats.bytes_sent += byte_count;
+	pool->cgminer_pool_stats.times_received++;
+	if (curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &byte_count) == CURLE_OK)
+		pool->cgminer_pool_stats.bytes_received += byte_count;
+
 	sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": []}", swork_id++);
 
 	if (!__stratum_send(pool, s, strlen(s))) {

Some files were not shown because too many files changed in this diff