Browse Source

Merge branch 'master' of git://github.com/ckolivas/cgminer.git

Paul Sheppard 13 years ago
parent
commit
7b2ada0ee4
15 changed files with 1390 additions and 352 deletions
  1. 534 3
      API-README
  2. 80 0
      NEWS
  3. 14 7
      README
  4. 9 2
      adl.c
  5. 43 5
      api.c
  6. 334 236
      cgminer.c
  7. 2 2
      configure.ac
  8. 13 30
      driver-bitforce.c
  9. 18 8
      driver-opencl.c
  10. 188 5
      fpgautils.c
  11. 21 4
      libztex.c
  12. 14 7
      miner.h
  13. 109 41
      miner.php
  14. 5 2
      scrypt.h
  15. 6 0
      util.c

+ 534 - 3
API-README

@@ -1,6 +1,9 @@
 
 This README contains details about the cgminer RPC API
 
+It also includes some detailed information at the end,
+about using miner.php
+
 
 If you start cgminer with the "--api-listen" option, it will listen on a
 simple TCP/IP socket for single string API requests from the same machine
@@ -119,7 +122,9 @@ The list of requests - a (*) means it requires privileged access - and replies a
                               ADL in use=X, <- Y or N if any GPU has ADL
                               Strategy=Name, <- the current pool strategy
                               Log Interval=N, <- log interval (--log N)
-                              Device Code=GPU ICA | <- spaced list of compiled devices
+                              Device Code=GPU ICA , <- spaced list of compiled devices
+                              OS=Linux/Apple/..., <- operating System
+                              Failover-Only=true/false | <- failover-only setting
 
  summary       SUMMARY        The status summary of the miner
                               e.g. Elapsed=NNN,Found Blocks=N,Getworks=N,...|
@@ -272,6 +277,10 @@ The list of requests - a (*) means it requires privileged access - and replies a
  check|cmd     COMMAND        Exists=Y/N, <- 'cmd' exists in this version
                               Access=Y/N| <- you have access to use 'cmd'
 
+ failover-only|true/false (*)
+               none           There is no reply section just the STATUS section
+                              stating what failover-only was set to
+
 When you enable, disable or restart a GPU or PGA, you will also get Thread messages
 in the cgminer status window
 
@@ -316,7 +325,7 @@ api-example.c - a 'C' program to access the API (with source code)
 
 miner.php - an example web page to access the API
  This includes buttons and inputs to attempt access to the privileged commands
- Read the top of the file (miner.php) for details of how to tune the display
+ See the end of this API-README for details of how to tune the display
  and also to use the option to display a multi-rig summary
 
 ----------
@@ -324,7 +333,25 @@ miner.php - an example web page to access the API
 Feature Changelog for external applications using the API:
 
 
-API V1.15
+API V1.17
+
+Modified API commands:
+ 'summary' - add 'Work Utility'
+ 'pools' - add 'Diff1 Shares'
+
+----------
+
+API V1.16 (cgminer v2.6.5)
+
+Added API commands:
+ 'failover-only'
+
+Modified API commands:
+ 'config' - include failover-only state
+
+----------
+
+API V1.15 (cgminer v2.6.1)
 
 Added API commands:
  'poolpriority'
@@ -533,3 +560,507 @@ Commands:
  'cpucount'
  'quit'
 
