From 21a23a45d7b2ba325db6606bf554c7e0afd6e1f0 Mon Sep 17 00:00:00 2001 From: ckolivas Date: Wed, 27 Jun 2012 10:15:57 +1000 Subject: [PATCH 1/8] Work around pools that advertise very low expire= time inappropriately as this leads to many false positives for stale shares detected. --- cgminer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 69181b00..613b4068 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2167,7 +2167,10 @@ static bool stale_work(struct work *work, bool share) return false; if (share) { - if (work->rolltime) + /* Technically the rolltime should be correct but some pools + * advertise a broken expire= that is lower than a meaningful + * scantime */ + if (work->rolltime > opt_scantime) work_expiry = work->rolltime; else work_expiry = opt_expiry; From edd1f83a77af6447592bdb290d7fc4065ec479c9 Mon Sep 17 00:00:00 2001 From: Kano Date: Wed, 27 Jun 2012 15:08:59 +1000 Subject: [PATCH 2/8] miner.php allow custom summary pages - new 'Mobile' summary --- miner.php | 321 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 296 insertions(+), 25 deletions(-) diff --git a/miner.php b/miner.php index 7c4d8891..637c1f85 100644 --- a/miner.php +++ b/miner.php @@ -4,6 +4,7 @@ session_start(); global $miner, $port, $readonly, $notify, $rigs, $socktimeoutsec; global $checklastshare, $hidefields; global $ignorerefresh, $changerefresh, $autorefresh; +global $allowcustompages, $customsummarypages; # # Don't touch these 2 - see $rigs below $miner = null; @@ -59,6 +60,32 @@ $ignorerefresh = false; $changerefresh = true; $autorefresh = 0; # +# Should we allow custom pages? +# (or just completely ignore then and don't display the buttons) +$allowcustompages = true; +# +# OK this is a bit more complex item: Custom Summary Pages +# A custom summary page in an array of 'section' => array('FieldA','FieldB'...) +# This makes up what is displayed with each 'section' separately as a table +# - empty tables are not shown +# - empty columns (an unknown field) are not shown +# - and missing field data shows as blank +# There is a second array, listing fields to be totaled for each section +# see the example below (if there is no matching data, no total will show) +$mobilepage = array( + 'SUMMARY' => array('Elapsed', 'MHS av', 'Found Blocks', 'Accepted', 'Rejected', 'Utility'), + 'GPU' => array('GPU', 'Status', 'MHS av', 'Accepted', 'Rejected', 'Utility'), + 'PGA' => array('ID', 'Name', 'Status', 'MHS av', 'Accepted', 'Rejected', 'Utility'), + 'POOL' => array('POOL', 'Status', 'Accepted', 'Rejected', 'Last Share Time')); +$mobilesum = array( + 'SUMMARY' => array('MHS av' => 1, 'Found Blocks' => 1, 'Accepted' => 1, 'Rejected' => 1, 'Utility' => 1), + 'GPU' => array('MHS av' => 1, 'Accepted' => 1, 'Rejected' => 1, 'Utility' => 1), + 'PGA' => array('MHS av' => 1, 'Accepted' => 1, 'Rejected' => 1, 'Utility' => 1), + 'POOL' => array('Accepted' => 1, 'Rejected' => 1)); +# +# customsummarypages is an array of these Custom Summary Pages +$customsummarypages = array('Mobile' => array($mobilepage, $mobilesum)); +# $here = $_SERVER['PHP_SELF']; # global $tablebegin, $tableend, $warnfont, $warnoff, $dfmt; @@ -110,6 +137,7 @@ function htmlhead($checkapi, $rig) if ($readonly === false && $checkapi === true) { + $error = null; $access = api('privileged'); if ($error != null || !isset($access['STATUS']['STATUS']) @@ -150,17 +178,20 @@ function prs2(a,n,r){var v=document.getElementById('gi'+n).value;var c=a.substr( 'switchpool', 'Enable' => 'enablepool', 'Disable' => 'disablepool' ); # -function showhead($cmd, $item, $values) +function showhead($cmd, $values, $justnames = false) { global $poolcmd, $readonly; @@ -532,7 +566,7 @@ function showhead($cmd, $item, $values) echo "$name"; } - if ($cmd == 'pools' && $readonly === false) + if ($justnames === false && $cmd == 'pools' && $readonly === false) foreach ($poolcmd as $name => $pcmd) echo "$name"; @@ -588,7 +622,7 @@ function details($cmd, $list, $rig) if ($sectionname != $section) { echo $tableend.$tablebegin; - showhead($cmd, $item, $values); + showhead($cmd, $values); $section = $sectionname; } @@ -796,7 +830,7 @@ function doforeach($cmd, $des, $sum, $head, $datetime) echo $tableend.$tablebegin; $dthead = array('' => 1, 'STATUS' => 1, 'Description' => 1, 'When' => 1, 'API' => 1, 'CGMiner' => 1); - showhead('', null, $dthead); + showhead('', $dthead); foreach ($anss as $rig => $ans) { @@ -865,7 +899,7 @@ function doforeach($cmd, $des, $sum, $head, $datetime) if ($sum != null) $anss['total']['total'] = $total; - showhead('', null, $header); + showhead('', $header); $section = ''; @@ -924,26 +958,38 @@ function refreshbuttons() if ($ignorerefresh == false && $changerefresh == true) { echo '    '; - echo ""; + echo ""; echo ""; echo ""; } } # -function doOne($rig, $preprocess) +function pagetop($rig, $pg) { - global $error, $readonly, $notify, $rigs; + global $readonly, $rigs; + global $allowcustompages, $customsummarypages; - htmlhead(true, $rig); + if ($rig === null) + { + if ($pg === null) + $refresh = ''; + else + $refresh = "&pg=$pg"; + } + else + $refresh = "&rig=$rig"; - $error = null; - - echo ""; + echo '"; +} +# +function doOne($rig, $preprocess) +{ + global $haderror, $readonly, $notify, $rigs; + + htmlhead(true, $rig); + + pagetop($rig, null); if ($preprocess != null) process(array($preprocess => $preprocess), $rig); @@ -968,16 +1023,226 @@ function doOne($rig, $preprocess) process($cmds, $rig); - if ($error == null && $readonly === false) + if ($haderror == false && $readonly === false) processgpus($rig); } # +global $sectionmap; +# map sections to their api command +$sectionmap = array( + 'SUMMARY' => 'summary', + 'POOL' => 'pools', + 'GPU' => 'devs', + 'PGA' => 'devs', + 'NOTIFY' => 'notify', + 'CONFIG' => 'config'); +# +function customset($showfields, $sum, $section, $num, $result, $total) +{ + foreach ($result as $sec => $row) + { + $secname = preg_replace('/\d/', '', $sec); + + if ($sec != 'total') + { + if ($secname != $section) + continue; + } + + echo ''; + + $when = 0; + if (isset($result['STATUS']['When'])) + $when = $result['STATUS']['When']; + + if ($sec === 'total') + $class = ' class=tot'; + else + $class = ''; + + echo ""; + + foreach ($showfields as $name => $one) + { + if (isset($row[$name])) + { + $value = $row[$name]; + + if (isset($sum[$secname][$name])) + { + if (isset($total[$name])) + $total[$name] += $value; + else + $total[$name] = $value; + } + } + else + { + if ($sec == 'total' && isset($total[$name])) + $value = $total[$name]; + else + $value = null; + } + + list($showvalue, $class) = fmt($section, $name, $value, $when, $row); + + if ($sec === 'total' and $class == '') + $class = ' class=tot'; + + + echo "$showvalue"; + } + + echo ''; + } + return $total; +} +# +function processcustompage($pagename, $sections, $sum) +{ + global $sectionmap; + global $miner, $port; + global $rigs, $error; + global $warnfont, $warnoff; + global $tablebegin, $tableend, $dfmt; + global $readonly, $showndate; + + $cmds = array(); + $errors = array(); + foreach ($sections as $section => $fields) + { + if (isset($sectionmap[$section])) + { + $cmd = $sectionmap[$section]; + if (!isset($cmds[$cmd])) + $cmds[$cmd] = 1; + } + else + $errors[] = "Error: unknown section '$section' in custom summary page '$pagename'"; + } + + $results = array(); + foreach ($rigs as $num => $rig) + { + $parts = explode(':', $rig, 2); + if (count($parts) == 2) + { + $miner = $parts[0]; + $port = $parts[1]; + + foreach ($cmds as $cmd => $one) + { + $process = api($cmd); + + if ($error != null) + { + $errors[] = "Error getting $cmd for $rig $warnfont$error$warnoff"; + break; + } + else + $results[$cmd][$num] = $process; + } + } + } + + if (count($results) > 0) + { + $first = true; + foreach ($sections as $section => $fields) + { + if (isset($results[$sectionmap[$section]])) + { + $rigresults = $results[$sectionmap[$section]]; + $showfields = array(); + foreach ($fields as $field) + foreach ($rigresults as $result) + foreach ($result as $sec => $row) + { + $secname = preg_replace('/\d/', '', $sec); + if ($secname == $section && isset($row[$field])) + $showfields[$field] = 1; + } + + if (count($showfields) > 0) + { + if ($first === false) + echo ''; + + echo $tablebegin; + + showhead('', array('Rig'=>1)+$showfields, true); + + $total = array(); + $add = array('total' => array()); + + foreach ($rigresults as $num => $result) + { + $rg = ""; + $total = customset($showfields, $sum, $section, $rg, $result, $total); + } + + if (count($total) > 0) + customset($showfields, $sum, $section, 'Σ', $add, $total); + + $first = false; + + echo $tableend; + } + } + } + } + + if (count($errors) > 0) + { + if (count($results) > 0) + echo ''; + + foreach ($errors as $err) + echo ""; + } +} +# +function showcustompage($pagename) +{ + global $customsummarypages; + + htmlhead(false, null); + + pagetop(null, $pagename); + + if (!isset($customsummarypages[$pagename])) + { + echo ""; + return; + } + + if (count($customsummarypages[$pagename]) != 2) + { + echo ""; + return; + } + + $page = $customsummarypages[$pagename][0]; + $sum = $customsummarypages[$pagename][1]; + if ($sum === null) + $sum = array(); + + if (count($page) <= 1) + { + echo ""; + return; + } + + processcustompage($pagename, $page, $sum); +} +# function display() { global $tablebegin, $tableend; global $miner, $port; - global $error, $readonly, $notify, $rigs; + global $readonly, $notify, $rigs; global $ignorerefresh, $autorefresh; + global $allowcustompages; if ($ignorerefresh == false) { @@ -1021,6 +1286,16 @@ function display() return; } + if ($allowcustompages === true) + { + $pg = trim(getparam('pg', true)); + if ($pg != null && $pg != '') + { + showcustompage($pg); + return; + } + } + if (count($rigs) == 1) { $parts = explode(':', $rigs[0], 2); @@ -1055,11 +1330,7 @@ function display() htmlhead(false, null); - echo ""; + pagetop(null, null); if ($preprocess != null) process(array($preprocess => $preprocess), $rig); From f43ee5d652892f554058979f1b690f5c3188efcd Mon Sep 17 00:00:00 2001 From: Kano Date: Wed, 27 Jun 2012 15:26:27 +1000 Subject: [PATCH 3/8] miner.php - fix/enable autorefresh for custom pages --- miner.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/miner.php b/miner.php index 637c1f85..1c64e5a8 100644 --- a/miner.php +++ b/miner.php @@ -117,21 +117,24 @@ $showndate = false; global $rigerror; $rigerror = array(); # -function htmlhead($checkapi, $rig) +function htmlhead($checkapi, $rig, $pg = null) { global $miner_font_family, $miner_font_size; global $error, $readonly, $here; global $ignorerefresh, $autorefresh; - $paramrig = ''; + $extraparams = ''; if ($rig != null && $rig != '') - $paramrig = "&rig=$rig"; + $extraparams = "&rig=$rig"; + else + if ($pg != null && $pg != '') + $extraparams = "&pg=$pg"; if ($ignorerefresh == true || $autorefresh == 0) $refreshmeta = ''; else { - $url = "$here?ref=$autorefresh$paramrig"; + $url = "$here?ref=$autorefresh$extraparams"; $refreshmeta = "\n"; } @@ -162,7 +165,7 @@ td.lst { color:blue; $miner_font background:#ffffdd } function pr(a,m){if(m!=null){if(!confirm(m+'?'))return}window.location='$here?ref=$autorefresh'+a}\n"; if ($ignorerefresh == false) - echo "function prr(a){if(a){v=document.getElementById('refval').value}else{v=0}window.location='$here?ref='+v+'$paramrig'}\n"; + echo "function prr(a){if(a){v=document.getElementById('refval').value}else{v=0}window.location='$here?ref='+v+'$extraparams'}\n"; if ($readonly === false && $checkapi === true) { @@ -1206,7 +1209,7 @@ function showcustompage($pagename) { global $customsummarypages; - htmlhead(false, null); + htmlhead(false, null, $pagename); pagetop(null, $pagename); From e4f9cc4e3e296eac39979c20e5bb378bc027c4d1 Mon Sep 17 00:00:00 2001 From: Kano Date: Wed, 27 Jun 2012 21:21:54 +1000 Subject: [PATCH 4/8] api.c allow unwell devices to be enabled so they can be cured --- api.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api.c b/api.c index ff26e54f..ac5b9a6b 100644 --- a/api.c +++ b/api.c @@ -1174,10 +1174,12 @@ static void pgaenable(__maybe_unused SOCKETTYPE c, char *param, bool isjson) return; } +#if 0 /* A DISABLED device wont change status FIXME: should disabling make it WELL? */ if (cgpu->status != LIFE_WELL) { strcpy(io_buffer, message(MSG_PGAUNW, id, NULL, isjson)); return; } +#endif for (i = 0; i < mining_threads; i++) { pga = thr_info[i].cgpu->device_id; From 522f620c89b5f152f86a2916b0dca7b71b2a5005 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 27 Jun 2012 22:34:46 +1000 Subject: [PATCH 5/8] Check we don't exhaust the entire unsigned 32 bit ntime range when rolling time to cope with extremely high hashrates. --- cgminer.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cgminer.c b/cgminer.c index 47747974..0c4e0c36 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3646,13 +3646,17 @@ static inline bool can_roll(struct work *work) return (work->pool && !stale_work(work, false) && work->rolltime && !work->clone); } -static void roll_work(struct work *work) +static bool roll_work(struct work *work) { uint32_t *work_ntime; uint32_t ntime; work_ntime = (uint32_t *)(work->data + 68); ntime = be32toh(*work_ntime); + if (unlikely(ntime == 0xFFFFFFFF)) { + applog(LOG_DEBUG, "Exhausted ntime space, cannot roll work"); + return false; + } ntime++; *work_ntime = htobe32(ntime); local_work++; @@ -3663,13 +3667,14 @@ static void roll_work(struct work *work) /* This is now a different work item so it needs a different ID for the * hashtable */ work->id = total_work++; + return true; } static bool reuse_work(struct work *work) { if (can_roll(work) && should_roll(work)) { - roll_work(work); - return true; + if (likely(roll_work(work))) + return true; } return false; } From bcec5f510203f7f663a7d2d7c330043256d86890 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 27 Jun 2012 23:30:50 +1000 Subject: [PATCH 6/8] Revert "Check we don't exhaust the entire unsigned 32 bit ntime range when rolling time to cope with extremely high hashrates." This reverts commit 522f620c89b5f152f86a2916b0dca7b71b2a5005. Unrealistic. Limits are bitcoind related to 2 hours in the future. --- cgminer.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/cgminer.c b/cgminer.c index a3528246..756e0059 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3649,17 +3649,13 @@ static inline bool can_roll(struct work *work) return (work->pool && !stale_work(work, false) && work->rolltime && !work->clone); } -static bool roll_work(struct work *work) +static void roll_work(struct work *work) { uint32_t *work_ntime; uint32_t ntime; work_ntime = (uint32_t *)(work->data + 68); ntime = be32toh(*work_ntime); - if (unlikely(ntime == 0xFFFFFFFF)) { - applog(LOG_DEBUG, "Exhausted ntime space, cannot roll work"); - return false; - } ntime++; *work_ntime = htobe32(ntime); local_work++; @@ -3670,14 +3666,13 @@ static bool roll_work(struct work *work) /* This is now a different work item so it needs a different ID for the * hashtable */ work->id = total_work++; - return true; } static bool reuse_work(struct work *work) { if (can_roll(work) && should_roll(work)) { - if (likely(roll_work(work))) - return true; + roll_work(work); + return true; } return false; } From eddd02fea17c6d96ff272f739e1b70e3530e81f0 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 27 Jun 2012 23:32:50 +1000 Subject: [PATCH 7/8] Put upper bounds to under 2 hours that work can be rolled into the future for bitcoind will deem it invalid beyond that. --- cgminer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 756e0059..457990db 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3644,9 +3644,12 @@ static inline bool should_roll(struct work *work) return false; } +/* Limit rolls to 7000 to not beyond 2 hours in the future where bitcoind will + * reject blocks as invalid. */ static inline bool can_roll(struct work *work) { - return (work->pool && !stale_work(work, false) && work->rolltime && !work->clone); + return (work->pool && work->rolltime && !work->clone && + work->rolls < 7000 && !stale_work(work, false)); } static void roll_work(struct work *work) From 5ad58f9a5ce1a6b99f3011e1811fa01040d12aa2 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 27 Jun 2012 23:36:48 +1000 Subject: [PATCH 8/8] Work is checked if it's stale elsewhere outside of can_roll so there is no need to check it again. --- cgminer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 457990db..8b38acae 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3648,8 +3648,7 @@ static inline bool should_roll(struct work *work) * reject blocks as invalid. */ static inline bool can_roll(struct work *work) { - return (work->pool && work->rolltime && !work->clone && - work->rolls < 7000 && !stale_work(work, false)); + return (work->pool && work->rolltime && !work->clone && work->rolls < 7000); } static void roll_work(struct work *work)
"; - echo "
"; - echo "
'; + echo " "; if (count($rigs) > 1) - echo " "; - if ($readonly === false) + echo " "; + + if ($allowcustompages === true) + foreach ($customsummarypages as $pagename => $data) + echo " "; + + echo ' '; + if ($rig !== null && $readonly === false) { $rg = ''; if (count($rigs) > 1) @@ -953,6 +999,15 @@ function doOne($rig, $preprocess) } refreshbuttons(); echo "
$num
 
 
$err
Unknown custom summary page '$pagename'
Invalid custom summary page '$pagename' (".count($customsummarypages[$pagename]).")
Invalid custom summary page '$pagename' no content
"; - echo ""; - echo " "; - refreshbuttons(); - echo "