+----------------------------------------
+
+miner.php
+=========
+
+miner.php is a PHP based interface to the cgminer RPC API
+(referred to simply as the API below)
+
+It can show rig details, summaries and input fields to allow you to change
+cgminer
+You can also create custom summary pages with it
+
+It has two levels to the security:
+1) cgminer can be configured to allow or disallow API access and access level
+   security for miner.php
+2) miner.php can be configured to allow or disallow privileged cgminer
+   access, if cgminer is configured to allow privileged access for miner.php
+
+---------
+
+To use miner.php requires a web server with PHP
+
+Basics: On xubuntu 11.04, to install apache2 and php, the commands are:
+ sudo apt-get install apache2
+ sudo apt-get install php5
+ sudo /etc/init.d/apache2 reload
+
+On Fedora 17:
+ yum install httpd php
+ systemctl restart httpd.service
+ systemctl enable httpd.service --system
+
+On windows there are a few options.
+Try one of these (I've never used either one)
+ http://www.apachefriends.org/en/xampp.html
+ http://www.wampserver.com/en/
+
+---------
+
+The basic cgminer option to enable the API is:
+
+ --api-listen
+
+or in your cgminer.conf
+
+ "api-listen" : true,
+
+(without the ',' on the end if it is the last item)
+
+If the web server is running on the cgminer computer, the above
+is the only change required to give miner.php basic access to
+the cgminer API
+
+-
+
+If the web server runs on a different computer to cgminer,
+you will also need to tell cgminer to allow the web server
+to access cgminer's API and tell miner.php where cgminer is
+
+Assuming a.b.c.d is the IP address of the web server, you
+would add the following to cgminer:
+
+ --api-listen --api-allow a.b.c.d
+
+or in your cgminer.conf
+
+ "api-listen" : true,
+ "api-allow" : "a.b.c.d",
+
+to tell cgminer to give the web server read access to the API
+
+You also need to tell miner.php where cgminer is.
+Assuming cgminer is at IP address e.f.g.h, then you would
+edit miner.php and change the line
+
+ $rigs = array('127.0.0.1:4028');
+
+to
+
+ $rigs = array('e.f.g.h:4028');
+
+See --api-network or --api-allow for more access details
+and how to give write access
+
+---------
+
+Once you have a web server with PHP running
+
+ copy your miner.php to the main web folder
+
+On Xubuntu 11.04
+ /var/www/
+
+On Fedora 17
+ /var/www/html/
+
+On Windows
+ see your windows Web/PHP documentation
+
+Assuming the IP address of the web server is a.b.c.d
+Then in your web browser go to:
+
+ http://a.b.c.d/miner.php
+
+Done :)
+
+---------
+
+The rest of this documentation deals with the more complex
+functions of miner.php, using myminer.php, creaing custom
+summaries and displaying multiple cgminer rigs
+
+---------
+
+If you create a file called myminer.php in the same web folder
+where you put miner.php, miner.php will load it when it runs
+
+This is useful, to put any changes you need to make to miner.php
+instead of changing miner.php
+Thus if you update/get a new miner.php, you won't lose the changes
+you have made if you put all your changes in myminer.php
+(and don't change miner.php at all)
+
+A simple example myminer.php that defines 2 rigs
+(that I will keep referring to further below) is:
+
+<?php
+#
+$rigs = array('192.168.0.100:4028:A', '192.168.0.102:4028:B');
+#
+?>
+
+Changes in myminer.php superscede what is in miner.php
+However, this is only valid for variables in miner.php before the
+2 lines where myminer.php is included by miner.php:
+
+ if (file_exists('myminer.php'))
+  include_once('myminer.php');
+ 
+Every variable in miner.php above those 2 lines, can be changed by
+simply defining them in your myminer.php
+
+So although miner.php originally contains the line
+
+ $rigs = array('127.0.0.1:4028');
+
+if you created the example myminer.php given above, it would actually
+change the value of $rigs that is used when miner.php is running
+i.e. you don't have to remove or comment out the $rigs line in miner.php
+It will be superceded by myminer.php
+
+---------
+
+The example.php above also shows how to define more that one rig to
+be shown my miner.php
+
+Each rig string is 2 or 3 values seperated by colons ':'
+They are simply an IP address or host name, followed by the
+port number (usually 4028) and an optional Name string
+
+miner.php displays rig buttons that will show the defails of a single
+rig when you click on it - the button shows either the rig number,
+or the 'Name' string if you provide it
+
+PHP arrays contain each string seperated by a comma, but no comma after
+the last one
+
+So an example for 3 rigs would be:
+
+ $rigs = array('192.168.0.100:4028:A', '192.168.0.102:4028:B', '192.168.0.110:4028:C');
+
+Of course each of the rigs listed would also have to have the API
+running and be set to allow the web server to access the API - as
+explained before
+
+---------
+
+So basically, any variable explained below can be put in myminer.php
+if you wanted to set it to something different to it's default value
+and did not want to change miner.php itself every time you updated it
+
+Below is each variable that can be changed and an explanation of each
+
+---------
+
+Default:
+ $readonly = false;
+
+Set $readonly to true to force miner.php to be readonly
+This means it won't allow you to change cgminer even if the cgminer API
+options allow it to
+
+If you set $readonly to false then it will check cgminer 'privileged'
+and will show input fields and buttons on the single rig page
+allowing you to change devices, pools and even quit or restart
+cgminer
+
+However, if the 'privileged' test fails, the code will set $readonly to
+true
+
+---------
+
+Default:
+ $notify = true;
+
+Set $notify to false to NOT attempt to display the notify command
+table of data
+
+Set $notify to true to attempt to display the notify command on
+the single rig page
+If your older version of cgminer returns an 'Invalid command'
+coz it doesn't have notify - it just shows the error status table
+
+---------
+
+Default:
+ $checklastshare = true;
+
+Set $checklastshare to true to do the following checks:
+If a device's last share is 12x expected ago then display as an error
+If a device's last share is 8x expected ago then display as a warning
+If either of the above is true, also display the whole line highlighted
+This assumes shares are 1 difficulty shares
+
+Set $checklastshare to false to not do the above checks
+
+'expected' is calculated from the device MH/s value
+So for example, a device that hashes at 380MH/s should (on average)
+find a share every 11.3s
+If the last share was found more than 11.3 x 12 seconds (135.6s) ago,
+it is considered an error and highlighted
+If the last share was found more than 11.3 x 8 seconds (90.4s) ago,
+it is considered a warning and highlighted
+
+The default highlighting is very subtle
+
+---------
+
+Default:
+ $poolinputs = false;
+
+Set $poolinputs to true to show the input fields for adding a pool
+and changing the pool priorities on a single rig page
+However, if $readonly is true, it will not display them
+
+---------
+
+Default:
+ $rigs = array('127.0.0.1:4028');
+
+Set $rigs to an array of your cgminer rigs that are running
+ format: 'IP:Port' or 'Host:Port' or 'Host:Port:Name'
+If you only have one rig, it will just show the detail of that rig
+If you have more than one rig it will show a summary of all the rigs
+ with buttons to show the details of each rig -
+ the button contents will be 'Name' rather than rig number, if you
+ specify 'Name'
+e.g. $rigs = array('127.0.0.1:4028','myrig.com:4028:Sugoi');
+
+---------
+
+Default:
+ $rigtotals = true;
+ $forcerigtotals = false;
+
+Set $rigtotals to true to display totals on the single rig page
+'false' means no totals (and ignores $forcerigtotals)
+
+If $rigtotals is true, all data is also right aligned
+With false, it's as before, left aligned
+
+This option is just here to allow people to set it to false
+if they prefer the old non-total display when viewing a single rig
+
+Also, if there is only one line shown in any section, then no
+total will be shown (to save screen space)
+You can force it to always show rig totals on the single rig page,
+even if there is only one line, by setting $forcerigtotals = true;
+
+---------
+
+Default:
+ $socksndtimeoutsec = 10;
+ $sockrcvtimeoutsec = 40;
+
+The numbers are integer seconds
+
+The defaults should be OK for most cases
+However, the longer SND is, the longer you have to wait while
+php hangs if the target cgminer isn't runnning or listening
+
+RCV should only ever be relevant if cgminer has hung but the
+API thread is still running, RCV would normally be >= SND
+
+Feel free to increase SND if your network is very slow
+or decrease RCV if that happens often to you
+
+Also, on some windows PHP, apparently the $usec is ignored
+(so usec can't be specified)
+
+---------
+
+Default:
+ $hidefields = array();
+
+List of fields NOT to be displayed
+You can use this to hide data you don't want to see or don't want
+shown on a public web page
+The list of sections are:
+ SUMMARY, POOL, PGA, GPU, NOTIFY, CONFIG, DEVDETAILS, DEVS
+See the web page for the list of field names (the table headers)
+It is an array of 'SECTION.Field Name' => 1
+
+This example would hide the slightly more sensitive pool information:
+Pool URL and pool username:
+ $hidefields = array('POOL.URL' => 1, 'POOL.User' => 1);
+
+If you just want to hide the pool username:
+ $hidefields = array('POOL.User' => 1);
+
+---------
+
+Default:
+ $ignorerefresh = false;
+ $changerefresh = true;
+ $autorefresh = 0;
+
+Auto-refresh of the page (in seconds) - integers only
+
+$ignorerefresh = true/false always ignore refresh parameters
+$changerefresh = true/false show buttons to change the value
+$autorefresh = default value, 0 means dont auto-refresh
+
+---------
+
+Default:
+ $placebuttons = 'top';
+
+Where to place the Refresh, Summary, Custom Pages, Quit, etc. buttons
+
+Valid values are: 'top' 'bot' 'both'
+ anything else means don't show them - case sensitive
+
+---------
+
+Default:
+ $miner_font_family = 'verdana,arial,sans';
+ $miner_font_size = '13pt';
+
+Change these to set the font and font size used on the web page
+
+---------
+
+Default:
+ $colouroverride = array();
+
+Use this to change the web page colour scheme
+
+See $colourtable in miner.php for the list of possible names to change
+
+Simply put in $colouroverride, just the colours you wish to change
+
+e.g. to change the colour of the header font and background
+you could do the following:
+
+ $colouroverride = array(
+	'td.h color'		=> 'green',
+	'td.h background'	=> 'blue'
+ );
+
+---------
+
+Default:
+ $allowcustompages = true;
+
+Should we allow custom pages?
+(or just completely ignore them and don't display the buttons)
+
+---------
+
+OK this part is more complex: Custom Summary Pages
+
+A custom summary page in an array of 'section' => array('FieldA','FieldB'...)
+
+The section defines what data you want in the summary table and the Fields
+define what data you want shown from that section
+
+Standard sections are:
+ SUMMARY, POOL, PGA, GPU, NOTIFY, CONFIG, DEVDETAILS, DEVS, STATS
+
+Fields are the names as shown on the headers on the normal pages
+
+Fields can be 'name=new name' to display 'name' with a different heading
+'new name'
+
+There are also now joined sections:
+ SUMMARY+POOL, SUMMARY+DEVS, SUMMARY+CONFIG, DEVS+NOTIFY, DEVS+DEVDETAILS
+
+These sections are an SQL join of the two sections and the fields in them
+are named section.field where section. is the section the field comes from
+See the example further down
+
+Also note:
+- empty tables are not shown
+- empty columns (e.g. an unknown field) are not shown
+- missing field data shows as blank
+- the field name '*' matches all fields except in joined sections
+  (useful for STATS)
+
+There are 2 hard coded sections:
+ DATE - displays a date table like 'Summary'
+ RIGS - displays a rig table like 'Summary'
+
+Each custom summary requires a second array, that can be empty, listing fields
+to be totaled for each section
+If there is no matching total data, no total will show
+
+---------
+
+Looking at the Mobile example:
+
+ $mobilepage = array(
+  'DATE' => null,
+  'RIGS' => null,
+  'SUMMARY' => array('Elapsed', 'MHS av', 'Found Blocks=Blks', 
+			Accepted', 'Rejected=Rej', 'Utility'),
+  'DEVS+NOTIFY' => array('DEVS.Name=Name', 'DEVS.ID=ID', 'DEVS.Status=Status',
+			'DEVS.Temperature=Temp', 'DEVS.MHS av=MHS av',
+			'DEVS.Accepted=Accept', 'DEVS.Rejected=Rej',
+			'DEVS.Utility=Utility', 'NOTIFY.Last Not Well=Not Well'),
+  'POOL' => array('POOL', 'Status', 'Accepted', 'Rejected=Rej', 'Last Share Time'));
+
+ $mobilesum = array(
+  'SUMMARY' => array('MHS av', 'Found Blocks', 'Accepted', 'Rejected', 'Utility'),
+  'DEVS+NOTIFY' => array('DEVS.MHS av', 'DEVS.Accepted', 'DEVS.Rejected', 'DEVS.Utility'),
+  'POOL' => array('Accepted', 'Rejected'));
+
+ $customsummarypages = array('Mobile' => array($mobilepage, $mobilesum));
+
+This will show 5 tables (according to $mobilepage)
+Each table will have the chosen details for all the rigs specified in $rigs
+
+ DATE
+	A single box with the web server's current date and time
+
+ RIGS
+	A table of the rigs: description, time, versions etc
+
+ SUMMARY
+
+	This will use the API 'summary' command and show the selected fields:
+		Elapsed, MHS av, Found Blocks, Accepted, Rejected and Utility
+	However, 'Rejected=Rej' means that the header displayed for the 'Rejected'
+	field will be 'Rej', instead of 'Rejected' (to save space)
+	Same for 'Found Blocks=Blks' - to save space
+
+ DEVS+NOTIFY
+
+	This will list each of the devices on each rig and display the list of
+	fields as shown
+	It will also include the 'Last Not Well' field from the 'notify' command
+	so you know when the device was last not well
+
+	You will notice that you need to rename each field e.g. 'DEVS.Name=Name'
+	since each field name in the join between DEVS and NOTIFY is actually
+	section.fieldname, not just fieldname
+
+	The join code automatically adds 2 fields to each GPU device: 'Name' and 'ID'
+	They don't exist in the API 'devs' output but you can correctly calculate
+	them from the GPU device data
+	These two fields are used to join DEVS to NOTIFY i.e. find the NOTIFY
+	record that has the same Name and ID as the DEVS record and join them
+
+ POOL
+
+	This will use the API 'pools' command and show the selected fields:
+		POOL, Status, Accepted, Rejected, Last Share Time
+	Again, I renamed the 'Rejected' field using 'Rejected=Rej', to save space
+
+$mobilesum lists the sections and fields that should have a total
+You can't define them for 'DATE' or 'RIGS' since they are hard coded tables
+The example given:
+
+ SUMMARY
+	Show a total at the bottom of the columns for:
+		MHS av, Found Blocks, Accepted, Rejected, Utility
+
+	Firstly note that you use the original name i.e. for 'Rejected=Rej'
+	you use 'Rejected', not 'Rej' and not 'Rejected=Rej'
+
+	Secondly note that it simply adds up the fields
+	If you ask for a total of a string field you will get the numerical
+	sum of the string data
+
+ DEVS+NOTIFY
+
+	Simply note in this join example that you must use the original field
+	names which are section.fieldname, not just fieldname
+
+ POOL
+	Show a total at the bottom of the columns for:
+		Accepted and Rejected
+
+	Again remember to use the original field name 'Rejected'

+ 80 - 0
NEWS

@@ -1,3 +1,83 @@
+Version 2.7.0 - August 18, 2012
+
+- Introduce a new statistic, Work Utility, which is the number of difficulty 1
+shares solved per minute. This is useful for measuring a relative rate of work
+that is independent of reject rate and target difficulty.
+- Implement a new pool strategy, BALANCE, which monitors work performed per pool
+as a rolling average every 10 minutes to try and distribute work evenly over all
+the pools. Do this by monitoring diff1 solutions to allow different difficulty
+target pools to be treated equally, along with solo mining. Update the
+documentation to describe this strategy and more accurately describe the
+load-balance one.
+- Getwork fail was not being detected. Remove a vast amount of unused variables
+and functions used in the old queue request mechanism and redefine the getfail
+testing.
+- Don't try to start devices that don't support scrypt when scrypt mining.
+- 0 is a valid return value for read so only break out if read returns -1.
+- Consider us lagging only once our queue is almost full and no staged work.
+- Simplify the enough work algorithm dramatically.
+- Only queue from backup pools once we have nothing staged.
+- Don't keep queueing work indefinitely if we're in opt failover mode.
+- Make sure we don't opt out of queueing more work if all the queued work is
+from one pool.
+- Set lagging flag if we're on the last of our staged items.
+- Reinstate clone on grabbing work.
+- Grab clones from hashlist wherever possible first.
+- Cull all the early queue requests since we request every time work is popped
+now.
+- Keep track of staged rollable work item counts to speed up clone_available.
+- Make expiry on should_roll to 2/3 time instead of share duration since some
+hardware will have very fast share times.
+- Do the cheaper comparison first.
+- Check that we'll get 1 shares' worth of work time by rolling before saying we
+should roll the work.
+- Simplify all those total_secs usages by initialising it to 1 second.
+- Overlap queued decrementing with staged incrementing.
+- Artificially set the pool lagging flag on pool switch in failover only mode as
+well.
+- Artificially set the pool lagging flag on work restart to avoid messages about
+slow pools after every longpoll.
+- Factor in opt_queue value into enough work queued or staged.
+- Roll work whenever we can on getwork.
+- Queue requests for getwork regardless and test whether we should send for a
+getwork from the getwork thread itself.
+- Get rid of age_work().
+- 0 is a valid return value for read so only break out if read returns -1.
+- Offset libusb reads/writes by length written as well in ztex.
+- Cope with timeouts and partial reads in ztex code.
+- fpga serial I/O extra debug (disabled by default)
+
+
+Version 2.6.5 - August 15, 2012
+
+- Don't try to get bitforce temperature if we're polling for a result to
+minimise the chance of interleaved responses.
+- Set memory clock based on memdiff if present from with engine changes,
+allowing it to parallel manual changes from the menu as well.
+- Increase the timeout on bitforce as per Paul Sheppard's suggestion to account
+for throttling + work time + excess.
+- Fix ADL gpu-map not working when there are more ADL devices than openCL.
+Initial patch supplied by Nite69. Modified to suit.
+- Windows' timer resolution is limited to 15ms accuracy. This was breaking
+dynamic intensity since it tries to measure below this. Since we are repeatedly
+sampling similar timeframes, we can average the gpu_us result over 5 different
+values to get very fine precision.
+- Fix harmless unused warnings in scrypt.h.
+- api.c typo
+- API allow display/change failover-only setting
+- Check we are not lagging as well as there is enough work in getwork.
+- Minimise locking and unlocking when getting counts by reusing shared mutex
+lock functions.
+- Avoid getting more work if by the time the getwork thread is spawned we find
+ourselves with enough work.
+- The bitforce buffer is cleared and hw error count incremented on return from a
+failed send_work already so no need to do it within the send_work function.
+- miner.php allow a custom page section to select all fields with '*' - e.g. to
+create a STATS section on a custom page
+- Escape " and \ when writing json config file
+- miner.php optional single rig totals (on by default)
+
+
 Version 2.6.4 - August 7, 2012
 
 - Convert the serial autodetect functions to use int instead of char to

+ 14 - 7
README

@@ -141,12 +141,13 @@ Options for both config file and command line:
 --api-port          Port number of miner API (default: 4028)
 --auto-fan          Automatically adjust all GPU fan speeds to maintain a target temperature
 --auto-gpu          Automatically adjust all GPU engine clock speeds to maintain a target temperature
+--balance           Change multipool strategy from failover to even share balance
 --benchmark         Run cgminer in benchmark mode - produces no shares
 --debug|-D          Enable debug output
 --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
 --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 even load balance
+--load-balance      Change multipool strategy from failover to efficiency based balance
 --log|-l <arg>      Interval in seconds between log output (default: 5)
 --monitor|-m <arg>  Use custom pipe cmd for output messages
 --net-delay         Impose small delays in networking to not overload slow routers
@@ -386,7 +387,7 @@ The number of hardware erorrs
 The utility defines as the number of shares / minute
 
 The cgminer status line shows:
- TQ: 1  ST: 1  SS: 0  DW: 0  NB: 1  LW: 8  GF: 1  RF: 1
+ TQ: 1  ST: 1  SS: 0  DW: 0  NB: 1  LW: 8  GF: 1  RF: 1  WU:4.4/m
 
 TQ is Total Queued work items.
 ST is STaged work items (ready to use).
@@ -396,6 +397,7 @@ NB is New Blocks detected on the network
 LW is Locally generated Work items
 GF is Getwork Fail Occasions (server slow to provide work)
 RF is Remote Fail occasions (server slow to accept work)
+WU is Work Utility (Rate of difficulty 1 shares solved per minute)
 
 NOTE: Running intensities above 9 with current hardware is likely to only
 diminish return performance even if the hash rate might appear better. A good
@@ -425,8 +427,14 @@ This strategy moves at user-defined intervals from one active pool to the next,
 skipping pools that are idle.
 
 LOAD BALANCE:
-This strategy sends work in equal amounts to all the pools specified. If any
-pool falls idle, the rest will take up the slack keeping the miner busy.
+This strategy sends work to all the pools to maintain optimum load. The most
+efficient pools will tend to get a lot more shares. If any pool falls idle, the
+rest will tend to take up the slack keeping the miner busy.
+
+BALANCE:
+This strategy monitors the amount of difficulty 1 shares solved for each pool
+and uses it to try to end up doing the same amount of work for all pools.
+
 
 ---
 LOGGING
@@ -838,9 +846,8 @@ mining. Since the acronym needs to be only 3 characters, the "Field-" part has
 been skipped.
 
 Q: How do I get my BFL device to auto-recognise?
-A: They are only automatically recognised on linux, and no option needs to be
-passed to them. The only thing that needs to be done is to load the driver for
-them, which on linux would require:
+A: The only thing that needs to be done is to load the driver for them, which
+on linux would require:
 sudo modprobe ftdi_sio vendor=0x0403 product=0x6014
 
 

+ 9 - 2
adl.c

@@ -339,6 +339,9 @@ void init_adl(int nDevs)
 		}
 	}
 
+	if (devices > nDevs)
+		devices = nDevs;
+
 	for (gpu = 0; gpu < devices; gpu++) {
 		struct gpu_adl *ga;
 		int iAdapterIndex;
@@ -788,6 +791,7 @@ static void get_enginerange(int gpu, int *imin, int *imax)
 int set_engineclock(int gpu, int iEngineClock)
 {
 	ADLODPerformanceLevels *lpOdPerformanceLevels;
+	struct cgpu_info *cgpu;
 	int i, lev, ret = 1;
 	struct gpu_adl *ga;
 
@@ -829,6 +833,11 @@ int set_engineclock(int gpu, int iEngineClock)
 	ga->managed = true;
 out:
 	unlock_adl();
+
+	cgpu = &gpus[gpu];
+	if (cgpu->gpu_memdiff)
+		set_memoryclock(gpu, iEngineClock / 100 + cgpu->gpu_memdiff);
+
 	return ret;
 }
 
@@ -1194,8 +1203,6 @@ void gpu_autotune(int gpu, enum dev_enable *denable)
 			newengine /= 100;
 			applog(LOG_INFO, "Setting GPU %d engine clock to %d", gpu, newengine);
 			set_engineclock(gpu, newengine);
-			if (cgpu->gpu_memdiff)
-				set_memoryclock(gpu, newengine + cgpu->gpu_memdiff);
 		}
 	}
 	ga->lasttemp = temp;

+ 43 - 5
api.c

@@ -166,7 +166,7 @@ static const char SEPARATOR = '|';
 #define SEPSTR "|"
 static const char GPUSEP = ',';
 
-static const char *APIVERSION = "1.15";
+static const char *APIVERSION = "1.17";
 static const char *DEAD = "Dead";
 static const char *SICK = "Sick";
 static const char *NOSTART = "NoStart";
@@ -184,6 +184,9 @@ static const char *YES = "Y";
 static const char *NO = "N";
 static const char *NULLSTR = "(null)";
 
+static const char *TRUESTR = "true";
+static const char *FALSESTR = "false";
+
 static const char *DEVICECODE = ""
 #ifdef HAVE_OPENCL
 			"GPU "
@@ -376,6 +379,9 @@ static const char *JSON_PARAMETER = "parameter";
 #define MSG_CHECK 72
 #define MSG_POOLPRIO 73
 #define MSG_DUPPID 74
+#define MSG_MISBOOL 75
+#define MSG_INVBOOL 76
+#define MSG_FOO 77
 
 enum code_severity {
 	SEVERITY_ERR,
@@ -403,6 +409,7 @@ enum code_parameters {
 	PARAM_POOL,
 	PARAM_STR,
 	PARAM_BOTH,
+	PARAM_BOOL,
 	PARAM_NONE
 };
 
@@ -524,6 +531,9 @@ struct CODES {
  { SEVERITY_SUCC,  MSG_MINESTATS,PARAM_NONE,	"CGMiner stats" },
  { SEVERITY_ERR,   MSG_MISCHK,	PARAM_NONE,	"Missing check cmd" },
  { SEVERITY_SUCC,  MSG_CHECK,	PARAM_NONE,	"Check command" },
+ { SEVERITY_ERR,   MSG_MISBOOL,	PARAM_NONE,	"Missing parameter: true/false" },
+ { SEVERITY_ERR,   MSG_INVBOOL,	PARAM_NONE,	"Invalid parameter should be true or false" },
+ { SEVERITY_SUCC,  MSG_FOO,	PARAM_BOOL,	"Failover-Only set to %s" },
  { SEVERITY_FAIL, 0, 0, NULL }
 };
 
@@ -928,7 +938,7 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson
 				sprintf(buf, "%.15f", *((double *)(root->data)));
 				break;
 			case API_BOOL:
-				sprintf(buf, "%s", *((bool *)(root->data)) ? "true" : "false");
+				sprintf(buf, "%s", *((bool *)(root->data)) ? TRUESTR : FALSESTR);
 				break;
 			case API_TIMEVAL:
 				sprintf(buf, "%ld.%06ld",
@@ -1133,6 +1143,9 @@ static char *message(int messageid, int paramid, char *param2, bool isjson)
 				case PARAM_BOTH:
 					sprintf(buf, codes[i].description, paramid, param2);
 					break;
+				case PARAM_BOOL:
+					sprintf(buf, codes[i].description, paramid ? TRUESTR : FALSESTR);
+					break;
 				case PARAM_NONE:
 				default:
 					strcpy(buf, codes[i].description);
@@ -1233,6 +1246,7 @@ static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
 	root = api_add_int(root, "Log Interval", &opt_log_interval, false);
 	root = api_add_const(root, "Device Code", DEVICECODE, false);
 	root = api_add_const(root, "OS", OSINFO, false);
+	root = api_add_bool(root, "Failover-Only", &opt_fail_only, false);
 
 	root = print_data(root, buf, isjson);
 	if (isjson)
@@ -1240,8 +1254,7 @@ static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
 	strcat(io_buffer, buf);
 }
 
-static const char*
-status2str(enum alive status)
+static const char *status2str(enum alive status)
 {
 	switch (status) {
 		case LIFE_WELL:
@@ -1766,6 +1779,7 @@ static void poolstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
 		root = api_add_uint(root, "Remote Failures", &(pool->remotefail_occasions), false);
 		root = api_add_escape(root, "User", pool->rpc_user, false);
 		root = api_add_time(root, "Last Share Time", &(pool->last_share_time), false);
+		root = api_add_int(root, "Diff1 Shares", &(pool->diff1), false);
 
 		if (isjson && (i > 0))
 			strcat(io_buffer, COMMA);
@@ -1782,7 +1796,7 @@ static void summary(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo
 {
 	struct api_data *root = NULL;
 	char buf[TMPBUFSIZ];
-	double utility, mhs;
+	double utility, mhs, work_utility;
 
 #ifdef WANT_CPUMINE
 	char *algo = (char *)(algo_names[opt_algo]);
@@ -1792,6 +1806,7 @@ static void summary(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo
 
 	utility = total_accepted / ( total_secs ? total_secs : 1 ) * 60;
 	mhs = total_mhashes_done / total_secs;
+	work_utility = total_diff1 / ( total_secs ? total_secs : 1 ) * 60;
 
 	sprintf(io_buffer, isjson
 		? "%s," JSON_SUMMARY
@@ -1816,6 +1831,7 @@ static void summary(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo
 	root = api_add_uint(root, "Remote Failures", &(total_ro), false);
 	root = api_add_uint(root, "Network Blocks", &(new_blocks), false);
 	root = api_add_mhtotal(root, "Total MH", &(total_mhashes_done), false);
+	root = api_add_utility(root, "Work Utility", &(work_utility), false);
 
 	root = print_data(root, buf, isjson);
 	if (isjson)
@@ -2704,6 +2720,27 @@ static void minerstats(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
 		strcat(io_buffer, JSON_CLOSE);
 }
 
+static void failoveronly(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
+{
+	if (param == NULL || *param == '\0') {
+		strcpy(io_buffer, message(MSG_MISBOOL, 0, NULL, isjson));
+		return;
+	}
+
+	*param = tolower(*param);
+
+	if (*param != 't' && *param != 'f') {
+		strcpy(io_buffer, message(MSG_INVBOOL, 0, NULL, isjson));
+		return;
+	}
+
+	bool tf = (*param == 't');
+
+	opt_fail_only = tf;
+
+	strcpy(io_buffer, message(MSG_FOO, tf, NULL, isjson));
+}
+
 static void checkcommand(__maybe_unused SOCKETTYPE c, char *param, bool isjson, char group);
 
 struct CMDS {
@@ -2754,6 +2791,7 @@ struct CMDS {
 	{ "restart",		dorestart,	true },
 	{ "stats",		minerstats,	false },
 	{ "check",		checkcommand,	false },
+	{ "failover-only",	failoveronly,	true },
 	{ NULL,			NULL,		false }
 };
 

File diff suppressed because it is too large
+ 334 - 236
cgminer.c


+ 2 - 2
configure.ac

@@ -1,8 +1,8 @@
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_maj], [2])
-m4_define([v_min], [6])
-m4_define([v_mic], [4])
+m4_define([v_min], [7])
+m4_define([v_mic], [0])
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_ver], [v_maj.v_min.v_mic])
 m4_define([lt_rev], m4_eval(v_maj + v_min))

+ 13 - 30
driver-bitforce.c

@@ -51,7 +51,7 @@ enum {
 #define BITFORCE_SLEEP_MS 500
 #define BITFORCE_TIMEOUT_S 7
 #define BITFORCE_TIMEOUT_MS (BITFORCE_TIMEOUT_S * 1000)
-#define BITFORCE_LONG_TIMEOUT_S 15
+#define BITFORCE_LONG_TIMEOUT_S 30
 #define BITFORCE_LONG_TIMEOUT_MS (BITFORCE_LONG_TIMEOUT_S * 1000)
 #define BITFORCE_CHECK_INTERVAL_MS 10
 #define WORK_CHECK_INTERVAL_MS 50
@@ -347,6 +347,11 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
 	if (!fdDev)
 		return false;
 
+	/* Do not try to get the temperature if we're polling for a result to
+	 * minimise the change of interleaved results */
+	if (bitforce->polling)
+		return true;
+
 	/* It is not critical getting temperature so don't get stuck if  we
 	 * can't grab the mutex here */
 	if (mutex_trylock(&bitforce->device_mutex))
@@ -421,8 +426,6 @@ re_send:
 			goto re_send;
 		}
 		applog(LOG_ERR, "BFL%i: Error: Send work reports: %s", bitforce->device_id, pdevbuf);
-		bitforce->hw_errors++;
-		bitforce_clear_buffer(bitforce);
 		return false;
 	}
 
@@ -463,8 +466,6 @@ re_send:
 
 	if (unlikely(strncasecmp(pdevbuf, "OK", 2))) {
 		applog(LOG_ERR, "BFL%i: Error: Send block data reports: %s", bitforce->device_id, pdevbuf);
-		bitforce->hw_errors++;
-		bitforce_clear_buffer(bitforce);
 		return false;
 	}
 
@@ -601,39 +602,21 @@ static void biforce_thread_enable(struct thr_info *thr)
 static int64_t bitforce_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce)
 {
 	struct cgpu_info *bitforce = thr->cgpu;
-	unsigned int sleep_time;
 	bool send_ret;
 	int64_t ret;
 
 	send_ret = bitforce_send_work(thr, work);
 
-	if (!bitforce->nonce_range) {
-		/* Initially wait 2/3 of the average cycle time so we can request more
-		work before full scan is up */
-		sleep_time = (2 * bitforce->sleep_ms) / 3;
-		if (!restart_wait(sleep_time))
-			return 0;
-
-		bitforce->wait_ms = sleep_time;
-		queue_request(thr, false);
-
-		/* Now wait athe final 1/3rd; no bitforce should be finished by now */
-		sleep_time = bitforce->sleep_ms - sleep_time;
-		if (!restart_wait(sleep_time))
-			return 0;
-
-		bitforce->wait_ms += sleep_time;
-	} else {
-		sleep_time = bitforce->sleep_ms;
-		if (!restart_wait(sleep_time))
-			return 0;
+	if (!restart_wait(bitforce->sleep_ms))
+		return 0;
 
-		bitforce->wait_ms = sleep_time;
-	}
+	bitforce->wait_ms = bitforce->sleep_ms;
 
-	if (send_ret)
+	if (send_ret) {
+		bitforce->polling = true;
 		ret = bitforce_get_result(thr, work);
-	else
+		bitforce->polling = false;
+	} else
 		ret = -1;
 
 	if (ret == -1) {

+ 18 - 8
driver-opencl.c

@@ -1490,6 +1490,7 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 	_clState *clState = clStates[thr_id];
 	const cl_kernel *kernel = &clState->kernel;
 	const int dynamic_us = opt_dynamic_interval * 1000;
+	struct timeval tv_gpuend;
 	cl_bool blocking;
 
 	cl_int status;
@@ -1508,13 +1509,17 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 		clFinish(clState->commandQueue);
 
 	if (gpu->dynamic) {
-		struct timeval diff;
-		suseconds_t gpu_us;
-
-		gettimeofday(&gpu->tv_gpuend, NULL);
-		timersub(&gpu->tv_gpuend, &gpu->tv_gpustart, &diff);
-		gpu_us = diff.tv_sec * 1000000 + diff.tv_usec;
-		if (likely(gpu_us >= 0)) {
+		double gpu_us;
+
+		/* Windows returns the same time for gettimeofday due to its
+		 * 15ms timer resolution, so we must average the result over
+		 * at least 5 values that are actually different to get an
+		 * accurate result */
+		gpu->intervals++;
+		gettimeofday(&tv_gpuend, NULL);
+		gpu_us = us_tdiff(&tv_gpuend, &gpu->tv_gpumid);
+		if (gpu_us > 0 && ++gpu->hit > 4) {
+			gpu_us = us_tdiff(&tv_gpuend, &gpu->tv_gpustart) / gpu->intervals;
 			gpu->gpu_us_average = (gpu->gpu_us_average + gpu_us * 0.63) / 1.63;
 
 			/* Try to not let the GPU be out for longer than 
@@ -1527,6 +1532,7 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 				if (gpu->intensity < MAX_INTENSITY)
 					++gpu->intensity;
 			}
+			gpu->intervals = gpu->hit = 0;
 		}
 	}
 	set_threads_hashes(clState->vwidth, &threads, &hashes, globalThreads,
@@ -1562,7 +1568,11 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 			clFinish(clState->commandQueue);
 	}
 
-	gettimeofday(&gpu->tv_gpustart, NULL);
+	gettimeofday(&gpu->tv_gpumid, NULL);
+	if (!gpu->intervals) {
+		gpu->tv_gpustart.tv_sec = gpu->tv_gpumid.tv_sec;
+		gpu->tv_gpustart.tv_usec = gpu->tv_gpumid.tv_usec;
+	}
 
 	if (clState->goffset) {
 		size_t global_work_offset[1];

+ 188 - 5
fpgautils.c

@@ -143,6 +143,174 @@ _serial_detect(const char*dname, detectone_func_t detectone, autoscan_func_t aut
 	return found;
 }
 
+// This code is purely for debugging but is very useful for that
+// It also took quite a bit of effort so I left it in
+// #define TERMIOS_DEBUG 1
+// Here to include it at compile time
+// It's off by default
+#ifndef WIN32
+#ifdef TERMIOS_DEBUG
+
+#define BITSSET "Y"
+#define BITSNOTSET "N"
+
+int tiospeed(speed_t speed)
+{
+	switch (speed) {
+	case B0:
+		return 0;
+	case B50:
+		return 50;
+	case B75:
+		return 75;
+	case B110:
+		return 110;
+	case B134:
+		return 134;
+	case B150:
+		return 150;
+	case B200:
+		return 200;
+	case B300:
+		return 300;
+	case B600:
+		return 600;
+	case B1200:
+		return 1200;
+	case B1800:
+		return 1800;
+	case B2400:
+		return 2400;
+	case B4800:
+		return 4800;
+	case B9600:
+		return 9600;
+	case B19200:
+		return 19200;
+	case B38400:
+		return 38400;
+	case B57600:
+		return 57600;
+	case B115200:
+		return 115200;
+	case B230400:
+		return 230400;
+	case B460800:
+		return 460800;
+	case B500000:
+		return 500000;
+	case B576000:
+		return 576000;
+	case B921600:
+		return 921600;
+	case B1000000:
+		return 1000000;
+	case B1152000:
+		return 1152000;
+	case B1500000:
+		return 1500000;
+	case B2000000:
+		return 2000000;
+	case B2500000:
+		return 2500000;
+	case B3000000:
+		return 3000000;
+	case B3500000:
+		return 3500000;
+	case B4000000:
+		return 4000000;
+	default:
+		return -1;
+	}
+}
+
+void termios_debug(const char *devpath, struct termios *my_termios, const char *msg)
+{
+	applog(LOG_DEBUG, "TIOS: Open %s attributes %s: ispeed=%d ospeed=%d",
+			devpath, msg, tiospeed(cfgetispeed(my_termios)), tiospeed(cfgetispeed(my_termios)));
+
+#define ISSETI(b) ((my_termios->c_iflag | (b)) ? BITSSET : BITSNOTSET)
+
+	applog(LOG_DEBUG, "TIOS:  c_iflag: IGNBRK=%s BRKINT=%s IGNPAR=%s PARMRK=%s INPCK=%s ISTRIP=%s INLCR=%s IGNCR=%s ICRNL=%s IUCLC=%s IXON=%s IXANY=%s IOFF=%s IMAXBEL=%s IUTF8=%s",
+			ISSETI(IGNBRK), ISSETI(BRKINT), ISSETI(IGNPAR), ISSETI(PARMRK),
+			ISSETI(INPCK), ISSETI(ISTRIP), ISSETI(INLCR), ISSETI(IGNCR),
+			ISSETI(ICRNL), ISSETI(IUCLC), ISSETI(IXON), ISSETI(IXANY),
+			ISSETI(IXOFF), ISSETI(IMAXBEL), ISSETI(IUTF8));
+
+#define ISSETO(b) ((my_termios->c_oflag | (b)) ? BITSSET : BITSNOTSET)
+#define VALO(b) (my_termios->c_oflag | (b))
+
+	applog(LOG_DEBUG, "TIOS:  c_oflag: OPOST=%s OLCUC=%s ONLCR=%s OCRNL=%s ONOCR=%s ONLRET=%s OFILL=%s OFDEL=%s NLDLY=%d CRDLY=%d TABDLY=%d BSDLY=%d VTDLY=%d FFDLY=%d",
+			ISSETO(OPOST), ISSETO(OLCUC), ISSETO(ONLCR), ISSETO(OCRNL),
+			ISSETO(ONOCR), ISSETO(ONLRET), ISSETO(OFILL), ISSETO(OFDEL),
+			VALO(NLDLY), VALO(CRDLY), VALO(TABDLY), VALO(BSDLY),
+			VALO(VTDLY), VALO(FFDLY));
+
+#define ISSETC(b) ((my_termios->c_cflag | (b)) ? BITSSET : BITSNOTSET)
+#define VALC(b) (my_termios->c_cflag | (b))
+
+	applog(LOG_DEBUG, "TIOS:  c_cflag: CBAUDEX=%s CSIZE=%d CSTOPB=%s CREAD=%s PARENB=%s PARODD=%s HUPCL=%s CLOCAL=%s"
+#ifdef LOBLK
+			" LOBLK=%s"
+#endif
+			" CMSPAR=%s CRTSCTS=%s",
+			ISSETC(CBAUDEX), VALC(CSIZE), ISSETC(CSTOPB), ISSETC(CREAD),
+			ISSETC(PARENB), ISSETC(PARODD), ISSETC(HUPCL), ISSETC(CLOCAL),
+#ifdef LOBLK
+			ISSETC(LOBLK),
+#endif
+			ISSETC(CMSPAR), ISSETC(CRTSCTS));
+
+#define ISSETL(b) ((my_termios->c_lflag | (b)) ? BITSSET : BITSNOTSET)
+
+	applog(LOG_DEBUG, "TIOS:  c_lflag: ISIG=%s ICANON=%s XCASE=%s ECHO=%s ECHOE=%s ECHOK=%s ECHONL=%s ECHOCTL=%s ECHOPRT=%s ECHOKE=%s"
+#ifdef DEFECHO
+			" DEFECHO=%s"
+#endif
+			" FLUSHO=%s NOFLSH=%s TOSTOP=%s PENDIN=%s IEXTEN=%s",
+			ISSETL(ISIG), ISSETL(ICANON), ISSETL(XCASE), ISSETL(ECHO),
+			ISSETL(ECHOE), ISSETL(ECHOK), ISSETL(ECHONL), ISSETL(ECHOCTL),
+			ISSETL(ECHOPRT), ISSETL(ECHOKE),
+#ifdef DEFECHO
+			ISSETL(DEFECHO),
+#endif
+			ISSETL(FLUSHO), ISSETL(NOFLSH), ISSETL(TOSTOP), ISSETL(PENDIN),
+			ISSETL(IEXTEN));
+
+#define VALCC(b) (my_termios->c_cc[b])
+	applog(LOG_DEBUG, "TIOS:  c_cc: VINTR=0x%02x VQUIT=0x%02x VERASE=0x%02x VKILL=0x%02x VEOF=0x%02x VMIN=%u VEOL=0x%02x VTIME=%u VEOL2=0x%02x"
+#ifdef VSWTCH
+			" VSWTCH=0x%02x"
+#endif
+			" VSTART=0x%02x VSTOP=0x%02x VSUSP=0x%02x"
+#ifdef VDSUSP
+			" VDSUSP=0x%02x"
+#endif
+			" VLNEXT=0x%02x VWERASE=0x%02x VREPRINT=0x%02x VDISCARD=0x%02x"
+#ifdef VSTATUS
+			" VSTATUS=0x%02x"
+#endif
+			,
+			VALCC(VINTR), VALCC(VQUIT), VALCC(VERASE), VALCC(VKILL),
+			VALCC(VEOF), VALCC(VMIN), VALCC(VEOL), VALCC(VTIME),
+			VALCC(VEOL2),
+#ifdef VSWTCH
+			VALCC(VSWTCH),
+#endif
+			VALCC(VSTART), VALCC(VSTOP), VALCC(VSUSP),
+#ifdef VDSUSP
+			VALCC(VDSUSP),
+#endif
+			VALCC(VLNEXT), VALCC(VWERASE),
+			VALCC(VREPRINT), VALCC(VDISCARD)
+#ifdef VSTATUS
+			,VALCC(VSTATUS)
+#endif
+			);
+}
+#endif
+#endif
+
 int
 serial_open(const char*devpath, unsigned long baud, signed short timeout, bool purge)
 {
@@ -208,19 +376,24 @@ serial_open(const char*devpath, unsigned long baud, signed short timeout, bool p
 
 	tcgetattr(fdDev, &my_termios);
 
+#ifdef TERMIOS_DEBUG
+	termios_debug(devpath, &my_termios, "before");
+#endif
+
 	switch (baud) {
 	case 0:
 		break;
 	case 57600:
-		cfsetispeed( &my_termios, B57600 );
-		cfsetospeed( &my_termios, B57600 );
+		cfsetispeed(&my_termios, B57600);
+		cfsetospeed(&my_termios, B57600);
 		break;
 	case 115200:
-		cfsetispeed( &my_termios, B115200 );
-		cfsetospeed( &my_termios, B115200 );
+		cfsetispeed(&my_termios, B115200);
+		cfsetospeed(&my_termios, B115200);
 		break;
 	// TODO: try some higher speeds with the Icarus and BFL to see
 	// if they support them and if setting them makes any difference
+	// N.B. B3000000 doesn't work on Icarus
 	default:
 		applog(LOG_WARNING, "Unrecognized baud rate: %lu", baud);
 	}
@@ -239,7 +412,17 @@ serial_open(const char*devpath, unsigned long baud, signed short timeout, bool p
 	my_termios.c_cc[VTIME] = (cc_t)timeout;
 	my_termios.c_cc[VMIN] = 0;
 
+#ifdef TERMIOS_DEBUG
+	termios_debug(devpath, &my_termios, "settings");
+#endif
+
 	tcsetattr(fdDev, TCSANOW, &my_termios);
+
+#ifdef TERMIOS_DEBUG
+	tcgetattr(fdDev, &my_termios);
+	termios_debug(devpath, &my_termios, "after");
+#endif
+
 	if (purge)
 		tcflush(fdDev, TCIOFLUSH);
 	return fdDev;
@@ -252,7 +435,7 @@ _serial_read(int fd, char *buf, size_t bufsiz, char *eol)
 	ssize_t len, tlen = 0;
 	while (bufsiz) {
 		len = read(fd, buf, eol ? 1 : bufsiz);
-		if (len < 1)
+		if (unlikely(len == -1))
 			break;
 		tlen += len;
 		if (eol && *eol == buf[0])

+ 21 - 4
libztex.c

@@ -607,11 +607,19 @@ int libztex_scanDevices(struct libztex_dev_list*** devs_p)
 
 int libztex_sendHashData(struct libztex_device *ztex, unsigned char *sendbuf)
 {
-	int cnt;
+	int cnt, ret, len;
 
 	if (ztex == NULL || ztex->hndl == NULL)
 		return 0;
-	cnt = libusb_control_transfer(ztex->hndl, 0x40, 0x80, 0, 0, sendbuf, 44, 1000);
+	ret = 44; len = 0;
+	while (ret > 0) {
+		cnt = libusb_control_transfer(ztex->hndl, 0x40, 0x80, 0, 0, sendbuf + len, ret, 1000);
+		if (cnt >= 0) {
+			ret -= cnt;
+			len += cnt;
+		} else
+			break;
+	}
 	if (unlikely(cnt < 0))
 		applog(LOG_ERR, "%s: Failed sendHashData with err %d", ztex->repr, cnt);
 	
@@ -620,8 +628,8 @@ int libztex_sendHashData(struct libztex_device *ztex, unsigned char *sendbuf)
 
 int libztex_readHashData(struct libztex_device *ztex, struct libztex_hash_data nonces[]) {
 	int bufsize = 12 + ztex->extraSolutions * 4;
+	int cnt = 0, i, j, ret, len;
 	unsigned char *rbuf;
-	int cnt, i, j;
 
 	if (ztex->hndl == NULL)
 		return 0;
@@ -631,7 +639,16 @@ int libztex_readHashData(struct libztex_device *ztex, struct libztex_hash_data n
 		applog(LOG_ERR, "%s: Failed to allocate memory for reading nonces", ztex->repr);
 		return 0;
 	}
-	cnt = libusb_control_transfer(ztex->hndl, 0xc0, 0x81, 0, 0, rbuf, bufsize * ztex->numNonces, 1000);
+	ret = bufsize * ztex->numNonces; len = 0;
+	while (ret > 0) {
+		cnt = libusb_control_transfer(ztex->hndl, 0xc0, 0x81, 0, 0, rbuf + len, ret, 1000);
+		if (cnt >= 0) {
+			ret -= cnt;
+			len += cnt;
+		} else
+			break;
+	}
+
 	if (unlikely(cnt < 0)) {
 		applog(LOG_ERR, "%s: Failed readHashData with err %d", ztex->repr, cnt);
 		free(rbuf);

+ 14 - 7
miner.h

@@ -173,9 +173,10 @@ enum pool_strategy {
 	POOL_ROUNDROBIN,
 	POOL_ROTATE,
 	POOL_LOADBALANCE,
+	POOL_BALANCE,
 };
 
-#define TOP_STRATEGY (POOL_LOADBALANCE)
+#define TOP_STRATEGY (POOL_BALANCE)
 
 struct strategies {
 	const char *s;
@@ -329,6 +330,7 @@ struct cgpu_info {
 	unsigned int avg_wait_d;
 	uint32_t nonces;
 	bool nonce_range;
+	bool polling;
 #endif
 	pthread_mutex_t		device_mutex;
 
@@ -366,9 +368,10 @@ struct cgpu_info {
 	int opt_tc, thread_concurrency;
 	int shaders;
 #endif
-	struct timeval tv_gpustart;;
-	struct timeval tv_gpuend;
+	struct timeval tv_gpustart;
+	struct timeval tv_gpumid;
 	double gpu_us_average;
+	int intervals, hit;
 #endif
 
 	float temp;
@@ -440,6 +443,7 @@ extern int thr_info_create(struct thr_info *thr, pthread_attr_t *attr, void *(*s
 extern void thr_info_cancel(struct thr_info *thr);
 extern void thr_info_freeze(struct thr_info *thr);
 extern void nmsleep(unsigned int msecs);
+extern double us_tdiff(struct timeval *end, struct timeval *start);
 
 struct string_elist {
 	char *string;
@@ -551,6 +555,7 @@ extern bool opt_protocol;
 extern char *opt_kernel_path;
 extern char *opt_socks_proxy;
 extern char *cgminer_path;
+extern bool opt_fail_only;
 extern bool opt_autofan;
 extern bool opt_autoengine;
 extern bool use_curses;
@@ -595,7 +600,6 @@ extern pthread_mutex_t restart_lock;
 extern pthread_cond_t restart_cond;
 
 extern void thread_reportin(struct thr_info *thr);
-extern bool queue_request(struct thr_info *thr, bool needed);
 extern int restart_wait(unsigned int mstime);
 
 extern void kill_work(void);
@@ -658,7 +662,7 @@ extern int opt_rotate_period;
 extern double total_mhashes_done;
 extern unsigned int new_blocks;
 extern unsigned int found_blocks;
-extern int total_accepted, total_rejected;
+extern int total_accepted, total_rejected, total_diff1;;
 extern int total_getworks, total_stale, total_discarded;
 extern unsigned int local_work;
 extern unsigned int total_go, total_ro;
@@ -720,8 +724,7 @@ struct pool {
 	int accepted, rejected;
 	int seq_rejects;
 	int solved;
-	int queued;
-	int staged;
+	int diff1;
 
 	bool submit_fail;
 	bool idle;
@@ -742,6 +745,9 @@ struct pool {
 	unsigned int remotefail_occasions;
 	struct timeval tv_idle;
 
+	double utility;
+	int last_shares, shares;
+
 	char *rpc_url;
 	char *rpc_userpass;
 	char *rpc_user, *rpc_pass;
@@ -791,6 +797,7 @@ struct work {
 	bool		stale;
 	bool		mandatory;
 	bool		block;
+	bool		queued;
 
 	unsigned int	work_block;
 	int		id;

+ 109 - 41
miner.php

@@ -2,6 +2,7 @@
 session_start();
 #
 global $miner, $port, $readonly, $notify, $rigs;
+global $rigtotals, $forcerigtotals;
 global $socksndtimeoutsec, $sockrcvtimeoutsec;
 global $checklastshare, $poolinputs, $hidefields;
 global $ignorerefresh, $changerefresh, $autorefresh;
@@ -9,9 +10,8 @@ global $allowcustompages, $customsummarypages;
 global $miner_font_family, $miner_font_size;
 global $colouroverride, $placebuttons;
 #
-# Don't touch these 2 - see $rigs below
-$miner = null;
-$port = null;
+# See API-README for more details of these variables and how
+# to configure miner.php
 #
 # Set $readonly to true to force miner.php to be readonly
 # Set $readonly to false then it will check cgminer 'privileged'
@@ -19,8 +19,6 @@ $readonly = false;
 #
 # Set $notify to false to NOT attempt to display the notify command
 # Set $notify to true to attempt to display the notify command
-# If your older version of cgminer returns an 'Invalid command'
-#  coz it doesn't have notify - it just shows the error status table
 $notify = true;
 #
 # Set $checklastshare to true to do the following checks:
@@ -37,30 +35,20 @@ $poolinputs = false;
 #
 # Set $rigs to an array of your cgminer rigs that are running
 #  format: 'IP:Port' or 'Host:Port' or 'Host:Port:Name'
-# If you only have one rig, it will just show the detail of that rig
-# If you have more than one rig it will show a summary of all the rigs
-#  with buttons to show the details of each rig -
-#  the button contents will be 'Name' if that was specified
-# e.g. $rigs = array('127.0.0.1:4028','myrig.com:4028:Sugoi');
 $rigs = array('127.0.0.1:4028');
 #
+# Set $rigtotals to true to display totals on the single rig page
+# 'false' means no totals (and ignores $forcerigtotals)
+# You can force it to always show rig totals when there is only
+# one line by setting $forcerigtotals = true;
+$rigtotals = true;
+$forcerigtotals = false;
+#
 # These should be OK for most cases
-# However, the longer SND is, the longer you have to wait while
-# php hangs if the target cgminer isn't runnning or listening
-# RCV should only ever be relevant if cgminer has hung but the
-# API thread is still running, RCV would normally be >= SND
-# Feel free to increase SND if your network is very slow
-# or decrease RCV if that happens often to you
-# Also, on some windows PHP, apparently the $usec is ignored
 $socksndtimeoutsec = 10;
 $sockrcvtimeoutsec = 40;
 #
 # List of fields NOT to be displayed
-# You can use this to hide data you don't want to see or don't want
-# shown on a public web page
-# The list of sections are: SUMMARY, POOL, PGA, GPU, NOTIFY, CONFIG
-# See the web page for the list of field names (the table headers)
-# It is an array of 'SECTION.Field Name' => 1
 # This example would hide the slightly more sensitive pool information
 #$hidefields = array('POOL.URL' => 1, 'POOL.User' => 1);
 $hidefields = array();
@@ -74,19 +62,11 @@ $changerefresh = true;
 $autorefresh = 0;
 #
 # Should we allow custom pages?
-# (or just completely ignore then and don't display the buttons)
+# (or just completely ignore them 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'...)
-#  Field can be 'name=new name' to display 'name' with a different heading 'new name'
-# 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
-# - section = 'DATE' displays a date table like 'Summary'
-# - section = 'RIGS' displays a rig table like 'Summary'
-# There is a second array, listing fields to be totaled for each section
+# As mentioned above, see API-README
 # see the example below (if there is no matching data, no total will show)
 $mobilepage = array(
  'DATE' => null,
@@ -161,6 +141,10 @@ $colourtable = array(
 	'td.lo background'	=> '#deffff'
 );
 #
+# Don't touch these 2
+$miner = null;
+$port = null;
+#
 # Ensure it is only ever shown once
 global $showndate;
 $showndate = false;
@@ -790,7 +774,7 @@ function fmt($section, $name, $value, $when, $alldata)
  if ($class == '' && ($rownum % 2) == 0)
 	$class = $c2class;
 
- if ($ret == '')
+ if ($ret === '')
 	$ret = $b;
 
  return array($ret, $class);
@@ -829,9 +813,47 @@ function showdatetime()
  otherrow('<td class=sta>Date: '.date($dfmt).'</td>');
 }
 #
+global $singlerigsum;
+$singlerigsum = array(
+ 'devs' => array('MHS av' => 1, 'MHS 5s' => 1, 'Accepted' => 1, 'Rejected' => 1,
+			'Hardware Errors' => 1, 'Utility' => 1, 'Total MH' => 1),
+ 'pools' => array('Getworks' => 1, 'Accepted' => 1, 'Rejected' => 1, 'Discarded' => 1,
+			'Stale' => 1, 'Get Failures' => 1, 'Remote Failures' => 1),
+ 'notify' => array('*' => 1));
+#
+function showtotal($total, $when, $oldvalues)
+{
+ global $rigtotals;
+
+ list($showvalue, $class) = fmt('total', '', 'Total:', $when, null);
+ echo "<td$class align=right>$showvalue</td>";
+
+ $skipfirst = true;
+ foreach ($oldvalues as $name => $value)
+ {
+	if ($skipfirst === true)
+	{
+		$skipfirst = false;
+		continue;
+	}
+
+	if (isset($total[$name]))
+		$newvalue = $total[$name];
+	else
+		$newvalue = '';
+
+	list($showvalue, $class) = fmt('total', $name, $newvalue, $when, null);
+	echo "<td$class";
+	if ($rigtotals === true)
+		echo ' align=right';
+	echo ">$showvalue</td>";
+ }
+}
+#
 function details($cmd, $list, $rig)
 {
  global $dfmt, $poolcmd, $readonly, $showndate;
+ global $rownum, $rigtotals, $forcerigtotals, $singlerigsum;
 
  $when = 0;
 
@@ -864,8 +886,15 @@ function details($cmd, $list, $rig)
 	endrow();
  }
 
+ if ($rigtotals === true && isset($singlerigsum[$cmd]))
+	$dototal = $singlerigsum[$cmd];
+ else
+	$dototal = array();
+
+ $total = array();
 
  $section = '';
+ $oldvalues = null;
  foreach ($list as $item => $values)
  {
 	if ($item == 'STATUS')
@@ -873,8 +902,13 @@ function details($cmd, $list, $rig)
 
 	$sectionname = preg_replace('/\d/', '', $item);
 
+	// Handle 'devs' possibly containing >1 table
 	if ($sectionname != $section)
 	{
+		if ($oldvalues != null && count($total) > 0
+		&&  ($rownum > 2 || $forcerigtotals === true))
+			showtotal($total, $when, $oldvalues);
+
 		endtable();
 		newtable();
 		showhead($cmd, $values);
@@ -886,7 +920,19 @@ function details($cmd, $list, $rig)
 	foreach ($values as $name => $value)
 	{
 		list($showvalue, $class) = fmt($section, $name, $value, $when, $values);
-		echo "<td$class>$showvalue</td>";
+		echo "<td$class";
+		if ($rigtotals === true)
+			echo ' align=right';
+		echo ">$showvalue</td>";
+
+		if (isset($dototal[$name])
+		||  (isset($dototal['*']) and substr($name, 0, 1) == '*'))
+		{
+			if (isset($total[$name]))
+				$total[$name] += $value;
+			else
+				$total[$name] = $value;
+		}
 	}
 
 	if ($cmd == 'pools' && $readonly === false)
@@ -908,7 +954,14 @@ function details($cmd, $list, $rig)
 		}
 	}
 	endrow();
+
+	$oldvalues = $values;
  }
+
+ if ($oldvalues != null && count($total) > 0
+ &&  ($rownum > 2 || $forcerigtotals === true))
+	showtotal($total, $when, $oldvalues);
+
  endtable();
 }
 #
@@ -1736,14 +1789,29 @@ function processcustompage($pagename, $sections, $sum, $namemap)
 					foreach ($result as $sec => $row)
 					{
 						$secname = preg_replace('/\d/', '', $sec);
-						if (secmatch($section, $secname) && isset($row[$field]))
+						if (secmatch($section, $secname))
 						{
-							$showfields[$field] = 1;
-							$map = $section.'.'.$field;
-							if (isset($namemap[$map]))
-								$showhead[$namemap[$map]] = 1;
-							else
-								$showhead[$field] = 1;
+							if ($field === '*')
+							{
+								foreach ($row as $f => $v)
+								{
+									$showfields[$f] = 1;
+									$map = $section.'.'.$f;
+									if (isset($namemap[$map]))
+										$showhead[$namemap[$map]] = 1;
+									else
+										$showhead[$f] = 1;
+								}
+							}
+							elseif (isset($row[$field]))
+							{
+								$showfields[$field] = 1;
+								$map = $section.'.'.$field;
+								if (isset($namemap[$map]))
+									$showhead[$namemap[$map]] = 1;
+								else
+									$showhead[$field] = 1;
+							}
 						}
 					}
 

+ 5 - 2
scrypt.h

@@ -2,9 +2,12 @@
 #define SCRYPT_H
 
 #ifdef USE_SCRYPT
-extern bool scrypt_test(unsigned char *pdata, const unsigned char *ptarget, uint32_t nonce);
+extern bool scrypt_test(unsigned char *pdata, const unsigned char *ptarget,
+			uint32_t nonce);
 #else /* USE_SCRYPT */
-static inline bool scrypt_test(unsigned char *pdata, const unsigned char *ptarget, uint32_t nonce)
+static inline bool scrypt_test(__maybe_unused unsigned char *pdata,
+			       __maybe_unused const unsigned char *ptarget,
+			       __maybe_unused uint32_t nonce)
 {
 	return false;
 }

+ 6 - 0
util.c

@@ -705,3 +705,9 @@ void nmsleep(unsigned int msecs)
 		ret = nanosleep(&twait, &tleft);
 	} while (ret == -1 && errno == EINTR);
 }
+
+/* Returns the microseconds difference between end and start times as a double */
+double us_tdiff(struct timeval *end, struct timeval *start)
+{
+	return end->tv_sec * 1000000 + end->tv_usec - start->tv_sec * 1000000 - start->tv_usec;
+}

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