mirror of
https://github.com/GOSTSec/sgminer
synced 2025-08-26 13:52:02 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
7f54adb4c9
459
API-README
Normal file
459
API-README
Normal file
@ -0,0 +1,459 @@
|
|||||||
|
|
||||||
|
This README contains details about the cgminer RPC API
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
running cgminer and reply with a string and then close the socket each time
|
||||||
|
If you add the "--api-network" option, it will accept API requests from any
|
||||||
|
network attached computer.
|
||||||
|
|
||||||
|
You can only access the comands that reply with data in this mode.
|
||||||
|
By default, you cannot access any privileged command that affects the miner -
|
||||||
|
you will receive an access denied status message see --api-allow below.
|
||||||
|
|
||||||
|
You can specify IP addresses/prefixes that are only allowed to access the API
|
||||||
|
with the "--api-allow" option e.g. --api-allow W:192.168.0.1,10.0.0/24
|
||||||
|
will allow 192.168.0.1 or any address matching 10.0.0.*, but nothing else
|
||||||
|
IP addresses are automatically padded with extra '.0's as needed
|
||||||
|
Without a /prefix is the same as specifying /32
|
||||||
|
0/0 means all IP addresses.
|
||||||
|
The 'W:' on the front gives that address/subnet privileged access to commands
|
||||||
|
that modify cgminer.
|
||||||
|
Without it those commands return an access denied status.
|
||||||
|
Privileged access is checked in the order the IP addresses were supplied to
|
||||||
|
"--api-allow"
|
||||||
|
The first match determines the privilege level.
|
||||||
|
Using the "--api-allow" option overides the "--api-network" option if they
|
||||||
|
are both specified
|
||||||
|
With "--api-allow", 127.0.0.1 is not by default given access unless specified
|
||||||
|
|
||||||
|
The RPC API request can be either simple text or JSON.
|
||||||
|
|
||||||
|
If the request is JSON (starts with '{'), it will reply with a JSON formatted
|
||||||
|
response, otherwise it replies with text formatted as described further below.
|
||||||
|
|
||||||
|
The JSON request format required is '{"command":"CMD","parameter":"PARAM"}'
|
||||||
|
(though of course parameter is not required for all requests)
|
||||||
|
where "CMD" is from the "Request" column below and "PARAM" would be e.g.
|
||||||
|
the CPU/GPU number if required.
|
||||||
|
|
||||||
|
An example request in both formats to set GPU 0 fan to 80%:
|
||||||
|
gpufan|0,80
|
||||||
|
{"command":"gpufan","parameter":"0,80"}
|
||||||
|
|
||||||
|
The format of each reply (unless stated otherwise) is a STATUS section
|
||||||
|
followed by an optional detail section
|
||||||
|
|
||||||
|
From API version 1.7 onwards, reply strings in JSON and Text have the
|
||||||
|
necessary escaping as required to avoid ambiguity - they didn't before 1.7
|
||||||
|
For JSON the 2 characters '"' and '\' are escaped with a '\' before them
|
||||||
|
For Text the 4 characters '|' ',' '=' and '\' are escaped the same way
|
||||||
|
|
||||||
|
Only user entered information will contain characters that require being
|
||||||
|
escaped, such as Pool URL, User and Password or the Config save filename,
|
||||||
|
when they are returned in messages or as their values by the API
|
||||||
|
|
||||||
|
For API version 1.4 and later:
|
||||||
|
|
||||||
|
The STATUS section is:
|
||||||
|
|
||||||
|
STATUS=X,When=NNN,Code=N,Msg=string,Description=string|
|
||||||
|
|
||||||
|
STATUS=X Where X is one of:
|
||||||
|
W - Warning
|
||||||
|
I - Informational
|
||||||
|
S - Success
|
||||||
|
E - Error
|
||||||
|
F - Fatal (code bug)
|
||||||
|
|
||||||
|
When=NNN
|
||||||
|
Standard long time of request in seconds
|
||||||
|
|
||||||
|
Code=N
|
||||||
|
Each unique reply has a unigue Code (See api.c - #define MSG_NNNNNN)
|
||||||
|
|
||||||
|
Msg=string
|
||||||
|
Message matching the Code value N
|
||||||
|
|
||||||
|
Description=string
|
||||||
|
This defaults to the cgminer version but is the value of --api-description
|
||||||
|
if it was specified at runtime.
|
||||||
|
|
||||||
|
For API version 1.9:
|
||||||
|
|
||||||
|
The list of requests - a (*) means it requires privileged access - and replies are:
|
||||||
|
|
||||||
|
Request Reply Section Details
|
||||||
|
------- ------------- -------
|
||||||
|
version VERSION CGMiner=cgminer version
|
||||||
|
API=API version
|
||||||
|
|
||||||
|
config CONFIG Some miner configuration information:
|
||||||
|
GPU Count=N, <- the number of GPUs
|
||||||
|
PGA Count=N, <- the number of PGAs
|
||||||
|
CPU Count=N, <- the number of CPUs
|
||||||
|
Pool Count=N, <- the number of Pools
|
||||||
|
ADL=X, <- Y or N if ADL is compiled in the code
|
||||||
|
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
|
||||||
|
|
||||||
|
summary SUMMARY The status summary of the miner
|
||||||
|
e.g. Elapsed=NNN,Found Blocks=N,Getworks=N,...|
|
||||||
|
|
||||||
|
pools POOLS The status of each pool
|
||||||
|
e.g. Pool=0,URL=http://pool.com:6311,Status=Alive,...|
|
||||||
|
|
||||||
|
devs DEVS Each available GPU, PGA and CPU with their details
|
||||||
|
e.g. GPU=0,Accepted=NN,MHS av=NNN,...,Intensity=D|
|
||||||
|
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)
|
||||||
|
Will not report PGAs if PGA mining is disabled
|
||||||
|
Will not report CPUs if CPU mining is disabled
|
||||||
|
|
||||||
|
gpu|N GPU The details of a single GPU number N in the same
|
||||||
|
format and details as for DEVS
|
||||||
|
|
||||||
|
pga|N PGA The details of a single PGA number N in the same
|
||||||
|
format and details as for DEVS
|
||||||
|
This is only available if PGA mining is enabled
|
||||||
|
Use 'pgacount' or 'config' first to see if there are any
|
||||||
|
|
||||||
|
cpu|N CPU The details of a single CPU number N in the same
|
||||||
|
format and details as for DEVS
|
||||||
|
This is only available if CPU mining is enabled
|
||||||
|
Use 'cpucount' or 'config' first to see if there are any
|
||||||
|
|
||||||
|
gpucount GPUS Count=N| <- the number of GPUs
|
||||||
|
|
||||||
|
pgacount PGAS Count=N| <- the number of PGAs
|
||||||
|
Always returns 0 if PGA mining is disabled
|
||||||
|
|
||||||
|
cpucount CPUS Count=N| <- the number of CPUs
|
||||||
|
Always returns 0 if CPU mining is disabled
|
||||||
|
|
||||||
|
switchpool|N (*)
|
||||||
|
none There is no reply section just the STATUS section
|
||||||
|
stating the results of switching pool N to the
|
||||||
|
highest priority (the pool is also enabled)
|
||||||
|
The Msg includes the pool URL
|
||||||
|
|
||||||
|
enablepool|N (*)
|
||||||
|
none There is no reply section just the STATUS section
|
||||||
|
stating the results of enabling pool N
|
||||||
|
The Msg includes the pool URL
|
||||||
|
|
||||||
|
addpool|URL,USR,PASS (*)
|
||||||
|
none There is no reply section just the STATUS section
|
||||||
|
stating the results of attempting to add pool N
|
||||||
|
The Msg includes the pool URL
|
||||||
|
Use '\\' to get a '\' and '\,' to include a comma
|
||||||
|
inside URL, USR or PASS
|
||||||
|
|
||||||
|
disablepool|N (*)
|
||||||
|
none There is no reply section just the STATUS section
|
||||||
|
stating the results of disabling pool N
|
||||||
|
The Msg includes the pool URL
|
||||||
|
|
||||||
|
removepool|N (*)
|
||||||
|
none There is no reply section just the STATUS section
|
||||||
|
stating the results of removing pool N
|
||||||
|
The Msg includes the pool URL
|
||||||
|
N.B. all details for the pool will be lost
|
||||||
|
|
||||||
|
gpuenable|N (*)
|
||||||
|
none There is no reply section just the STATUS section
|
||||||
|
stating the results of the enable request
|
||||||
|
|
||||||
|
gpudisable|N (*)
|
||||||
|
none There is no reply section just the STATUS section
|
||||||
|
stating the results of the disable request
|
||||||
|
|
||||||
|
gpurestart|N (*)
|
||||||
|
none There is no reply section just the STATUS section
|
||||||
|
stating the results of the restart request
|
||||||
|
|
||||||
|
gpuintensity|N,I (*)
|
||||||
|
none There is no reply section just the STATUS section
|
||||||
|
stating the results of setting GPU N intensity to I
|
||||||
|
|
||||||
|
gpumem|N,V (*)
|
||||||
|
none There is no reply section just the STATUS section
|
||||||
|
stating the results of setting GPU N memoryclock to V MHz
|
||||||
|
|
||||||
|
gpuengine|N,V (*)
|
||||||
|
none There is no reply section just the STATUS section
|
||||||
|
stating the results of setting GPU N clock to V MHz
|
||||||
|
|
||||||
|
gpufan|N,V (*)
|
||||||
|
none There is no reply section just the STATUS section
|
||||||
|
stating the results of setting GPU N fan speed to V%
|
||||||
|
|
||||||
|
gpuvddc|N,V (*)
|
||||||
|
none There is no reply section just the STATUS section
|
||||||
|
stating the results of setting GPU N vddc to V
|
||||||
|
|
||||||
|
save|filename (*)
|
||||||
|
none There is no reply section just the STATUS section
|
||||||
|
stating success or failure saving the cgminer config
|
||||||
|
to filename
|
||||||
|
The filename is optional and will use the cgminer
|
||||||
|
default if not specified
|
||||||
|
|
||||||
|
quit (*) none There is no status section but just a single "BYE"
|
||||||
|
reply before cgminer quits
|
||||||
|
|
||||||
|
notify NOTIFY The last status and history count of each devices problem
|
||||||
|
This lists all devices including those not supported
|
||||||
|
by the 'devs' command
|
||||||
|
e.g. NOTIFY=0,Name=GPU,ID=0,Last Well=1332432290,...|
|
||||||
|
|
||||||
|
privileged (*)
|
||||||
|
none There is no reply section just the STATUS section
|
||||||
|
stating an error if you do not have privileged access
|
||||||
|
to the API and success if you do have privilege
|
||||||
|
The command doesn't change anything in cgminer
|
||||||
|
|
||||||
|
pgaenable|N (*)
|
||||||
|
none There is no reply section just the STATUS section
|
||||||
|
stating the results of the enable request
|
||||||
|
You cannot enable a PGA if it's status is not WELL
|
||||||
|
This is only available if PGA mining is enabled
|
||||||
|
|
||||||
|
pgadisable|N (*)
|
||||||
|
none There is no reply section just the STATUS section
|
||||||
|
stating the results of the disable request
|
||||||
|
This is only available if PGA mining is enabled
|
||||||
|
|
||||||
|
devdetails DEVDETAILS Each device with a list of their static details
|
||||||
|
This lists all devices including those not supported
|
||||||
|
by the 'devs' command
|
||||||
|
e.g. DEVDETAILS=0,Name=GPU,ID=0,Driver=opencl,...|
|
||||||
|
|
||||||
|
restart (*) none There is no status section but just a single "RESTART"
|
||||||
|
reply before cgminer restarts
|
||||||
|
|
||||||
|
stats STATS Each device or pool that has 1 or more getworks
|
||||||
|
with a list of stats regarding getwork times
|
||||||
|
The values returned by stats may change in future
|
||||||
|
versions thus would not normally be displayed
|
||||||
|
Device drivers are also able to add stats to the
|
||||||
|
end of the details returned
|
||||||
|
|
||||||
|
When you enable, disable or restart a GPU or PGA, you will also get Thread messages
|
||||||
|
in the cgminer status window
|
||||||
|
|
||||||
|
When you switch to a different pool to the current one, you will get a
|
||||||
|
'Switching to URL' message in the cgminer status windows
|
||||||
|
|
||||||
|
Obviously, the JSON format is simply just the names as given before the '='
|
||||||
|
with the values after the '='
|
||||||
|
|
||||||
|
If you enable cgminer debug (-D or --debug) you will also get messages showing
|
||||||
|
details of the requests received and the replies
|
||||||
|
|
||||||
|
There are included 4 program examples for accessing the API:
|
||||||
|
|
||||||
|
api-example.php - a php script to access the API
|
||||||
|
usAge: php api-example.php command
|
||||||
|
by default it sends a 'summary' request to the miner at 127.0.0.1:4028
|
||||||
|
If you specify a command it will send that request instead
|
||||||
|
You must modify the line "$socket = getsock('127.0.0.1', 4028);" at the
|
||||||
|
beginning of "function request($cmd)" to change where it looks for cgminer
|
||||||
|
|
||||||
|
API.java/API.class
|
||||||
|
a java program to access the API (with source code)
|
||||||
|
usAge is: java API command address port
|
||||||
|
Any missing or blank parameters are replaced as if you entered:
|
||||||
|
java API summary 127.0.0.1 4028
|
||||||
|
|
||||||
|
api-example.c - a 'C' program to access the API (with source code)
|
||||||
|
usAge: api-example [command [ip/host [port]]]
|
||||||
|
again, as above, missing or blank parameters are replaced as if you entered:
|
||||||
|
api-example summary 127.0.0.1 4028
|
||||||
|
|
||||||
|
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
|
||||||
|
and also to use the option to display a multi-rig summary
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
Feature Changelog for external applications using the API:
|
||||||
|
|
||||||
|
|
||||||
|
API V1.11
|
||||||
|
|
||||||
|
Modified API commands:
|
||||||
|
'save' no longer requires a filename (use default if not specified)
|
||||||
|
|
||||||
|
'save' incorrectly returned status E (error) on success before.
|
||||||
|
It now correctly returns S (success)
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
API V1.10 (cgminer v2.4.1)
|
||||||
|
|
||||||
|
Added API commands:
|
||||||
|
'stats'
|
||||||
|
|
||||||
|
N.B. the 'stats' command can change at any time so any specific content
|
||||||
|
present should not be relied upon.
|
||||||
|
The data content is mainly used for debugging purposes or hidden options
|
||||||
|
in cgminer and can change as development work requires
|
||||||
|
|
||||||
|
Modified API commands:
|
||||||
|
'pools' added "Last Share Time"
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
API V1.9 (cgminer v2.4.0)
|
||||||
|
|
||||||
|
Added API commands:
|
||||||
|
'restart'
|
||||||
|
|
||||||
|
Modified API commands:
|
||||||
|
'notify' corrected invalid JSON
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
API V1.8 (cgminer v2.3.5)
|
||||||
|
|
||||||
|
Added API commands:
|
||||||
|
'devdetails'
|
||||||
|
|
||||||
|
Support for the ZTex FPGA was added
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
API V1.7 (cgminer v2.3.4)
|
||||||
|
|
||||||
|
Added API commands:
|
||||||
|
'removepool'
|
||||||
|
|
||||||
|
Modified API commands:
|
||||||
|
'pools' added "User"
|
||||||
|
|
||||||
|
From API version 1.7 onwards, reply strings in JSON and Text have the
|
||||||
|
necessary escaping as required to avoid ambiguity
|
||||||
|
For JSON the 2 characters '"' and '\' are escaped with a '\' before them
|
||||||
|
For Text the 4 characters '|' ',' '=' and '\' are escaped the same way
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
API V1.6 (cgminer v2.3.2)
|
||||||
|
|
||||||
|
Added API commands:
|
||||||
|
'pga'
|
||||||
|
'pgaenable'
|
||||||
|
'pgadisable'
|
||||||
|
'pgacount'
|
||||||
|
|
||||||
|
Modified API commands:
|
||||||
|
'devs' now includes Icarus and Bitforce FPGA devices
|
||||||
|
'notify' added "*" to the front of the name of all numeric error fields
|
||||||
|
'config' correct "Log Interval" to use numeric (not text) type for JSON
|
||||||
|
|
||||||
|
Support for Icarus and Bitforce FPGAs was added
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
API V1.5 was not released
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
API V1.4 (Kano's interim release of cgminer v2.3.1)
|
||||||
|
|
||||||
|
Added API commands:
|
||||||
|
'notify'
|
||||||
|
|
||||||
|
Modified API commands:
|
||||||
|
'config' added "Device Code" and "OS"
|
||||||
|
|
||||||
|
Added "When" to the STATUS reply section of all commands
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
API V1.3 (cgminer v2.3.1-2)
|
||||||
|
|
||||||
|
Added API commands:
|
||||||
|
'addpool'
|
||||||
|
|
||||||
|
Modified API commands:
|
||||||
|
'devs'/'gpu' added "Total MH" for each device
|
||||||
|
'summary' added "Total MH"
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
API V1.2 (cgminer v2.3.0)
|
||||||
|
|
||||||
|
Added API commands:
|
||||||
|
'enablepool'
|
||||||
|
'disablepool'
|
||||||
|
'privileged'
|
||||||
|
|
||||||
|
Modified API commands:
|
||||||
|
'config' added "Log Interval"
|
||||||
|
|
||||||
|
Starting with API V1.2, any attempt to access a command that requires
|
||||||
|
privileged security, from an IP address that does not have privileged
|
||||||
|
security, will return an "Access denied" Error Status
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
API V1.1 (cgminer v2.2.4)
|
||||||
|
|
||||||
|
There were no changes to the API commands in cgminer v2.2.4,
|
||||||
|
however support was added to cgminer for IP address restrictions
|
||||||
|
with the --api-allow option
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
API V1.1 (cgminer v2.2.2)
|
||||||
|
|
||||||
|
Prior to V1.1, devs/gpu incorrectly reported GPU0 Intensity for all GPUs
|
||||||
|
|
||||||
|
Modified API commands:
|
||||||
|
'devs'/'gpu' added "Last Share Pool" and "Last Share Time" for each device
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
API V1.0 (cgminer v2.2.0)
|
||||||
|
|
||||||
|
Remove default CPU support
|
||||||
|
|
||||||
|
Added API commands:
|
||||||
|
'config'
|
||||||
|
'gpucount'
|
||||||
|
'cpucount'
|
||||||
|
'switchpool'
|
||||||
|
'gpuintensity'
|
||||||
|
'gpumem'
|
||||||
|
'gpuengine'
|
||||||
|
'gpufan'
|
||||||
|
'gpuvddc'
|
||||||
|
'save'
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
API V0.7 (cgminer v2.1.0)
|
||||||
|
|
||||||
|
Initial release of the API in the main cgminer git
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
'version'
|
||||||
|
'devs'
|
||||||
|
'pools'
|
||||||
|
'summary'
|
||||||
|
'gpuenable'
|
||||||
|
'gpudisable'
|
||||||
|
'gpurestart'
|
||||||
|
'gpu'
|
||||||
|
'cpu'
|
||||||
|
'gpucount'
|
||||||
|
'cpucount'
|
||||||
|
'quit'
|
||||||
|
|
56
FPGA-README
Normal file
56
FPGA-README
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
This README contains extended details about FPGA mining with cgminer
|
||||||
|
|
||||||
|
|
||||||
|
Icarus
|
||||||
|
|
||||||
|
There is a hidden option in cgminer when Icarus support is compiled in:
|
||||||
|
|
||||||
|
--icarus-timing <arg> Set how the Icarus timing is calculated - one setting/value for all or comma separated
|
||||||
|
default[=N] Use the default Icarus hash time (2.6316ns)
|
||||||
|
short Calculate the hash time and stop adjusting it at ~315 difficulty 1 shares (~1hr)
|
||||||
|
long Re-calculate the hash time continuously
|
||||||
|
value[=N] Specify the hash time in nanoseconds (e.g. 2.6316) and abort time (e.g. 2.6316=80)
|
||||||
|
|
||||||
|
Icarus timing is required for devices that do not exactly match a default Icarus Rev3 in
|
||||||
|
processing speed
|
||||||
|
If you have an Icarus Rev3 you should not normally need to use --icarus-timing since the
|
||||||
|
default values will maximise the MH/s and display it correctly
|
||||||
|
|
||||||
|
Icarus timing is used to determine the number of hashes that have been checked when it aborts
|
||||||
|
a nonce range (including on a LongPoll)
|
||||||
|
It is also used to determine the elapsed time when it should abort a nonce range to avoid
|
||||||
|
letting the Icarus go idle, but also to safely maximise that time
|
||||||
|
|
||||||
|
'short' or 'long' mode should only be used on a computer that has enough CPU available to run
|
||||||
|
cgminer without any CPU delays (an active desktop or swapping computer would not be stable enough)
|
||||||
|
Any CPU delays while calculating the hash time will affect the result
|
||||||
|
'short' mode only requires the computer to be stable until it has completed ~315 difficulty 1 shares
|
||||||
|
'long' mode requires it to always be stable to ensure accuracy, however, over time it continually
|
||||||
|
corrects itself
|
||||||
|
|
||||||
|
When in 'short' or 'long' mode, it will report the hash time value each time it is re-calculated
|
||||||
|
In 'short' or 'long' mode, the scan abort time starts at 5 seconds and uses the default 2.6316ns
|
||||||
|
scan hash time, for the first 5 nonce's or one minute (whichever is longer)
|
||||||
|
|
||||||
|
In 'default' or 'value' mode the 'constants' are calculated once at the start, based on the default
|
||||||
|
value or the value specified
|
||||||
|
The optional additional =N specifies to set the default abort at N 1/10ths of a second, not the
|
||||||
|
calculated value, which is 112 for 2.6316ns
|
||||||
|
|
||||||
|
To determine the hash time value for a non Icarus Rev3 device or an Icarus Rev3 with a different
|
||||||
|
bitstream to the default one, use 'long' mode and give it at least a few hundred shares, or use
|
||||||
|
'short' mode and take note of the final hash time value (Hs) calculated
|
||||||
|
You can also use the RPC API 'stats' command to see the current hash time (Hs) at any time
|
||||||
|
|
||||||
|
The Icarus code currently only works with a dual FPGA device that supports the same commands as
|
||||||
|
Icarus Rev3 requires and also is less than ~840MH/s and greater than 2MH/s
|
||||||
|
If a dual FPGA device does hash faster than ~840MH/s it should work correctly if you supply the
|
||||||
|
correct hash time nanoseconds value
|
||||||
|
|
||||||
|
The timing code itself will affect the Icarus performance since it increases the delay after
|
||||||
|
work is completed or aborted until it starts again
|
||||||
|
The increase is, however, extremely small and the actual increase is reported with the
|
||||||
|
RPC API 'stats' command (a very slow CPU will make it more noticeable)
|
||||||
|
Using the 'short' mode will remove this delay after 'short' mode completes
|
||||||
|
The delay doesn't affect the calculation of the correct hash time
|
@ -10,7 +10,7 @@ endif
|
|||||||
EXTRA_DIST = example.conf m4/gnulib-cache.m4 linux-usb-cgminer \
|
EXTRA_DIST = example.conf m4/gnulib-cache.m4 linux-usb-cgminer \
|
||||||
ADL_SDK/readme.txt api-example.php miner.php \
|
ADL_SDK/readme.txt api-example.php miner.php \
|
||||||
API.class API.java api-example.c windows-build.txt \
|
API.class API.java api-example.c windows-build.txt \
|
||||||
bitstreams/*
|
bitstreams/* API-README FPGA-README
|
||||||
|
|
||||||
SUBDIRS = lib compat ccan
|
SUBDIRS = lib compat ccan
|
||||||
|
|
||||||
|
28
NEWS
28
NEWS
@ -1,3 +1,31 @@
|
|||||||
|
Version 2.4.2 - June 2, 2012
|
||||||
|
|
||||||
|
- API.class compiled with Java SE 6.0_03 - works with Win7x64
|
||||||
|
- miner.php highlight devs too slow finding shares (possibly failing)
|
||||||
|
- API update version to V1.11 and document changes
|
||||||
|
- API save default config file if none specified
|
||||||
|
- api.c save success incorrectly returns error
|
||||||
|
- api.c replace BUFSIZ (linux/windows have different values)
|
||||||
|
- Move RPC API content out of README to API-README
|
||||||
|
- Open a longpoll connection if a pool is in the REJECTING state as it's the
|
||||||
|
only way to re-enable it automatically.
|
||||||
|
- Use only one longpoll as much as possible by using a pthread conditional
|
||||||
|
broadcast that each longpoll thread waits on and checks if it's the current pool
|
||||||
|
before
|
||||||
|
- If shares are known stale, don't use them to decide to disable a pool for
|
||||||
|
sequential rejects.
|
||||||
|
- Restarting cgminer from within after ADL has been corrupted only leads to a
|
||||||
|
crash. Display a warning only and disable fanspeed monitoring.
|
||||||
|
- Icarus: fix abort calculation/allow user specified abort
|
||||||
|
- Icarus: make --icarus-timing hidden and document it in FPGA-README
|
||||||
|
- Icarus: high accuracy timing and other bitstream speed support
|
||||||
|
- add-MIPSEB-to-icarus-for-BIG_ENDIAN
|
||||||
|
- work_decode only needs swab32 on midstate under BIG ENDIAN
|
||||||
|
- add compile command to api-example.c
|
||||||
|
- save config bugfix: writing an extra ',' when no gpus
|
||||||
|
- Add dpkg-source commits
|
||||||
|
|
||||||
|
|
||||||
Version 2.4.1 - May 6, 2012
|
Version 2.4.1 - May 6, 2012
|
||||||
|
|
||||||
- In the unlikely event of finding a block, display the block solved count with
|
- In the unlikely event of finding a block, display the block solved count with
|
||||||
|
278
README
278
README
@ -209,6 +209,8 @@ FPGA mining boards(BitForce, Icarus, Ztex) only options:
|
|||||||
On windows <arg> is usually of the format \\.\COMn
|
On windows <arg> is usually of the format \\.\COMn
|
||||||
(where n = the correct device number for the FPGA device)
|
(where n = the correct device number for the FPGA device)
|
||||||
|
|
||||||
|
For other FPGA details see the FPGA-README
|
||||||
|
|
||||||
|
|
||||||
CPU only options (deprecated, not included in binaries!):
|
CPU only options (deprecated, not included in binaries!):
|
||||||
|
|
||||||
@ -569,281 +571,7 @@ cgminer shuts down because of this.
|
|||||||
|
|
||||||
RPC API
|
RPC API
|
||||||
|
|
||||||
If you start cgminer with the "--api-listen" option, it will listen on a
|
For RPC API details see the API-README file
|
||||||
simple TCP/IP socket for single string API requests from the same machine
|
|
||||||
running cgminer and reply with a string and then close the socket each time
|
|
||||||
If you add the "--api-network" option, it will accept API requests from any
|
|
||||||
network attached computer.
|
|
||||||
|
|
||||||
You can only access the comands that reply with data in this mode.
|
|
||||||
By default, you cannot access any privileged command that affects the miner -
|
|
||||||
you will receive an access denied status message see --api-allow below.
|
|
||||||
|
|
||||||
You can specify IP addresses/prefixes that are only allowed to access the API
|
|
||||||
with the "--api-allow" option e.g. --api-allow W:192.168.0.1,10.0.0/24
|
|
||||||
will allow 192.168.0.1 or any address matching 10.0.0.*, but nothing else
|
|
||||||
IP addresses are automatically padded with extra '.0's as needed
|
|
||||||
Without a /prefix is the same as specifying /32
|
|
||||||
0/0 means all IP addresses.
|
|
||||||
The 'W:' on the front gives that address/subnet privileged access to commands
|
|
||||||
that modify cgminer.
|
|
||||||
Without it those commands return an access denied status.
|
|
||||||
Privileged access is checked in the order the IP addresses were supplied to
|
|
||||||
"--api-allow"
|
|
||||||
The first match determines the privilege level.
|
|
||||||
Using the "--api-allow" option overides the "--api-network" option if they
|
|
||||||
are both specified
|
|
||||||
With "--api-allow", 127.0.0.1 is not by default given access unless specified
|
|
||||||
|
|
||||||
The RPC API request can be either simple text or JSON.
|
|
||||||
|
|
||||||
If the request is JSON (starts with '{'), it will reply with a JSON formatted
|
|
||||||
response, otherwise it replies with text formatted as described further below.
|
|
||||||
|
|
||||||
The JSON request format required is '{"command":"CMD","parameter":"PARAM"}'
|
|
||||||
(though of course parameter is not required for all requests)
|
|
||||||
where "CMD" is from the "Request" column below and "PARAM" would be e.g.
|
|
||||||
the CPU/GPU number if required.
|
|
||||||
|
|
||||||
An example request in both formats to set GPU 0 fan to 80%:
|
|
||||||
gpufan|0,80
|
|
||||||
{"command":"gpufan","parameter":"0,80"}
|
|
||||||
|
|
||||||
The format of each reply (unless stated otherwise) is a STATUS section
|
|
||||||
followed by an optional detail section
|
|
||||||
|
|
||||||
From API version 1.7 onwards, reply strings in JSON and Text have the
|
|
||||||
necessary escaping as required to avoid ambiguity - they didn't before 1.7
|
|
||||||
For JSON the 2 characters '"' and '\' are escaped with a '\' before them
|
|
||||||
For Text the 4 characters '|' ',' '=' and '\' are escaped the same way
|
|
||||||
|
|
||||||
Only user entered information will contain characters that require being
|
|
||||||
escaped, such as Pool URL, User and Password or the Config save filename,
|
|
||||||
when they are returned in messages or as their values by the API
|
|
||||||
|
|
||||||
For API version 1.4 and later:
|
|
||||||
|
|
||||||
The STATUS section is:
|
|
||||||
|
|
||||||
STATUS=X,When=NNN,Code=N,Msg=string,Description=string|
|
|
||||||
|
|
||||||
STATUS=X Where X is one of:
|
|
||||||
W - Warning
|
|
||||||
I - Informational
|
|
||||||
S - Success
|
|
||||||
E - Error
|
|
||||||
F - Fatal (code bug)
|
|
||||||
|
|
||||||
When=NNN
|
|
||||||
Standard long time of request in seconds
|
|
||||||
|
|
||||||
Code=N
|
|
||||||
Each unique reply has a unigue Code (See api.c - #define MSG_NNNNNN)
|
|
||||||
|
|
||||||
Msg=string
|
|
||||||
Message matching the Code value N
|
|
||||||
|
|
||||||
Description=string
|
|
||||||
This defaults to the cgminer version but is the value of --api-description
|
|
||||||
if it was specified at runtime.
|
|
||||||
|
|
||||||
For API version 1.9:
|
|
||||||
|
|
||||||
The list of requests - a (*) means it requires privileged access - and replies are:
|
|
||||||
|
|
||||||
Request Reply Section Details
|
|
||||||
------- ------------- -------
|
|
||||||
version VERSION CGMiner=cgminer version
|
|
||||||
API=API version
|
|
||||||
|
|
||||||
config CONFIG Some miner configuration information:
|
|
||||||
GPU Count=N, <- the number of GPUs
|
|
||||||
PGA Count=N, <- the number of PGAs
|
|
||||||
CPU Count=N, <- the number of CPUs
|
|
||||||
Pool Count=N, <- the number of Pools
|
|
||||||
ADL=X, <- Y or N if ADL is compiled in the code
|
|
||||||
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
|
|
||||||
|
|
||||||
summary SUMMARY The status summary of the miner
|
|
||||||
e.g. Elapsed=NNN,Found Blocks=N,Getworks=N,...|
|
|
||||||
|
|
||||||
pools POOLS The status of each pool
|
|
||||||
e.g. Pool=0,URL=http://pool.com:6311,Status=Alive,...|
|
|
||||||
|
|
||||||
devs DEVS Each available GPU, PGA and CPU with their details
|
|
||||||
e.g. GPU=0,Accepted=NN,MHS av=NNN,...,Intensity=D|
|
|
||||||
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)
|
|
||||||
Will not report PGAs if PGA mining is disabled
|
|
||||||
Will not report CPUs if CPU mining is disabled
|
|
||||||
|
|
||||||
gpu|N GPU The details of a single GPU number N in the same
|
|
||||||
format and details as for DEVS
|
|
||||||
|
|
||||||
pga|N PGA The details of a single PGA number N in the same
|
|
||||||
format and details as for DEVS
|
|
||||||
This is only available if PGA mining is enabled
|
|
||||||
Use 'pgacount' or 'config' first to see if there are any
|
|
||||||
|
|
||||||
cpu|N CPU The details of a single CPU number N in the same
|
|
||||||
format and details as for DEVS
|
|
||||||
This is only available if CPU mining is enabled
|
|
||||||
Use 'cpucount' or 'config' first to see if there are any
|
|
||||||
|
|
||||||
gpucount GPUS Count=N| <- the number of GPUs
|
|
||||||
|
|
||||||
pgacount PGAS Count=N| <- the number of PGAs
|
|
||||||
Always returns 0 if PGA mining is disabled
|
|
||||||
|
|
||||||
cpucount CPUS Count=N| <- the number of CPUs
|
|
||||||
Always returns 0 if CPU mining is disabled
|
|
||||||
|
|
||||||
switchpool|N (*)
|
|
||||||
none There is no reply section just the STATUS section
|
|
||||||
stating the results of switching pool N to the
|
|
||||||
highest priority (the pool is also enabled)
|
|
||||||
The Msg includes the pool URL
|
|
||||||
|
|
||||||
enablepool|N (*)
|
|
||||||
none There is no reply section just the STATUS section
|
|
||||||
stating the results of enabling pool N
|
|
||||||
The Msg includes the pool URL
|
|
||||||
|
|
||||||
addpool|URL,USR,PASS (*)
|
|
||||||
none There is no reply section just the STATUS section
|
|
||||||
stating the results of attempting to add pool N
|
|
||||||
The Msg includes the pool URL
|
|
||||||
Use '\\' to get a '\' and '\,' to include a comma
|
|
||||||
inside URL, USR or PASS
|
|
||||||
|
|
||||||
disablepool|N (*)
|
|
||||||
none There is no reply section just the STATUS section
|
|
||||||
stating the results of disabling pool N
|
|
||||||
The Msg includes the pool URL
|
|
||||||
|
|
||||||
removepool|N (*)
|
|
||||||
none There is no reply section just the STATUS section
|
|
||||||
stating the results of removing pool N
|
|
||||||
The Msg includes the pool URL
|
|
||||||
N.B. all details for the pool will be lost
|
|
||||||
|
|
||||||
gpuenable|N (*)
|
|
||||||
none There is no reply section just the STATUS section
|
|
||||||
stating the results of the enable request
|
|
||||||
|
|
||||||
gpudisable|N (*)
|
|
||||||
none There is no reply section just the STATUS section
|
|
||||||
stating the results of the disable request
|
|
||||||
|
|
||||||
gpurestart|N (*)
|
|
||||||
none There is no reply section just the STATUS section
|
|
||||||
stating the results of the restart request
|
|
||||||
|
|
||||||
gpuintensity|N,I (*)
|
|
||||||
none There is no reply section just the STATUS section
|
|
||||||
stating the results of setting GPU N intensity to I
|
|
||||||
|
|
||||||
gpumem|N,V (*)
|
|
||||||
none There is no reply section just the STATUS section
|
|
||||||
stating the results of setting GPU N memoryclock to V MHz
|
|
||||||
|
|
||||||
gpuengine|N,V (*)
|
|
||||||
none There is no reply section just the STATUS section
|
|
||||||
stating the results of setting GPU N clock to V MHz
|
|
||||||
|
|
||||||
gpufan|N,V (*)
|
|
||||||
none There is no reply section just the STATUS section
|
|
||||||
stating the results of setting GPU N fan speed to V%
|
|
||||||
|
|
||||||
gpuvddc|N,V (*)
|
|
||||||
none There is no reply section just the STATUS section
|
|
||||||
stating the results of setting GPU N vddc to V
|
|
||||||
|
|
||||||
save|filename (*)
|
|
||||||
none There is no reply section just the STATUS section
|
|
||||||
stating success or failure saving the cgminer config
|
|
||||||
to filename
|
|
||||||
|
|
||||||
quit (*) none There is no status section but just a single "BYE"
|
|
||||||
reply before cgminer quits
|
|
||||||
|
|
||||||
notify NOTIFY The last status and history count of each devices problem
|
|
||||||
This lists all devices including those not supported
|
|
||||||
by the 'devs' command
|
|
||||||
e.g. NOTIFY=0,Name=GPU,ID=0,Last Well=1332432290,...|
|
|
||||||
|
|
||||||
privileged (*)
|
|
||||||
none There is no reply section just the STATUS section
|
|
||||||
stating an error if you do not have privileged access
|
|
||||||
to the API and success if you do have privilege
|
|
||||||
The command doesn't change anything in cgminer
|
|
||||||
|
|
||||||
pgaenable|N (*)
|
|
||||||
none There is no reply section just the STATUS section
|
|
||||||
stating the results of the enable request
|
|
||||||
You cannot enable a PGA if it's status is not WELL
|
|
||||||
This is only available if PGA mining is enabled
|
|
||||||
|
|
||||||
pgadisable|N (*)
|
|
||||||
none There is no reply section just the STATUS section
|
|
||||||
stating the results of the disable request
|
|
||||||
This is only available if PGA mining is enabled
|
|
||||||
|
|
||||||
devdetails DEVDETAILS Each device with a list of their static details
|
|
||||||
This lists all devices including those not supported
|
|
||||||
by the 'devs' command
|
|
||||||
e.g. DEVDETAILS=0,Name=GPU,ID=0,Driver=opencl,...|
|
|
||||||
|
|
||||||
restart (*) none There is no status section but just a single "RESTART"
|
|
||||||
reply before cgminer restarts
|
|
||||||
|
|
||||||
stats STATS Each device or pool that has 1 or more getworks
|
|
||||||
with a list of stats regarding getwork times
|
|
||||||
The values returned by stats may change in future
|
|
||||||
versions thus would not normally be displayed
|
|
||||||
Device drivers are also able to add stats to the
|
|
||||||
end of the details returned
|
|
||||||
|
|
||||||
When you enable, disable or restart a GPU or PGA, you will also get Thread messages
|
|
||||||
in the cgminer status window
|
|
||||||
|
|
||||||
When you switch to a different pool to the current one, you will get a
|
|
||||||
'Switching to URL' message in the cgminer status windows
|
|
||||||
|
|
||||||
Obviously, the JSON format is simply just the names as given before the '='
|
|
||||||
with the values after the '='
|
|
||||||
|
|
||||||
If you enable cgminer debug (-D or --debug) you will also get messages showing
|
|
||||||
details of the requests received and the replies
|
|
||||||
|
|
||||||
There are included 4 program examples for accessing the API:
|
|
||||||
|
|
||||||
api-example.php - a php script to access the API
|
|
||||||
usAge: php api-example.php command
|
|
||||||
by default it sends a 'summary' request to the miner at 127.0.0.1:4028
|
|
||||||
If you specify a command it will send that request instead
|
|
||||||
You must modify the line "$socket = getsock('127.0.0.1', 4028);" at the
|
|
||||||
beginning of "function request($cmd)" to change where it looks for cgminer
|
|
||||||
|
|
||||||
API.java/API.class
|
|
||||||
a java program to access the API (with source code)
|
|
||||||
usAge is: java API command address port
|
|
||||||
Any missing or blank parameters are replaced as if you entered:
|
|
||||||
java API summary 127.0.0.1 4028
|
|
||||||
|
|
||||||
api-example.c - a 'C' program to access the API (with source code)
|
|
||||||
usAge: api-example [command [ip/host [port]]]
|
|
||||||
again, as above, missing or blank parameters are replaced as if you entered:
|
|
||||||
api-example summary 127.0.0.1 4028
|
|
||||||
|
|
||||||
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
|
|
||||||
and also to use the option to display a multi-rig summary
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
6
adl.c
6
adl.c
@ -692,11 +692,7 @@ int gpu_fanpercent(int gpu)
|
|||||||
unlock_adl();
|
unlock_adl();
|
||||||
if (unlikely(ga->has_fanspeed && ret == -1)) {
|
if (unlikely(ga->has_fanspeed && ret == -1)) {
|
||||||
applog(LOG_WARNING, "GPU %d stopped reporting fanspeed due to driver corruption", gpu);
|
applog(LOG_WARNING, "GPU %d stopped reporting fanspeed due to driver corruption", gpu);
|
||||||
if (opt_restart) {
|
applog(LOG_WARNING, "You will need to start cgminer from scratch to correct this");
|
||||||
applog(LOG_WARNING, "Restart enabled, will restart cgminer");
|
|
||||||
applog(LOG_WARNING, "You can disable this with the --no-restart option");
|
|
||||||
app_restart();
|
|
||||||
}
|
|
||||||
applog(LOG_WARNING, "Disabling fanspeed monitoring on this device");
|
applog(LOG_WARNING, "Disabling fanspeed monitoring on this device");
|
||||||
ga->has_fanspeed = false;
|
ga->has_fanspeed = false;
|
||||||
}
|
}
|
||||||
|
42
api.c
42
api.c
@ -142,6 +142,9 @@
|
|||||||
// Current code assumes it can socket send this size also
|
// Current code assumes it can socket send this size also
|
||||||
#define MYBUFSIZ 65432 // TODO: intercept before it's exceeded
|
#define MYBUFSIZ 65432 // TODO: intercept before it's exceeded
|
||||||
|
|
||||||
|
// BUFSIZ varies on Windows and Linux
|
||||||
|
#define TMPBUFSIZ 8192
|
||||||
|
|
||||||
// Number of requests to queue - normally would be small
|
// Number of requests to queue - normally would be small
|
||||||
// However lots of PGA's may mean more
|
// However lots of PGA's may mean more
|
||||||
#define QUEUE 100
|
#define QUEUE 100
|
||||||
@ -158,7 +161,7 @@ static const char SEPARATOR = '|';
|
|||||||
#define SEPSTR "|"
|
#define SEPSTR "|"
|
||||||
static const char GPUSEP = ',';
|
static const char GPUSEP = ',';
|
||||||
|
|
||||||
static const char *APIVERSION = "1.10";
|
static const char *APIVERSION = "1.11";
|
||||||
static const char *DEAD = "Dead";
|
static const char *DEAD = "Dead";
|
||||||
static const char *SICK = "Sick";
|
static const char *SICK = "Sick";
|
||||||
static const char *NOSTART = "NoStart";
|
static const char *NOSTART = "NoStart";
|
||||||
@ -462,7 +465,7 @@ struct CODES {
|
|||||||
{ SEVERITY_SUCC, MSG_GPUFAN, PARAM_BOTH, "Setting GPU %d fan to (%s) reported succeess" },
|
{ SEVERITY_SUCC, MSG_GPUFAN, PARAM_BOTH, "Setting GPU %d fan to (%s) reported succeess" },
|
||||||
{ SEVERITY_ERR, MSG_MISFN, PARAM_NONE, "Missing save filename parameter" },
|
{ SEVERITY_ERR, MSG_MISFN, PARAM_NONE, "Missing save filename parameter" },
|
||||||
{ SEVERITY_ERR, MSG_BADFN, PARAM_STR, "Can't open or create save file '%s'" },
|
{ SEVERITY_ERR, MSG_BADFN, PARAM_STR, "Can't open or create save file '%s'" },
|
||||||
{ SEVERITY_ERR, MSG_SAVED, PARAM_STR, "Configuration saved to file '%s'" },
|
{ SEVERITY_SUCC, MSG_SAVED, PARAM_STR, "Configuration saved to file '%s'" },
|
||||||
{ SEVERITY_ERR, MSG_ACCDENY, PARAM_STR, "Access denied to '%s' command" },
|
{ SEVERITY_ERR, MSG_ACCDENY, PARAM_STR, "Access denied to '%s' command" },
|
||||||
{ SEVERITY_SUCC, MSG_ACCOK, PARAM_NONE, "Privileged access OK" },
|
{ SEVERITY_SUCC, MSG_ACCOK, PARAM_NONE, "Privileged access OK" },
|
||||||
{ SEVERITY_SUCC, MSG_ENAPOOL, PARAM_POOL, "Enabling pool %d:'%s'" },
|
{ SEVERITY_SUCC, MSG_ENAPOOL, PARAM_POOL, "Enabling pool %d:'%s'" },
|
||||||
@ -763,7 +766,7 @@ static void apiversion(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
|
|||||||
|
|
||||||
static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
||||||
{
|
{
|
||||||
char buf[BUFSIZ];
|
char buf[TMPBUFSIZ];
|
||||||
int pgacount = 0;
|
int pgacount = 0;
|
||||||
int cpucount = 0;
|
int cpucount = 0;
|
||||||
char *adlinuse = (char *)NO;
|
char *adlinuse = (char *)NO;
|
||||||
@ -804,7 +807,7 @@ static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
|
|||||||
static void gpustatus(int gpu, bool isjson)
|
static void gpustatus(int gpu, bool isjson)
|
||||||
{
|
{
|
||||||
char intensity[20];
|
char intensity[20];
|
||||||
char buf[BUFSIZ];
|
char buf[TMPBUFSIZ];
|
||||||
char *enabled;
|
char *enabled;
|
||||||
char *status;
|
char *status;
|
||||||
float gt, gv;
|
float gt, gv;
|
||||||
@ -856,7 +859,7 @@ static void gpustatus(int gpu, bool isjson)
|
|||||||
#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
|
#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
|
||||||
static void pgastatus(int pga, bool isjson)
|
static void pgastatus(int pga, bool isjson)
|
||||||
{
|
{
|
||||||
char buf[BUFSIZ];
|
char buf[TMPBUFSIZ];
|
||||||
char *enabled;
|
char *enabled;
|
||||||
char *status;
|
char *status;
|
||||||
int numpga = numpgas();
|
int numpga = numpgas();
|
||||||
@ -908,7 +911,7 @@ static void pgastatus(int pga, bool isjson)
|
|||||||
#ifdef WANT_CPUMINE
|
#ifdef WANT_CPUMINE
|
||||||
static void cpustatus(int cpu, bool isjson)
|
static void cpustatus(int cpu, bool isjson)
|
||||||
{
|
{
|
||||||
char buf[BUFSIZ];
|
char buf[TMPBUFSIZ];
|
||||||
|
|
||||||
if (opt_n_threads > 0 && cpu >= 0 && cpu < num_processors) {
|
if (opt_n_threads > 0 && cpu >= 0 && cpu < num_processors) {
|
||||||
struct cgpu_info *cgpu = &cpus[cpu];
|
struct cgpu_info *cgpu = &cpus[cpu];
|
||||||
@ -1188,7 +1191,7 @@ static void cpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|||||||
|
|
||||||
static void poolstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
static void poolstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
||||||
{
|
{
|
||||||
char buf[BUFSIZ];
|
char buf[TMPBUFSIZ];
|
||||||
char *status, *lp;
|
char *status, *lp;
|
||||||
char *rpc_url;
|
char *rpc_url;
|
||||||
char *rpc_user;
|
char *rpc_user;
|
||||||
@ -1400,7 +1403,7 @@ static void gpurestart(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|||||||
|
|
||||||
static void gpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
static void gpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
||||||
{
|
{
|
||||||
char buf[BUFSIZ];
|
char buf[TMPBUFSIZ];
|
||||||
|
|
||||||
strcpy(io_buffer, message(MSG_NUMGPU, 0, NULL, isjson));
|
strcpy(io_buffer, message(MSG_NUMGPU, 0, NULL, isjson));
|
||||||
|
|
||||||
@ -1414,7 +1417,7 @@ static void gpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo
|
|||||||
|
|
||||||
static void pgacount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
static void pgacount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
||||||
{
|
{
|
||||||
char buf[BUFSIZ];
|
char buf[TMPBUFSIZ];
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
|
#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
|
||||||
@ -1433,7 +1436,7 @@ static void pgacount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo
|
|||||||
|
|
||||||
static void cpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
static void cpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
||||||
{
|
{
|
||||||
char buf[BUFSIZ];
|
char buf[TMPBUFSIZ];
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
#ifdef WANT_CPUMINE
|
#ifdef WANT_CPUMINE
|
||||||
@ -1863,7 +1866,7 @@ void privileged(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool is
|
|||||||
|
|
||||||
void notifystatus(int device, struct cgpu_info *cgpu, bool isjson)
|
void notifystatus(int device, struct cgpu_info *cgpu, bool isjson)
|
||||||
{
|
{
|
||||||
char buf[BUFSIZ];
|
char buf[TMPBUFSIZ];
|
||||||
char *reason;
|
char *reason;
|
||||||
|
|
||||||
if (cgpu->device_last_not_well == 0)
|
if (cgpu->device_last_not_well == 0)
|
||||||
@ -1940,7 +1943,7 @@ static void notify(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool
|
|||||||
|
|
||||||
static void devdetails(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
static void devdetails(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
||||||
{
|
{
|
||||||
char buf[BUFSIZ];
|
char buf[TMPBUFSIZ];
|
||||||
struct cgpu_info *cgpu;
|
struct cgpu_info *cgpu;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -1976,12 +1979,13 @@ static void devdetails(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
|
|||||||
|
|
||||||
void dosave(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
void dosave(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
||||||
{
|
{
|
||||||
|
char filename[PATH_MAX];
|
||||||
FILE *fcfg;
|
FILE *fcfg;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
|
||||||
if (param == NULL || *param == '\0') {
|
if (param == NULL || *param == '\0') {
|
||||||
strcpy(io_buffer, message(MSG_MISFN, 0, NULL, isjson));
|
default_save_file(filename);
|
||||||
return;
|
param = filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
fcfg = fopen(param, "w");
|
fcfg = fopen(param, "w");
|
||||||
@ -2006,7 +2010,7 @@ void dosave(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
|
|||||||
|
|
||||||
static int itemstats(int i, char *id, struct cgminer_stats *stats, char *extra, bool isjson)
|
static int itemstats(int i, char *id, struct cgminer_stats *stats, char *extra, bool isjson)
|
||||||
{
|
{
|
||||||
char buf[BUFSIZ];
|
char buf[TMPBUFSIZ];
|
||||||
|
|
||||||
if (stats->getwork_calls || (extra != NULL && *extra))
|
if (stats->getwork_calls || (extra != NULL && *extra))
|
||||||
{
|
{
|
||||||
@ -2032,7 +2036,7 @@ static int itemstats(int i, char *id, struct cgminer_stats *stats, char *extra,
|
|||||||
}
|
}
|
||||||
static void minerstats(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
static void minerstats(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
||||||
{
|
{
|
||||||
char extra[BUFSIZ];
|
char extra[TMPBUFSIZ];
|
||||||
char id[20];
|
char id[20];
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
@ -2300,8 +2304,8 @@ static void *restart_thread(__maybe_unused void *userdata)
|
|||||||
void api(int api_thr_id)
|
void api(int api_thr_id)
|
||||||
{
|
{
|
||||||
struct thr_info bye_thr;
|
struct thr_info bye_thr;
|
||||||
char buf[BUFSIZ];
|
char buf[TMPBUFSIZ];
|
||||||
char param_buf[BUFSIZ];
|
char param_buf[TMPBUFSIZ];
|
||||||
const char *localaddr = "127.0.0.1";
|
const char *localaddr = "127.0.0.1";
|
||||||
SOCKETTYPE c;
|
SOCKETTYPE c;
|
||||||
int n, bound;
|
int n, bound;
|
||||||
@ -2434,7 +2438,7 @@ void api(int api_thr_id)
|
|||||||
applog(LOG_DEBUG, "API: connection from %s - %s", connectaddr, addrok ? "Accepted" : "Ignored");
|
applog(LOG_DEBUG, "API: connection from %s - %s", connectaddr, addrok ? "Accepted" : "Ignored");
|
||||||
|
|
||||||
if (addrok) {
|
if (addrok) {
|
||||||
n = recv(c, &buf[0], BUFSIZ-1, 0);
|
n = recv(c, &buf[0], TMPBUFSIZ-1, 0);
|
||||||
if (SOCKETFAIL(n))
|
if (SOCKETFAIL(n))
|
||||||
buf[0] = '\0';
|
buf[0] = '\0';
|
||||||
else
|
else
|
||||||
|
85
cgminer.c
85
cgminer.c
@ -134,6 +134,7 @@ bool opt_api_listen;
|
|||||||
bool opt_api_network;
|
bool opt_api_network;
|
||||||
bool opt_delaynet;
|
bool opt_delaynet;
|
||||||
bool opt_disable_pool = true;
|
bool opt_disable_pool = true;
|
||||||
|
char *opt_icarus_timing = NULL;
|
||||||
|
|
||||||
char *opt_kernel_path;
|
char *opt_kernel_path;
|
||||||
char *cgminer_path;
|
char *cgminer_path;
|
||||||
@ -165,6 +166,9 @@ static pthread_rwlock_t blk_lock;
|
|||||||
|
|
||||||
pthread_rwlock_t netacc_lock;
|
pthread_rwlock_t netacc_lock;
|
||||||
|
|
||||||
|
static pthread_mutex_t lp_lock;
|
||||||
|
static pthread_cond_t lp_cond;
|
||||||
|
|
||||||
double total_mhashes_done;
|
double total_mhashes_done;
|
||||||
static struct timeval total_tv_start, total_tv_end;
|
static struct timeval total_tv_start, total_tv_end;
|
||||||
|
|
||||||
@ -675,6 +679,15 @@ static char *set_api_description(const char *arg)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_ICARUS
|
||||||
|
static char *set_icarus_timing(const char *arg)
|
||||||
|
{
|
||||||
|
opt_set_charp(arg, &opt_icarus_timing);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* These options are available from config file or commandline */
|
/* These options are available from config file or commandline */
|
||||||
static struct opt_table opt_config_table[] = {
|
static struct opt_table opt_config_table[] = {
|
||||||
#ifdef WANT_CPUMINE
|
#ifdef WANT_CPUMINE
|
||||||
@ -811,6 +824,11 @@ static struct opt_table opt_config_table[] = {
|
|||||||
OPT_WITH_ARG("--kernel|-k",
|
OPT_WITH_ARG("--kernel|-k",
|
||||||
set_kernel, NULL, NULL,
|
set_kernel, NULL, NULL,
|
||||||
"Override kernel to use (diablo, poclbm, phatk or diakgcn) - one value or comma separated"),
|
"Override kernel to use (diablo, poclbm, phatk or diakgcn) - one value or comma separated"),
|
||||||
|
#endif
|
||||||
|
#ifdef USE_ICARUS
|
||||||
|
OPT_WITH_ARG("--icarus-timing",
|
||||||
|
set_icarus_timing, NULL, NULL,
|
||||||
|
opt_hidden),
|
||||||
#endif
|
#endif
|
||||||
OPT_WITHOUT_ARG("--load-balance",
|
OPT_WITHOUT_ARG("--load-balance",
|
||||||
set_loadbalance, &pool_strategy,
|
set_loadbalance, &pool_strategy,
|
||||||
@ -1718,8 +1736,10 @@ static bool submit_upstream_work(const struct work *work, CURL *curl)
|
|||||||
/* Once we have more than a nominal amount of sequential rejects,
|
/* Once we have more than a nominal amount of sequential rejects,
|
||||||
* at least 10 and more than 3 mins at the current utility,
|
* at least 10 and more than 3 mins at the current utility,
|
||||||
* disable the pool because some pool error is likely to have
|
* disable the pool because some pool error is likely to have
|
||||||
* ensued. */
|
* ensued. Do not do this if we know the share just happened to
|
||||||
if (pool->seq_rejects > 10 && opt_disable_pool && total_pools > 1) {
|
* be stale due to networking delays.
|
||||||
|
*/
|
||||||
|
if (pool->seq_rejects > 10 && !work->stale && opt_disable_pool && total_pools > 1) {
|
||||||
double utility = total_accepted / ( total_secs ? total_secs : 1 ) * 60;
|
double utility = total_accepted / ( total_secs ? total_secs : 1 ) * 60;
|
||||||
|
|
||||||
if (pool->seq_rejects > utility * 3) {
|
if (pool->seq_rejects > utility * 3) {
|
||||||
@ -2154,6 +2174,7 @@ static void *submit_work_thread(void *userdata)
|
|||||||
pool->stale_shares++;
|
pool->stale_shares++;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
work->stale = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ce = pop_curl_entry(pool);
|
ce = pop_curl_entry(pool);
|
||||||
@ -2280,6 +2301,10 @@ void switch_pools(struct pool *selected)
|
|||||||
mutex_lock(&qd_lock);
|
mutex_lock(&qd_lock);
|
||||||
total_queued = 0;
|
total_queued = 0;
|
||||||
mutex_unlock(&qd_lock);
|
mutex_unlock(&qd_lock);
|
||||||
|
|
||||||
|
mutex_lock(&lp_lock);
|
||||||
|
pthread_cond_broadcast(&lp_cond);
|
||||||
|
mutex_unlock(&lp_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void discard_work(struct work *work)
|
static void discard_work(struct work *work)
|
||||||
@ -2766,6 +2791,8 @@ void write_config(FILE *fcfg)
|
|||||||
fprintf(fcfg, ",\n\"api-allow\" : \"%s\"", opt_api_allow);
|
fprintf(fcfg, ",\n\"api-allow\" : \"%s\"", opt_api_allow);
|
||||||
if (strcmp(opt_api_description, PACKAGE_STRING) != 0)
|
if (strcmp(opt_api_description, PACKAGE_STRING) != 0)
|
||||||
fprintf(fcfg, ",\n\"api-description\" : \"%s\"", opt_api_description);
|
fprintf(fcfg, ",\n\"api-description\" : \"%s\"", opt_api_description);
|
||||||
|
if (opt_icarus_timing)
|
||||||
|
fprintf(fcfg, ",\n\"icarus-timing\" : \"%s\"", opt_icarus_timing);
|
||||||
fputs("\n}", fcfg);
|
fputs("\n}", fcfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2986,6 +3013,23 @@ retry:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void default_save_file(char *filename)
|
||||||
|
{
|
||||||
|
#if defined(unix)
|
||||||
|
if (getenv("HOME") && *getenv("HOME")) {
|
||||||
|
strcpy(filename, getenv("HOME"));
|
||||||
|
strcat(filename, "/");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
strcpy(filename, "");
|
||||||
|
strcat(filename, ".cgminer/");
|
||||||
|
mkdir(filename, 0777);
|
||||||
|
#else
|
||||||
|
strcpy(filename, "");
|
||||||
|
#endif
|
||||||
|
strcat(filename, def_conf);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_CURSES
|
#ifdef HAVE_CURSES
|
||||||
static void set_options(void)
|
static void set_options(void)
|
||||||
{
|
{
|
||||||
@ -3046,19 +3090,7 @@ retry:
|
|||||||
FILE *fcfg;
|
FILE *fcfg;
|
||||||
char *str, filename[PATH_MAX], prompt[PATH_MAX + 50];
|
char *str, filename[PATH_MAX], prompt[PATH_MAX + 50];
|
||||||
|
|
||||||
#if defined(unix)
|
default_save_file(filename);
|
||||||
if (getenv("HOME") && *getenv("HOME")) {
|
|
||||||
strcpy(filename, getenv("HOME"));
|
|
||||||
strcat(filename, "/");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
strcpy(filename, "");
|
|
||||||
strcat(filename, ".cgminer/");
|
|
||||||
mkdir(filename, 0777);
|
|
||||||
#else
|
|
||||||
strcpy(filename, "");
|
|
||||||
#endif
|
|
||||||
strcat(filename, def_conf);
|
|
||||||
sprintf(prompt, "Config filename to write (Enter for default) [%s]", filename);
|
sprintf(prompt, "Config filename to write (Enter for default) [%s]", filename);
|
||||||
str = curses_input(prompt);
|
str = curses_input(prompt);
|
||||||
if (strcmp(str, "-1")) {
|
if (strcmp(str, "-1")) {
|
||||||
@ -3997,6 +4029,21 @@ static struct pool *select_longpoll_pool(struct pool *cp)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This will make the longpoll thread wait till it's the current pool, or it
|
||||||
|
* has been flagged as rejecting, before attempting to open any connections.
|
||||||
|
*/
|
||||||
|
static void wait_lpcurrent(struct pool *pool)
|
||||||
|
{
|
||||||
|
if (pool->enabled == POOL_REJECTING)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (pool != current_pool()) {
|
||||||
|
mutex_lock(&lp_lock);
|
||||||
|
pthread_cond_wait(&lp_cond, &lp_lock);
|
||||||
|
mutex_unlock(&lp_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void *longpoll_thread(void *userdata)
|
static void *longpoll_thread(void *userdata)
|
||||||
{
|
{
|
||||||
struct pool *cp = (struct pool *)userdata;
|
struct pool *cp = (struct pool *)userdata;
|
||||||
@ -4027,6 +4074,8 @@ retry_pool:
|
|||||||
/* Any longpoll from any pool is enough for this to be true */
|
/* Any longpoll from any pool is enough for this to be true */
|
||||||
have_longpoll = true;
|
have_longpoll = true;
|
||||||
|
|
||||||
|
wait_lpcurrent(cp);
|
||||||
|
|
||||||
if (cp == pool)
|
if (cp == pool)
|
||||||
applog(LOG_WARNING, "Long-polling activated for %s", pool->lp_url);
|
applog(LOG_WARNING, "Long-polling activated for %s", pool->lp_url);
|
||||||
else
|
else
|
||||||
@ -4035,6 +4084,8 @@ retry_pool:
|
|||||||
while (42) {
|
while (42) {
|
||||||
json_t *val, *soval;
|
json_t *val, *soval;
|
||||||
|
|
||||||
|
wait_lpcurrent(cp);
|
||||||
|
|
||||||
gettimeofday(&start, NULL);
|
gettimeofday(&start, NULL);
|
||||||
|
|
||||||
/* Longpoll connections can be persistent for a very long time
|
/* Longpoll connections can be persistent for a very long time
|
||||||
@ -4730,6 +4781,10 @@ int main(int argc, char *argv[])
|
|||||||
rwlock_init(&blk_lock);
|
rwlock_init(&blk_lock);
|
||||||
rwlock_init(&netacc_lock);
|
rwlock_init(&netacc_lock);
|
||||||
|
|
||||||
|
mutex_init(&lp_lock);
|
||||||
|
if (unlikely(pthread_cond_init(&lp_cond, NULL)))
|
||||||
|
quit(1, "Failed to pthread_cond_init lp_cond");
|
||||||
|
|
||||||
sprintf(packagename, "%s %s", PACKAGE, VERSION);
|
sprintf(packagename, "%s %s", PACKAGE, VERSION);
|
||||||
|
|
||||||
#ifdef WANT_CPUMINE
|
#ifdef WANT_CPUMINE
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
|
##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
|
||||||
m4_define([v_maj], [2])
|
m4_define([v_maj], [2])
|
||||||
m4_define([v_min], [4])
|
m4_define([v_min], [4])
|
||||||
m4_define([v_mic], [1])
|
m4_define([v_mic], [2])
|
||||||
##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
|
##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
|
||||||
m4_define([v_ver], [v_maj.v_min.v_mic])
|
m4_define([v_ver], [v_maj.v_min.v_mic])
|
||||||
m4_define([lt_rev], m4_eval(v_maj + v_min))
|
m4_define([lt_rev], m4_eval(v_maj + v_min))
|
||||||
|
30
debian/changelog
vendored
30
debian/changelog
vendored
@ -1,3 +1,33 @@
|
|||||||
|
cgminer (2.4.2-1) stable; urgency=medium
|
||||||
|
Version 2.4.2 - June 2, 2012
|
||||||
|
|
||||||
|
- API.class compiled with Java SE 6.0_03 - works with Win7x64
|
||||||
|
- miner.php highlight devs too slow finding shares (possibly failing)
|
||||||
|
- API update version to V1.11 and document changes
|
||||||
|
- API save default config file if none specified
|
||||||
|
- api.c save success incorrectly returns error
|
||||||
|
- api.c replace BUFSIZ (linux/windows have different values)
|
||||||
|
- Move RPC API content out of README to API-README
|
||||||
|
- Open a longpoll connection if a pool is in the REJECTING state as it's the
|
||||||
|
only way to re-enable it automatically.
|
||||||
|
- Use only one longpoll as much as possible by using a pthread conditional
|
||||||
|
broadcast that each longpoll thread waits on and checks if it's the current pool
|
||||||
|
before
|
||||||
|
- If shares are known stale, don't use them to decide to disable a pool for
|
||||||
|
sequential rejects.
|
||||||
|
- Restarting cgminer from within after ADL has been corrupted only leads to a
|
||||||
|
crash. Display a warning only and disable fanspeed monitoring.
|
||||||
|
- Icarus: fix abort calculation/allow user specified abort
|
||||||
|
- Icarus: make --icarus-timing hidden and document it in FPGA-README
|
||||||
|
- Icarus: high accuracy timing and other bitstream speed support
|
||||||
|
- add-MIPSEB-to-icarus-for-BIG_ENDIAN
|
||||||
|
- work_decode only needs swab32 on midstate under BIG ENDIAN
|
||||||
|
- add compile command to api-example.c
|
||||||
|
- save config bugfix: writing an extra ',' when no gpus
|
||||||
|
- Add dpkg-source commits
|
||||||
|
|
||||||
|
-- nushor <nushor11@gmail.com> Sun, 03 Jun 2012 22:02:03 -0500
|
||||||
|
|
||||||
cgminer (2.4.1-1) stable; urgency=low
|
cgminer (2.4.1-1) stable; urgency=low
|
||||||
Version 2.4.1-1 - May 6, 2012
|
Version 2.4.1-1 - May 6, 2012
|
||||||
- In the unlikely event of finding a block, display the block solved count with
|
- In the unlikely event of finding a block, display the block solved count with
|
||||||
|
1
debian/patches/series
vendored
1
debian/patches/series
vendored
@ -1 +0,0 @@
|
|||||||
v2.4.1
|
|
64422
debian/patches/v2.4.2
vendored
Normal file
64422
debian/patches/v2.4.2
vendored
Normal file
File diff suppressed because it is too large
Load Diff
518
driver-icarus.c
518
driver-icarus.c
@ -51,17 +51,136 @@
|
|||||||
#include "elist.h"
|
#include "elist.h"
|
||||||
#include "miner.h"
|
#include "miner.h"
|
||||||
|
|
||||||
// This is valid for a standard Icarus Rev 3
|
// The serial I/O speed - Linux uses a define 'B115200' in bits/termios.h
|
||||||
// Assuming each hash pair takes 5.26ns then a whole nonce range would take 11.3s
|
#define ICARUS_IO_SPEED 115200
|
||||||
// Giving a little leaway 11.1s would be best
|
|
||||||
//#define ICARUS_READ_COUNT_DEFAULT 111
|
|
||||||
#define ICARUS_READ_COUNT_DEFAULT 80
|
|
||||||
|
|
||||||
// 2 x 11.1 / (5.26 x 10^-9)
|
// The size of a successful nonce read
|
||||||
//#define ESTIMATE_HASHES 0xFB90365E
|
#define ICARUS_READ_SIZE 4
|
||||||
|
|
||||||
// This is the 8s value
|
// Ensure the sizes are correct for the Serial read
|
||||||
#define ESTIMATE_HASHES 0xB54E9147
|
#if (ICARUS_READ_SIZE != 4)
|
||||||
|
#error ICARUS_READ_SIZE must be 4
|
||||||
|
#endif
|
||||||
|
#define ASSERT1(condition) __maybe_unused static char sizeof_uint32_t_must_be_4[(condition)?1:-1]
|
||||||
|
ASSERT1(sizeof(uint32_t) == 4);
|
||||||
|
|
||||||
|
#define ICARUS_READ_TIME ((double)ICARUS_READ_SIZE * (double)8.0 / (double)ICARUS_IO_SPEED)
|
||||||
|
|
||||||
|
// Fraction of a second, USB timeout is measured in
|
||||||
|
// i.e. 10 means 1/10 of a second
|
||||||
|
#define TIME_FACTOR 10
|
||||||
|
// In Linux it's 10 per second, thus value = 10/TIME_FACTOR =
|
||||||
|
#define LINUX_TIMEOUT_VALUE 1
|
||||||
|
// In Windows it's 1000 per second, thus value = 1000/TIME_FACTOR =
|
||||||
|
#define WINDOWS_TIMEOUT_VALUE 100
|
||||||
|
|
||||||
|
// In timing mode: Default starting value until an estimate can be obtained
|
||||||
|
// 5 seconds allows for up to a ~840MH/s device
|
||||||
|
#define ICARUS_READ_COUNT_TIMING (5 * TIME_FACTOR)
|
||||||
|
|
||||||
|
// For a standard Icarus REV3 (to 5 places)
|
||||||
|
// Since this rounds up a the last digit - it is a slight overestimate
|
||||||
|
// Thus the hash rate will be a VERY slight underestimate
|
||||||
|
// (by a lot less than the displayed accuracy)
|
||||||
|
#define ICARUS_REV3_HASH_TIME 0.0000000026316
|
||||||
|
#define NANOSEC 1000000000.0
|
||||||
|
|
||||||
|
// Icarus Rev3 doesn't send a completion message when it finishes
|
||||||
|
// the full nonce range, so to avoid being idle we must abort the
|
||||||
|
// work (by starting a new work) shortly before it finishes
|
||||||
|
//
|
||||||
|
// Thus we need to estimate 2 things:
|
||||||
|
// 1) How many hashes were done if the work was aborted
|
||||||
|
// 2) How high can the timeout be before the Icarus is idle,
|
||||||
|
// to minimise the number of work started
|
||||||
|
// We set 2) to 'the calculated estimate' - 1
|
||||||
|
// to ensure the estimate ends before idle
|
||||||
|
//
|
||||||
|
// The simple calculation used is:
|
||||||
|
// Tn = Total time in seconds to calculate n hashes
|
||||||
|
// Hs = seconds per hash
|
||||||
|
// Xn = number of hashes
|
||||||
|
// W = code overhead per work
|
||||||
|
//
|
||||||
|
// Rough but reasonable estimate:
|
||||||
|
// Tn = Hs * Xn + W (of the form y = mx + b)
|
||||||
|
//
|
||||||
|
// Thus:
|
||||||
|
// Line of best fit (using least squares)
|
||||||
|
//
|
||||||
|
// Hs = (n*Sum(XiTi)-Sum(Xi)*Sum(Ti))/(n*Sum(Xi^2)-Sum(Xi)^2)
|
||||||
|
// W = Sum(Ti)/n - (Hs*Sum(Xi))/n
|
||||||
|
//
|
||||||
|
// N.B. W is less when aborting work since we aren't waiting for the reply
|
||||||
|
// to be transferred back (ICARUS_READ_TIME)
|
||||||
|
// Calculating the hashes aborted at n seconds is thus just n/Hs
|
||||||
|
// (though this is still a slight overestimate due to code delays)
|
||||||
|
//
|
||||||
|
|
||||||
|
// Both below must be exceeded to complete a set of data
|
||||||
|
// Minimum how long after the first, the last data point must be
|
||||||
|
#define HISTORY_SEC 60
|
||||||
|
// Minimum how many points a single ICARUS_HISTORY should have
|
||||||
|
#define MIN_DATA_COUNT 5
|
||||||
|
// The value above used is doubled each history until it exceeds:
|
||||||
|
#define MAX_MIN_DATA_COUNT 100
|
||||||
|
|
||||||
|
static struct timeval history_sec = { HISTORY_SEC, 0 };
|
||||||
|
|
||||||
|
// Store the last INFO_HISTORY data sets
|
||||||
|
// [0] = current data, not yet ready to be included as an estimate
|
||||||
|
// Each new data set throws the last old set off the end thus
|
||||||
|
// keeping a ongoing average of recent data
|
||||||
|
#define INFO_HISTORY 10
|
||||||
|
|
||||||
|
struct ICARUS_HISTORY {
|
||||||
|
struct timeval finish;
|
||||||
|
double sumXiTi;
|
||||||
|
double sumXi;
|
||||||
|
double sumTi;
|
||||||
|
double sumXi2;
|
||||||
|
uint32_t values;
|
||||||
|
uint32_t hash_count_min;
|
||||||
|
uint32_t hash_count_max;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum timing_mode { MODE_DEFAULT, MODE_SHORT, MODE_LONG, MODE_VALUE };
|
||||||
|
|
||||||
|
static const char *MODE_DEFAULT_STR = "default";
|
||||||
|
static const char *MODE_SHORT_STR = "short";
|
||||||
|
static const char *MODE_LONG_STR = "long";
|
||||||
|
static const char *MODE_VALUE_STR = "value";
|
||||||
|
static const char *MODE_UNKNOWN_STR = "unknown";
|
||||||
|
|
||||||
|
struct ICARUS_INFO {
|
||||||
|
// time to calculate the golden_ob
|
||||||
|
uint64_t golden_hashes;
|
||||||
|
struct timeval golden_tv;
|
||||||
|
|
||||||
|
struct ICARUS_HISTORY history[INFO_HISTORY+1];
|
||||||
|
uint32_t min_data_count;
|
||||||
|
|
||||||
|
// seconds per Hash
|
||||||
|
double Hs;
|
||||||
|
int read_count;
|
||||||
|
|
||||||
|
enum timing_mode timing_mode;
|
||||||
|
bool do_icarus_timing;
|
||||||
|
|
||||||
|
double fullnonce;
|
||||||
|
int count;
|
||||||
|
double W;
|
||||||
|
uint32_t values;
|
||||||
|
uint64_t hash_count_range;
|
||||||
|
|
||||||
|
// Determine the cost of history processing
|
||||||
|
// (which will only affect W)
|
||||||
|
uint64_t history_count;
|
||||||
|
struct timeval history_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
// One for each possible device
|
||||||
|
static struct ICARUS_INFO *icarus_info[MAX_DEVICES];
|
||||||
|
|
||||||
struct device_api icarus_api;
|
struct device_api icarus_api;
|
||||||
|
|
||||||
@ -98,7 +217,7 @@ static int icarus_open(const char *devpath)
|
|||||||
ISTRIP | INLCR | IGNCR | ICRNL | IXON);
|
ISTRIP | INLCR | IGNCR | ICRNL | IXON);
|
||||||
my_termios.c_oflag &= ~OPOST;
|
my_termios.c_oflag &= ~OPOST;
|
||||||
my_termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
my_termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
||||||
my_termios.c_cc[VTIME] = 1; /* block 0.1 second */
|
my_termios.c_cc[VTIME] = LINUX_TIMEOUT_VALUE; /* how long to block */
|
||||||
my_termios.c_cc[VMIN] = 0;
|
my_termios.c_cc[VMIN] = 0;
|
||||||
tcsetattr(serialfd, TCSANOW, &my_termios);
|
tcsetattr(serialfd, TCSANOW, &my_termios);
|
||||||
|
|
||||||
@ -119,7 +238,7 @@ static int icarus_open(const char *devpath)
|
|||||||
comCfg.dwSize = sizeof(COMMCONFIG);
|
comCfg.dwSize = sizeof(COMMCONFIG);
|
||||||
comCfg.wVersion = 1;
|
comCfg.wVersion = 1;
|
||||||
comCfg.dcb.DCBlength = sizeof(DCB);
|
comCfg.dcb.DCBlength = sizeof(DCB);
|
||||||
comCfg.dcb.BaudRate = 115200;
|
comCfg.dcb.BaudRate = ICARUS_IO_SPEED;
|
||||||
comCfg.dcb.fBinary = 1;
|
comCfg.dcb.fBinary = 1;
|
||||||
comCfg.dcb.fDtrControl = DTR_CONTROL_ENABLE;
|
comCfg.dcb.fDtrControl = DTR_CONTROL_ENABLE;
|
||||||
comCfg.dcb.fRtsControl = RTS_CONTROL_ENABLE;
|
comCfg.dcb.fRtsControl = RTS_CONTROL_ENABLE;
|
||||||
@ -127,42 +246,57 @@ static int icarus_open(const char *devpath)
|
|||||||
|
|
||||||
SetCommConfig(hSerial, &comCfg, sizeof(comCfg));
|
SetCommConfig(hSerial, &comCfg, sizeof(comCfg));
|
||||||
|
|
||||||
// block 0.1 second
|
// How long to block
|
||||||
COMMTIMEOUTS cto = {100, 0, 100, 0, 100};
|
COMMTIMEOUTS cto = {WINDOWS_TIMEOUT_VALUE, 0, WINDOWS_TIMEOUT_VALUE, 0, WINDOWS_TIMEOUT_VALUE};
|
||||||
SetCommTimeouts(hSerial, &cto);
|
SetCommTimeouts(hSerial, &cto);
|
||||||
|
|
||||||
return _open_osfhandle((LONG)hSerial, 0);
|
return _open_osfhandle((LONG)hSerial, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int icarus_gets(unsigned char *buf, size_t bufLen, int fd, int thr_id, int read_count)
|
static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, int thr_id, int read_count)
|
||||||
{
|
{
|
||||||
ssize_t ret = 0;
|
ssize_t ret = 0;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
int read_amount = ICARUS_READ_SIZE;
|
||||||
|
bool first = true;
|
||||||
|
|
||||||
while (bufLen) {
|
// Read reply 1 byte at a time to get earliest tv_finish
|
||||||
|
while (true) {
|
||||||
ret = read(fd, buf, 1);
|
ret = read(fd, buf, 1);
|
||||||
if (ret == 1) {
|
|
||||||
bufLen--;
|
if (first)
|
||||||
buf++;
|
gettimeofday(tv_finish, NULL);
|
||||||
|
|
||||||
|
if (ret >= read_amount)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (ret > 0) {
|
||||||
|
buf += ret;
|
||||||
|
read_amount -= ret;
|
||||||
|
first = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc++;
|
rc++;
|
||||||
if (rc >= read_count) {
|
if (rc >= read_count) {
|
||||||
applog(LOG_DEBUG,
|
if (opt_debug) {
|
||||||
"Icarus Read: No data in %.2f seconds", (float)(rc/10.0f));
|
applog(LOG_DEBUG,
|
||||||
|
"Icarus Read: No data in %.2f seconds",
|
||||||
|
(float)rc/(float)TIME_FACTOR);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thr_id >= 0 && work_restart[thr_id].restart) {
|
if (thr_id >= 0 && work_restart[thr_id].restart) {
|
||||||
applog(LOG_DEBUG,
|
if (opt_debug) {
|
||||||
"Icarus Read: Work restart at %.2f seconds", (float)(rc/10.0f));
|
applog(LOG_DEBUG,
|
||||||
|
"Icarus Read: Work restart at %.2f seconds",
|
||||||
|
(float)(rc)/(float)TIME_FACTOR);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int icarus_write(int fd, const void *buf, size_t bufLen)
|
static int icarus_write(int fd, const void *buf, size_t bufLen)
|
||||||
@ -178,8 +312,110 @@ static int icarus_write(int fd, const void *buf, size_t bufLen)
|
|||||||
|
|
||||||
#define icarus_close(fd) close(fd)
|
#define icarus_close(fd) close(fd)
|
||||||
|
|
||||||
|
static const char *timing_mode_str(enum timing_mode timing_mode)
|
||||||
|
{
|
||||||
|
switch(timing_mode) {
|
||||||
|
case MODE_DEFAULT:
|
||||||
|
return MODE_DEFAULT_STR;
|
||||||
|
case MODE_SHORT:
|
||||||
|
return MODE_SHORT_STR;
|
||||||
|
case MODE_LONG:
|
||||||
|
return MODE_LONG_STR;
|
||||||
|
case MODE_VALUE:
|
||||||
|
return MODE_VALUE_STR;
|
||||||
|
default:
|
||||||
|
return MODE_UNKNOWN_STR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_timing_mode(struct cgpu_info *icarus)
|
||||||
|
{
|
||||||
|
struct ICARUS_INFO *info = icarus_info[icarus->device_id];
|
||||||
|
double Hs;
|
||||||
|
char buf[BUFSIZ+1];
|
||||||
|
char *ptr, *comma, *eq;
|
||||||
|
size_t max;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (opt_icarus_timing == NULL)
|
||||||
|
buf[0] = '\0';
|
||||||
|
else {
|
||||||
|
ptr = opt_icarus_timing;
|
||||||
|
for (i = 0; i < icarus->device_id; i++) {
|
||||||
|
comma = strchr(ptr, ',');
|
||||||
|
if (comma == NULL)
|
||||||
|
break;
|
||||||
|
ptr = comma + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
comma = strchr(ptr, ',');
|
||||||
|
if (comma == NULL)
|
||||||
|
max = strlen(ptr);
|
||||||
|
else
|
||||||
|
max = comma - ptr;
|
||||||
|
|
||||||
|
if (max > BUFSIZ)
|
||||||
|
max = BUFSIZ;
|
||||||
|
strncpy(buf, ptr, max);
|
||||||
|
buf[max] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
info->Hs = 0;
|
||||||
|
info->read_count = 0;
|
||||||
|
|
||||||
|
if (strcasecmp(buf, MODE_SHORT_STR) == 0) {
|
||||||
|
info->Hs = ICARUS_REV3_HASH_TIME;
|
||||||
|
info->read_count = ICARUS_READ_COUNT_TIMING;
|
||||||
|
|
||||||
|
info->timing_mode = MODE_SHORT;
|
||||||
|
info->do_icarus_timing = true;
|
||||||
|
} else if (strcasecmp(buf, MODE_LONG_STR) == 0) {
|
||||||
|
info->Hs = ICARUS_REV3_HASH_TIME;
|
||||||
|
info->read_count = ICARUS_READ_COUNT_TIMING;
|
||||||
|
|
||||||
|
info->timing_mode = MODE_LONG;
|
||||||
|
info->do_icarus_timing = true;
|
||||||
|
} else if ((Hs = atof(buf)) != 0) {
|
||||||
|
info->Hs = Hs / NANOSEC;
|
||||||
|
info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
|
||||||
|
|
||||||
|
if ((eq = strchr(buf, '=')) != NULL)
|
||||||
|
info->read_count = atoi(eq+1);
|
||||||
|
|
||||||
|
if (info->read_count < 1)
|
||||||
|
info->read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
|
||||||
|
|
||||||
|
if (unlikely(info->read_count < 1))
|
||||||
|
info->read_count = 1;
|
||||||
|
|
||||||
|
info->timing_mode = MODE_VALUE;
|
||||||
|
info->do_icarus_timing = false;
|
||||||
|
} else {
|
||||||
|
// Anything else in buf just uses DEFAULT mode
|
||||||
|
|
||||||
|
info->Hs = ICARUS_REV3_HASH_TIME;
|
||||||
|
info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
|
||||||
|
|
||||||
|
if ((eq = strchr(buf, '=')) != NULL)
|
||||||
|
info->read_count = atoi(eq+1);
|
||||||
|
|
||||||
|
if (info->read_count < 1)
|
||||||
|
info->read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
|
||||||
|
|
||||||
|
info->timing_mode = MODE_DEFAULT;
|
||||||
|
info->do_icarus_timing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->min_data_count = MIN_DATA_COUNT;
|
||||||
|
|
||||||
|
applog(LOG_DEBUG, "Icarus: Init: %d mode=%s read_count=%d Hs=%e",
|
||||||
|
icarus->device_id, timing_mode_str(info->timing_mode), info->read_count, info->Hs);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static bool icarus_detect_one(const char *devpath)
|
static bool icarus_detect_one(const char *devpath)
|
||||||
{
|
{
|
||||||
|
struct ICARUS_INFO *info;
|
||||||
struct timeval tv_start, tv_finish;
|
struct timeval tv_start, tv_finish;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
@ -194,8 +430,9 @@ static bool icarus_detect_one(const char *devpath)
|
|||||||
"0000000087320b1a1426674f2fa722ce";
|
"0000000087320b1a1426674f2fa722ce";
|
||||||
|
|
||||||
const char golden_nonce[] = "000187a2";
|
const char golden_nonce[] = "000187a2";
|
||||||
|
const uint32_t golden_nonce_val = 0x000187a2;
|
||||||
|
|
||||||
unsigned char ob_bin[64], nonce_bin[4];
|
unsigned char ob_bin[64], nonce_bin[ICARUS_READ_SIZE];
|
||||||
char *nonce_hex;
|
char *nonce_hex;
|
||||||
|
|
||||||
if (total_devices == MAX_DEVICES)
|
if (total_devices == MAX_DEVICES)
|
||||||
@ -212,8 +449,7 @@ static bool icarus_detect_one(const char *devpath)
|
|||||||
gettimeofday(&tv_start, NULL);
|
gettimeofday(&tv_start, NULL);
|
||||||
|
|
||||||
memset(nonce_bin, 0, sizeof(nonce_bin));
|
memset(nonce_bin, 0, sizeof(nonce_bin));
|
||||||
icarus_gets(nonce_bin, sizeof(nonce_bin), fd, -1, 1);
|
icarus_gets(nonce_bin, fd, &tv_finish, -1, 1);
|
||||||
gettimeofday(&tv_finish, NULL);
|
|
||||||
|
|
||||||
icarus_close(fd);
|
icarus_close(fd);
|
||||||
|
|
||||||
@ -221,16 +457,16 @@ static bool icarus_detect_one(const char *devpath)
|
|||||||
if (nonce_hex) {
|
if (nonce_hex) {
|
||||||
if (strncmp(nonce_hex, golden_nonce, 8)) {
|
if (strncmp(nonce_hex, golden_nonce, 8)) {
|
||||||
applog(LOG_ERR,
|
applog(LOG_ERR,
|
||||||
"Icarus Detect: "
|
"Icarus Detect: "
|
||||||
"Test failed at %s: get %s, should: %s",
|
"Test failed at %s: get %s, should: %s",
|
||||||
devpath, nonce_hex, golden_nonce);
|
devpath, nonce_hex, golden_nonce);
|
||||||
free(nonce_hex);
|
free(nonce_hex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
applog(LOG_DEBUG,
|
applog(LOG_DEBUG,
|
||||||
"Icarus Detect: "
|
"Icarus Detect: "
|
||||||
"Test succeeded at %s: got %s",
|
"Test succeeded at %s: got %s",
|
||||||
devpath, nonce_hex);
|
devpath, nonce_hex);
|
||||||
free(nonce_hex);
|
free(nonce_hex);
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
@ -244,7 +480,23 @@ static bool icarus_detect_one(const char *devpath)
|
|||||||
add_cgpu(icarus);
|
add_cgpu(icarus);
|
||||||
|
|
||||||
applog(LOG_INFO, "Found Icarus at %s, mark as %d",
|
applog(LOG_INFO, "Found Icarus at %s, mark as %d",
|
||||||
devpath, icarus->device_id);
|
devpath, icarus->device_id);
|
||||||
|
|
||||||
|
if (icarus_info[icarus->device_id] == NULL) {
|
||||||
|
icarus_info[icarus->device_id] = (struct ICARUS_INFO *)malloc(sizeof(struct ICARUS_INFO));
|
||||||
|
if (unlikely(!(icarus_info[icarus->device_id])))
|
||||||
|
quit(1, "Failed to malloc ICARUS_INFO");
|
||||||
|
}
|
||||||
|
|
||||||
|
info = icarus_info[icarus->device_id];
|
||||||
|
|
||||||
|
// Initialise everything to zero for a new device
|
||||||
|
memset(info, 0, sizeof(struct ICARUS_INFO));
|
||||||
|
|
||||||
|
info->golden_hashes = (golden_nonce_val & 0x7fffffff) << 1;
|
||||||
|
timersub(&tv_finish, &tv_start, &(info->golden_tv));
|
||||||
|
|
||||||
|
set_timing_mode(icarus);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -295,11 +547,24 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
|
|||||||
int fd;
|
int fd;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
unsigned char ob_bin[64], nonce_bin[4];
|
struct ICARUS_INFO *info;
|
||||||
char *ob_hex, *nonce_hex;
|
|
||||||
|
unsigned char ob_bin[64], nonce_bin[ICARUS_READ_SIZE];
|
||||||
|
char *ob_hex;
|
||||||
uint32_t nonce;
|
uint32_t nonce;
|
||||||
uint32_t hash_count;
|
uint64_t hash_count;
|
||||||
struct timeval tv_start, tv_finish, elapsed;
|
struct timeval tv_start, tv_finish, elapsed;
|
||||||
|
struct timeval tv_history_start, tv_history_finish;
|
||||||
|
double Ti, Xi;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
struct ICARUS_HISTORY *history0, *history;
|
||||||
|
int count;
|
||||||
|
double Hs, W, fullnonce;
|
||||||
|
int read_count;
|
||||||
|
uint64_t estimate_hashes;
|
||||||
|
uint32_t values;
|
||||||
|
uint64_t hash_count_range;
|
||||||
|
|
||||||
elapsed.tv_sec = elapsed.tv_usec = 0;
|
elapsed.tv_sec = elapsed.tv_usec = 0;
|
||||||
|
|
||||||
@ -315,39 +580,49 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
|
|||||||
tcflush(fd, TCOFLUSH);
|
tcflush(fd, TCOFLUSH);
|
||||||
#endif
|
#endif
|
||||||
ret = icarus_write(fd, ob_bin, sizeof(ob_bin));
|
ret = icarus_write(fd, ob_bin, sizeof(ob_bin));
|
||||||
if (opt_debug)
|
|
||||||
gettimeofday(&tv_start, NULL);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return 0; /* This should never happen */
|
return 0; /* This should never happen */
|
||||||
|
|
||||||
|
gettimeofday(&tv_start, NULL);
|
||||||
|
|
||||||
if (opt_debug) {
|
if (opt_debug) {
|
||||||
ob_hex = bin2hex(ob_bin, sizeof(ob_bin));
|
ob_hex = bin2hex(ob_bin, sizeof(ob_bin));
|
||||||
if (ob_hex) {
|
if (ob_hex) {
|
||||||
applog(LOG_DEBUG, "Icarus %d sent: %s",
|
applog(LOG_DEBUG, "Icarus %d sent: %s",
|
||||||
icarus->device_id, ob_hex);
|
icarus->device_id, ob_hex);
|
||||||
free(ob_hex);
|
free(ob_hex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Icarus will return 4 bytes nonces or nothing */
|
/* Icarus will return 4 bytes (ICARUS_READ_SIZE) nonces or nothing */
|
||||||
memset(nonce_bin, 0, sizeof(nonce_bin));
|
memset(nonce_bin, 0, sizeof(nonce_bin));
|
||||||
ret = icarus_gets(nonce_bin, sizeof(nonce_bin), fd, thr_id,
|
info = icarus_info[icarus->device_id];
|
||||||
ICARUS_READ_COUNT_DEFAULT);
|
ret = icarus_gets(nonce_bin, fd, &tv_finish, thr_id, info->read_count);
|
||||||
|
|
||||||
if (opt_debug)
|
|
||||||
gettimeofday(&tv_finish, NULL);
|
|
||||||
|
|
||||||
work->blk.nonce = 0xffffffff;
|
work->blk.nonce = 0xffffffff;
|
||||||
memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin));
|
memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin));
|
||||||
|
|
||||||
// aborted before becoming idle, get new work
|
// aborted before becoming idle, get new work
|
||||||
if (nonce == 0 && ret) {
|
if (nonce == 0 && ret) {
|
||||||
|
timersub(&tv_finish, &tv_start, &elapsed);
|
||||||
|
|
||||||
|
// ONLY up to just when it aborted
|
||||||
|
// We didn't read a reply so we don't subtract ICARUS_READ_TIME
|
||||||
|
estimate_hashes = ((double)(elapsed.tv_sec)
|
||||||
|
+ ((double)(elapsed.tv_usec))/((double)1000000)) / info->Hs;
|
||||||
|
|
||||||
|
// If some Serial-USB delay allowed the full nonce range to
|
||||||
|
// complete it can't have done more than a full nonce
|
||||||
|
if (unlikely(estimate_hashes > 0xffffffff))
|
||||||
|
estimate_hashes = 0xffffffff;
|
||||||
|
|
||||||
if (opt_debug) {
|
if (opt_debug) {
|
||||||
timersub(&tv_finish, &tv_start, &elapsed);
|
applog(LOG_DEBUG, "Icarus %d no nonce = 0x%08llx hashes (%ld.%06lds)",
|
||||||
applog(LOG_DEBUG, "Icarus %d no nonce = 0x%08x hashes (%ld.%06lds)",
|
icarus->device_id, estimate_hashes,
|
||||||
icarus->device_id, ESTIMATE_HASHES, elapsed.tv_sec, elapsed.tv_usec);
|
elapsed.tv_sec, elapsed.tv_usec);
|
||||||
}
|
}
|
||||||
return ESTIMATE_HASHES;
|
|
||||||
|
return estimate_hashes;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined (__BIG_ENDIAN__) && !defined(MIPSEB)
|
#if !defined (__BIG_ENDIAN__) && !defined(MIPSEB)
|
||||||
@ -356,28 +631,136 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
|
|||||||
|
|
||||||
submit_nonce(thr, work, nonce);
|
submit_nonce(thr, work, nonce);
|
||||||
|
|
||||||
if (opt_debug) {
|
|
||||||
timersub(&tv_finish, &tv_start, &elapsed);
|
|
||||||
|
|
||||||
nonce_hex = bin2hex(nonce_bin, sizeof(nonce_bin));
|
|
||||||
if (nonce_hex) {
|
|
||||||
applog(LOG_DEBUG, "Icarus %d returned (elapsed %ld.%06ld seconds): %s",
|
|
||||||
icarus->device_id, elapsed.tv_sec, elapsed.tv_usec, nonce_hex);
|
|
||||||
free(nonce_hex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hash_count = (nonce & 0x7fffffff);
|
hash_count = (nonce & 0x7fffffff);
|
||||||
if (hash_count++ == 0x7fffffff)
|
if (hash_count++ == 0x7fffffff)
|
||||||
hash_count = 0xffffffff;
|
hash_count = 0xffffffff;
|
||||||
else
|
else
|
||||||
hash_count <<= 1;
|
hash_count <<= 1;
|
||||||
|
|
||||||
if (opt_debug)
|
if (opt_debug || info->do_icarus_timing)
|
||||||
applog(LOG_DEBUG, "Icarus %d nonce = 0x%08x = 0x%08x hashes (%ld.%06lds)",
|
timersub(&tv_finish, &tv_start, &elapsed);
|
||||||
icarus->device_id, nonce, hash_count, elapsed.tv_sec, elapsed.tv_usec);
|
|
||||||
|
|
||||||
return hash_count;
|
if (opt_debug) {
|
||||||
|
applog(LOG_DEBUG, "Icarus %d nonce = 0x%08x = 0x%08llx hashes (%ld.%06lds)",
|
||||||
|
icarus->device_id, nonce, hash_count, elapsed.tv_sec, elapsed.tv_usec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore possible end condition values
|
||||||
|
if (info->do_icarus_timing && (nonce & 0x7fffffff) > 0x000fffff && (nonce & 0x7fffffff) < 0x7ff00000) {
|
||||||
|
gettimeofday(&tv_history_start, NULL);
|
||||||
|
|
||||||
|
history0 = &(info->history[0]);
|
||||||
|
|
||||||
|
if (history0->values == 0)
|
||||||
|
timeradd(&tv_start, &history_sec, &(history0->finish));
|
||||||
|
|
||||||
|
Ti = (double)(elapsed.tv_sec)
|
||||||
|
+ ((double)(elapsed.tv_usec))/((double)1000000)
|
||||||
|
- ICARUS_READ_TIME;
|
||||||
|
Xi = (double)hash_count;
|
||||||
|
history0->sumXiTi += Xi * Ti;
|
||||||
|
history0->sumXi += Xi;
|
||||||
|
history0->sumTi += Ti;
|
||||||
|
history0->sumXi2 += Xi * Xi;
|
||||||
|
|
||||||
|
history0->values++;
|
||||||
|
|
||||||
|
if (history0->hash_count_max < hash_count)
|
||||||
|
history0->hash_count_max = hash_count;
|
||||||
|
if (history0->hash_count_min > hash_count || history0->hash_count_min == 0)
|
||||||
|
history0->hash_count_min = hash_count;
|
||||||
|
|
||||||
|
if (history0->values >= info->min_data_count
|
||||||
|
&& timercmp(&tv_start, &(history0->finish), >)) {
|
||||||
|
for (i = INFO_HISTORY; i > 0; i--)
|
||||||
|
memcpy(&(info->history[i]),
|
||||||
|
&(info->history[i-1]),
|
||||||
|
sizeof(struct ICARUS_HISTORY));
|
||||||
|
|
||||||
|
// Initialise history0 to zero for summary calculation
|
||||||
|
memset(history0, 0, sizeof(struct ICARUS_HISTORY));
|
||||||
|
|
||||||
|
// We just completed a history data set
|
||||||
|
// So now recalc read_count based on the whole history thus we will
|
||||||
|
// initially get more accurate until it completes INFO_HISTORY
|
||||||
|
// total data sets
|
||||||
|
count = 0;
|
||||||
|
for (i = 1 ; i <= INFO_HISTORY; i++) {
|
||||||
|
history = &(info->history[i]);
|
||||||
|
if (history->values >= MIN_DATA_COUNT) {
|
||||||
|
count++;
|
||||||
|
|
||||||
|
history0->sumXiTi += history->sumXiTi;
|
||||||
|
history0->sumXi += history->sumXi;
|
||||||
|
history0->sumTi += history->sumTi;
|
||||||
|
history0->sumXi2 += history->sumXi2;
|
||||||
|
history0->values += history->values;
|
||||||
|
|
||||||
|
if (history0->hash_count_max < history->hash_count_max)
|
||||||
|
history0->hash_count_max = history->hash_count_max;
|
||||||
|
if (history0->hash_count_min > history->hash_count_min || history0->hash_count_min == 0)
|
||||||
|
history0->hash_count_min = history->hash_count_min;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All history data
|
||||||
|
Hs = (history0->values*history0->sumXiTi - history0->sumXi*history0->sumTi)
|
||||||
|
/ (history0->values*history0->sumXi2 - history0->sumXi*history0->sumXi);
|
||||||
|
W = history0->sumTi/history0->values - Hs*history0->sumXi/history0->values;
|
||||||
|
hash_count_range = history0->hash_count_max - history0->hash_count_min;
|
||||||
|
values = history0->values;
|
||||||
|
|
||||||
|
// Initialise history0 to zero for next data set
|
||||||
|
memset(history0, 0, sizeof(struct ICARUS_HISTORY));
|
||||||
|
|
||||||
|
fullnonce = W + Hs * (((double)0xffffffff) + 1);
|
||||||
|
read_count = (int)(fullnonce * TIME_FACTOR) - 1;
|
||||||
|
|
||||||
|
info->Hs = Hs;
|
||||||
|
info->read_count = read_count;
|
||||||
|
|
||||||
|
info->fullnonce = fullnonce;
|
||||||
|
info->count = count;
|
||||||
|
info->W = W;
|
||||||
|
info->values = values;
|
||||||
|
info->hash_count_range = hash_count_range;
|
||||||
|
|
||||||
|
if (info->min_data_count < MAX_MIN_DATA_COUNT)
|
||||||
|
info->min_data_count *= 2;
|
||||||
|
else if (info->timing_mode == MODE_SHORT)
|
||||||
|
info->do_icarus_timing = false;
|
||||||
|
|
||||||
|
// applog(LOG_WARNING, "Icarus %d Re-estimate: read_count=%d fullnonce=%fs history count=%d Hs=%e W=%e values=%d hash range=0x%08lx min data count=%u", icarus->device_id, read_count, fullnonce, count, Hs, W, values, hash_count_range, info->min_data_count);
|
||||||
|
applog(LOG_WARNING, "Icarus %d Re-estimate: Hs=%e W=%e read_count=%d fullnonce=%.3fs",
|
||||||
|
icarus->device_id, Hs, W, read_count, fullnonce);
|
||||||
|
}
|
||||||
|
info->history_count++;
|
||||||
|
gettimeofday(&tv_history_finish, NULL);
|
||||||
|
|
||||||
|
timersub(&tv_history_finish, &tv_history_start, &tv_history_finish);
|
||||||
|
timeradd(&tv_history_finish, &(info->history_time), &(info->history_time));
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void icarus_api_stats(char *buf, struct cgpu_info *cgpu, bool isjson)
|
||||||
|
{
|
||||||
|
struct ICARUS_INFO *info = icarus_info[cgpu->device_id];
|
||||||
|
|
||||||
|
// Warning, access to these is not locked - but we don't really
|
||||||
|
// care since hashing performance is way more important than
|
||||||
|
// locking access to displaying API debug 'stats'
|
||||||
|
sprintf(buf, isjson
|
||||||
|
? "\"read_count\":%d,\"fullnonce\":%f,\"count\":%d,\"Hs\":%.15f,\"W\":%f,\"total_values\":%u,\"range\":%"PRIu64",\"history_count\":%"PRIu64",\"history_time\":%f,\"min_data_count\":%u,\"timing_values\":%u"
|
||||||
|
: "read_count=%d,fullnonce=%f,count=%d,Hs=%.15f,W=%f,total_values=%u,range=%"PRIu64",history_count=%"PRIu64",history_time=%f,min_data_count=%u,timing_values=%u",
|
||||||
|
info->read_count, info->fullnonce,
|
||||||
|
info->count, info->Hs, info->W,
|
||||||
|
info->values, info->hash_count_range,
|
||||||
|
info->history_count,
|
||||||
|
(double)(info->history_time.tv_sec)
|
||||||
|
+ ((double)(info->history_time.tv_usec))/((double)1000000),
|
||||||
|
info->min_data_count, info->history[0].values);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void icarus_shutdown(struct thr_info *thr)
|
static void icarus_shutdown(struct thr_info *thr)
|
||||||
@ -390,6 +773,7 @@ struct device_api icarus_api = {
|
|||||||
.dname = "icarus",
|
.dname = "icarus",
|
||||||
.name = "ICA",
|
.name = "ICA",
|
||||||
.api_detect = icarus_detect,
|
.api_detect = icarus_detect,
|
||||||
|
.get_api_stats = icarus_api_stats,
|
||||||
.thread_prepare = icarus_prepare,
|
.thread_prepare = icarus_prepare,
|
||||||
.scanhash = icarus_scanhash,
|
.scanhash = icarus_scanhash,
|
||||||
.thread_shutdown = icarus_shutdown,
|
.thread_shutdown = icarus_shutdown,
|
||||||
|
4
miner.h
4
miner.h
@ -514,6 +514,7 @@ extern bool opt_api_listen;
|
|||||||
extern bool opt_api_network;
|
extern bool opt_api_network;
|
||||||
extern bool opt_delaynet;
|
extern bool opt_delaynet;
|
||||||
extern bool opt_restart;
|
extern bool opt_restart;
|
||||||
|
extern char *opt_icarus_timing;
|
||||||
|
|
||||||
extern pthread_rwlock_t netacc_lock;
|
extern pthread_rwlock_t netacc_lock;
|
||||||
|
|
||||||
@ -716,11 +717,13 @@ struct work {
|
|||||||
int thr_id;
|
int thr_id;
|
||||||
struct pool *pool;
|
struct pool *pool;
|
||||||
struct timeval tv_staged;
|
struct timeval tv_staged;
|
||||||
|
|
||||||
bool mined;
|
bool mined;
|
||||||
bool clone;
|
bool clone;
|
||||||
bool cloned;
|
bool cloned;
|
||||||
bool rolltime;
|
bool rolltime;
|
||||||
bool longpoll;
|
bool longpoll;
|
||||||
|
bool stale;
|
||||||
|
|
||||||
unsigned int work_block;
|
unsigned int work_block;
|
||||||
int id;
|
int id;
|
||||||
@ -739,6 +742,7 @@ extern void kill_work(void);
|
|||||||
extern void switch_pools(struct pool *selected);
|
extern void switch_pools(struct pool *selected);
|
||||||
extern void remove_pool(struct pool *pool);
|
extern void remove_pool(struct pool *pool);
|
||||||
extern void write_config(FILE *fcfg);
|
extern void write_config(FILE *fcfg);
|
||||||
|
extern void default_save_file(char *filename);
|
||||||
extern void log_curses(int prio, const char *f, va_list ap);
|
extern void log_curses(int prio, const char *f, va_list ap);
|
||||||
extern void clear_logwin(void);
|
extern void clear_logwin(void);
|
||||||
extern bool pool_tclear(struct pool *pool, bool *var);
|
extern bool pool_tclear(struct pool *pool, bool *var);
|
||||||
|
343
miner.php
343
miner.php
@ -2,6 +2,7 @@
|
|||||||
session_start();
|
session_start();
|
||||||
#
|
#
|
||||||
global $miner, $port, $readonly, $notify, $rigs, $socktimeoutsec;
|
global $miner, $port, $readonly, $notify, $rigs, $socktimeoutsec;
|
||||||
|
global $checklastshare;
|
||||||
#
|
#
|
||||||
# Don't touch these 2 - see $rigs below
|
# Don't touch these 2 - see $rigs below
|
||||||
$miner = null;
|
$miner = null;
|
||||||
@ -17,6 +18,13 @@ $readonly = false;
|
|||||||
# coz it doesn't have notify - it just shows the error status table
|
# coz it doesn't have notify - it just shows the error status table
|
||||||
$notify = true;
|
$notify = 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
|
||||||
|
$checklastshare = true;
|
||||||
|
#
|
||||||
# Set $rigs to an array of your cgminer rigs that are running
|
# Set $rigs to an array of your cgminer rigs that are running
|
||||||
# format: 'IP:Port' or 'Host:Port'
|
# format: 'IP:Port' or 'Host:Port'
|
||||||
# If you only have one rig, it will just show the detail of that rig
|
# If you only have one rig, it will just show the detail of that rig
|
||||||
@ -70,6 +78,7 @@ td.err { color:black; font-family:verdana,arial,sans; font-size:13pt; background
|
|||||||
td.warn { color:black; font-family:verdana,arial,sans; font-size:13pt; background:#ffb050 }
|
td.warn { color:black; font-family:verdana,arial,sans; font-size:13pt; background:#ffb050 }
|
||||||
td.sta { color:green; font-family:verdana,arial,sans; font-size:13pt; }
|
td.sta { color:green; font-family:verdana,arial,sans; font-size:13pt; }
|
||||||
td.tot { color:blue; font-family:verdana,arial,sans; font-size:13pt; background:#fff8f2 }
|
td.tot { color:blue; font-family:verdana,arial,sans; font-size:13pt; background:#fff8f2 }
|
||||||
|
td.lst { color:blue; font-family:verdana,arial,sans; font-size:13pt; background:#ffffdd }
|
||||||
</style>
|
</style>
|
||||||
</head><body bgcolor=#ecffff>
|
</head><body bgcolor=#ecffff>
|
||||||
<script type='text/javascript'>
|
<script type='text/javascript'>
|
||||||
@ -222,140 +231,230 @@ function getparam($name, $both = false)
|
|||||||
return substr($a, 0, 1024);
|
return substr($a, 0, 1024);
|
||||||
}
|
}
|
||||||
#
|
#
|
||||||
function fmt($section, $name, $value)
|
function classlastshare($when, $alldata, $warnclass, $errorclass)
|
||||||
|
{
|
||||||
|
global $checklastshare;
|
||||||
|
|
||||||
|
if ($checklastshare === false)
|
||||||
|
return '';
|
||||||
|
|
||||||
|
if ($when == 0)
|
||||||
|
return '';
|
||||||
|
|
||||||
|
if (!isset($alldata['MHS av']))
|
||||||
|
return '';
|
||||||
|
|
||||||
|
if (!isset($alldata['Last Share Time']))
|
||||||
|
return '';
|
||||||
|
|
||||||
|
$expected = pow(2, 32) / ($alldata['MHS av'] * pow(10, 6));
|
||||||
|
$howlong = $when - $alldata['Last Share Time'];
|
||||||
|
if ($howlong < 1)
|
||||||
|
$howlong = 1;
|
||||||
|
|
||||||
|
if ($howlong > ($expected * 12))
|
||||||
|
return $errorclass;
|
||||||
|
|
||||||
|
if ($howlong > ($expected * 8))
|
||||||
|
return $warnclass;
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
#
|
||||||
|
function fmt($section, $name, $value, $when, $alldata)
|
||||||
{
|
{
|
||||||
global $dfmt;
|
global $dfmt;
|
||||||
|
|
||||||
|
if ($alldata == null)
|
||||||
|
$alldata = array();
|
||||||
|
|
||||||
$errorclass = ' class=err';
|
$errorclass = ' class=err';
|
||||||
$warnclass = ' class=warn';
|
$warnclass = ' class=warn';
|
||||||
|
$lstclass = ' class=lst';
|
||||||
$b = ' ';
|
$b = ' ';
|
||||||
|
|
||||||
$ret = $value;
|
$ret = $value;
|
||||||
$class = '';
|
$class = '';
|
||||||
|
|
||||||
switch ($section.'.'.$name)
|
if ($value === null)
|
||||||
{
|
$ret = $b;
|
||||||
case 'GPU.Last Share Time':
|
else
|
||||||
case 'PGA.Last Share Time':
|
switch ($section.'.'.$name)
|
||||||
$ret = date('H:i:s', $value);
|
|
||||||
break;
|
|
||||||
case 'SUMMARY.Elapsed':
|
|
||||||
$s = $value % 60;
|
|
||||||
$value -= $s;
|
|
||||||
$value /= 60;
|
|
||||||
if ($value == 0)
|
|
||||||
$ret = $s.'s';
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
$m = $value % 60;
|
case 'GPU.Last Share Time':
|
||||||
$value -= $m;
|
case 'PGA.Last Share Time':
|
||||||
$value /= 60;
|
if ($value == 0
|
||||||
if ($value == 0)
|
|| (isset($alldata['Last Share Pool']) && $alldata['Last Share Pool'] == -1))
|
||||||
$ret = sprintf("%dm$b%02ds", $m, $s);
|
{
|
||||||
|
$ret = 'Never';
|
||||||
|
$class = $warnclass;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$h = $value % 24;
|
$ret = date('H:i:s', $value);
|
||||||
$value -= $h;
|
$class = classlastshare($when, $alldata, $warnclass, $errorclass);
|
||||||
$value /= 24;
|
}
|
||||||
|
break;
|
||||||
|
case 'POOL.Last Share Time':
|
||||||
|
if ($value == 0)
|
||||||
|
$ret = 'Never';
|
||||||
|
else
|
||||||
|
$ret = date('H:i:s d-M', $value);
|
||||||
|
break;
|
||||||
|
case 'GPU.Last Share Pool':
|
||||||
|
case 'PGA.Last Share Pool':
|
||||||
|
if ($value == -1)
|
||||||
|
{
|
||||||
|
$ret = 'None';
|
||||||
|
$class = $warnclass;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'SUMMARY.Elapsed':
|
||||||
|
$s = $value % 60;
|
||||||
|
$value -= $s;
|
||||||
|
$value /= 60;
|
||||||
|
if ($value == 0)
|
||||||
|
$ret = $s.'s';
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$m = $value % 60;
|
||||||
|
$value -= $m;
|
||||||
|
$value /= 60;
|
||||||
if ($value == 0)
|
if ($value == 0)
|
||||||
$ret = sprintf("%dh$b%02dm$b%02ds", $h, $m, $s);
|
$ret = sprintf("%dm$b%02ds", $m, $s);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ($value == 1)
|
$h = $value % 24;
|
||||||
$days = '';
|
$value -= $h;
|
||||||
|
$value /= 24;
|
||||||
|
if ($value == 0)
|
||||||
|
$ret = sprintf("%dh$b%02dm$b%02ds", $h, $m, $s);
|
||||||
else
|
else
|
||||||
$days = 's';
|
{
|
||||||
|
if ($value == 1)
|
||||||
$ret = sprintf("%dday$days$b%02dh$b%02dm$b%02ds", $value, $h, $m, $s);
|
$days = '';
|
||||||
|
else
|
||||||
|
$days = 's';
|
||||||
|
|
||||||
|
$ret = sprintf("%dday$days$b%02dh$b%02dm$b%02ds", $value, $h, $m, $s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case 'NOTIFY.Last Well':
|
||||||
|
if ($value == '0')
|
||||||
|
{
|
||||||
|
$ret = 'Never';
|
||||||
|
$class = $warnclass;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$ret = date('H:i:s', $value);
|
||||||
|
break;
|
||||||
|
case 'NOTIFY.Last Not Well':
|
||||||
|
if ($value == '0')
|
||||||
|
$ret = 'Never';
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$ret = date('H:i:s', $value);
|
||||||
|
$class = $errorclass;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'NOTIFY.Reason Not Well':
|
||||||
|
if ($value != 'None')
|
||||||
|
$class = $errorclass;
|
||||||
|
break;
|
||||||
|
case 'GPU.Utility':
|
||||||
|
case 'PGA.Utility':
|
||||||
|
case 'SUMMARY.Utility':
|
||||||
|
$ret = $value.'/m';
|
||||||
|
if ($value == 0)
|
||||||
|
$class = $warnclass;
|
||||||
|
break;
|
||||||
|
case 'PGA.Temperature':
|
||||||
|
$ret = $value.'°C';
|
||||||
|
break;
|
||||||
|
case 'GPU.Temperature':
|
||||||
|
$ret = $value.'°C';
|
||||||
|
case 'GPU.GPU Clock':
|
||||||
|
case 'GPU.Memory Clock':
|
||||||
|
case 'GPU.GPU Voltage':
|
||||||
|
case 'GPU.GPU Activity':
|
||||||
|
if ($value == 0)
|
||||||
|
$class = $warnclass;
|
||||||
|
break;
|
||||||
|
case 'GPU.Fan Percent':
|
||||||
|
if ($value == 0)
|
||||||
|
$class = $warnclass;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($value == 100)
|
||||||
|
$class = $errorclass;
|
||||||
|
else
|
||||||
|
if ($value > 85)
|
||||||
|
$class = $warnclass;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'GPU.Fan Speed':
|
||||||
|
if ($value == 0)
|
||||||
|
$class = $warnclass;
|
||||||
|
else
|
||||||
|
if (isset($alldata['Fan Percent']))
|
||||||
|
{
|
||||||
|
$test = $alldata['Fan Percent'];
|
||||||
|
if ($test == 100)
|
||||||
|
$class = $errorclass;
|
||||||
|
else
|
||||||
|
if ($test > 85)
|
||||||
|
$class = $warnclass;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'GPU.MHS av':
|
||||||
|
case 'PGA.MHS av':
|
||||||
|
case 'SUMMARY.MHS av':
|
||||||
|
case 'GPU.Total MH':
|
||||||
|
case 'PGA.Total MH':
|
||||||
|
case 'SUMMARY.Total MH':
|
||||||
|
case 'SUMMARY.Getworks':
|
||||||
|
case 'GPU.Accepted':
|
||||||
|
case 'PGA.Accepted':
|
||||||
|
case 'SUMMARY.Accepted':
|
||||||
|
case 'GPU.Rejected':
|
||||||
|
case 'PGA.Rejected':
|
||||||
|
case 'SUMMARY.Rejected':
|
||||||
|
case 'SUMMARY.Local Work':
|
||||||
|
case 'POOL.Getworks':
|
||||||
|
case 'POOL.Accepted':
|
||||||
|
case 'POOL.Rejected':
|
||||||
|
case 'POOL.Discarded':
|
||||||
|
$parts = explode('.', $value, 2);
|
||||||
|
if (count($parts) == 1)
|
||||||
|
$dec = '';
|
||||||
|
else
|
||||||
|
$dec = '.'.$parts[1];
|
||||||
|
$ret = number_format($parts[0]).$dec;
|
||||||
|
break;
|
||||||
|
case 'GPU.Status':
|
||||||
|
case 'PGA.Status':
|
||||||
|
case 'POOL.Status':
|
||||||
|
if ($value != 'Alive')
|
||||||
|
$class = $errorclass;
|
||||||
|
break;
|
||||||
|
case 'GPU.Enabled':
|
||||||
|
case 'PGA.Enabled':
|
||||||
|
if ($value != 'Y')
|
||||||
|
$class = $warnclass;
|
||||||
|
break;
|
||||||
|
case 'STATUS.When':
|
||||||
|
$ret = date($dfmt, $value);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 'NOTIFY.Last Well':
|
|
||||||
if ($value == '0')
|
|
||||||
{
|
|
||||||
$ret = 'Never';
|
|
||||||
$class = $warnclass;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
$ret = date('H:i:s', $value);
|
|
||||||
break;
|
|
||||||
case 'NOTIFY.Last Not Well':
|
|
||||||
if ($value == '0')
|
|
||||||
$ret = 'Never';
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$ret = date('H:i:s', $value);
|
|
||||||
$class = $errorclass;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'NOTIFY.Reason Not Well':
|
|
||||||
if ($value != 'None')
|
|
||||||
$class = $errorclass;
|
|
||||||
break;
|
|
||||||
case 'GPU.Utility':
|
|
||||||
case 'PGA.Utility':
|
|
||||||
case 'SUMMARY.Utility':
|
|
||||||
$ret = $value.'/m';
|
|
||||||
break;
|
|
||||||
case 'PGA.Temperature':
|
|
||||||
$ret = $value.'°C';
|
|
||||||
break;
|
|
||||||
case 'GPU.Temperature':
|
|
||||||
$ret = $value.'°C';
|
|
||||||
case 'GPU.Fan Speed':
|
|
||||||
case 'GPU.Fan Percent':
|
|
||||||
case 'GPU.GPU Clock':
|
|
||||||
case 'GPU.Memory Clock':
|
|
||||||
case 'GPU.GPU Voltage':
|
|
||||||
case 'GPU.GPU Activity':
|
|
||||||
if ($value == 0)
|
|
||||||
$class = $warnclass;
|
|
||||||
break;
|
|
||||||
case 'GPU.MHS av':
|
|
||||||
case 'PGA.MHS av':
|
|
||||||
case 'SUMMARY.MHS av':
|
|
||||||
case 'GPU.Total MH':
|
|
||||||
case 'PGA.Total MH':
|
|
||||||
case 'SUMMARY.Total MH':
|
|
||||||
case 'SUMMARY.Getworks':
|
|
||||||
case 'GPU.Accepted':
|
|
||||||
case 'PGA.Accepted':
|
|
||||||
case 'SUMMARY.Accepted':
|
|
||||||
case 'GPU.Rejected':
|
|
||||||
case 'PGA.Rejected':
|
|
||||||
case 'SUMMARY.Rejected':
|
|
||||||
case 'SUMMARY.Local Work':
|
|
||||||
case 'POOL.Getworks':
|
|
||||||
case 'POOL.Accepted':
|
|
||||||
case 'POOL.Rejected':
|
|
||||||
case 'POOL.Discarded':
|
|
||||||
$parts = explode('.', $value, 2);
|
|
||||||
if (count($parts) == 1)
|
|
||||||
$dec = '';
|
|
||||||
else
|
|
||||||
$dec = '.'.$parts[1];
|
|
||||||
$ret = number_format($parts[0]).$dec;
|
|
||||||
break;
|
|
||||||
case 'GPU.Status':
|
|
||||||
case 'PGA.Status':
|
|
||||||
case 'POOL.Status':
|
|
||||||
if ($value != 'Alive')
|
|
||||||
$class = $errorclass;
|
|
||||||
break;
|
|
||||||
case 'GPU.Enabled':
|
|
||||||
case 'PGA.Enabled':
|
|
||||||
if ($value != 'Y')
|
|
||||||
$class = $warnclass;
|
|
||||||
break;
|
|
||||||
case 'STATUS.When':
|
|
||||||
$ret = date($dfmt, $value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($section == 'NOTIFY' && substr($name, 0, 1) == '*' && $value != '0')
|
if ($section == 'NOTIFY' && substr($name, 0, 1) == '*' && $value != '0')
|
||||||
$class = $errorclass;
|
$class = $errorclass;
|
||||||
|
|
||||||
|
if ($class == '' && $section != 'POOL')
|
||||||
|
$class = classlastshare($when, $alldata, $lstclass, $lstclass);
|
||||||
|
|
||||||
return array($ret, $class);
|
return array($ret, $class);
|
||||||
}
|
}
|
||||||
#
|
#
|
||||||
@ -390,6 +489,8 @@ function details($cmd, $list, $rig)
|
|||||||
global $poolcmd, $readonly;
|
global $poolcmd, $readonly;
|
||||||
global $showndate;
|
global $showndate;
|
||||||
|
|
||||||
|
$when = 0;
|
||||||
|
|
||||||
$stas = array('S' => 'Success', 'W' => 'Warning', 'I' => 'Informational', 'E' => 'Error', 'F' => 'Fatal');
|
$stas = array('S' => 'Success', 'W' => 'Warning', 'I' => 'Informational', 'E' => 'Error', 'F' => 'Fatal');
|
||||||
|
|
||||||
echo $tablebegin;
|
echo $tablebegin;
|
||||||
@ -408,7 +509,10 @@ function details($cmd, $list, $rig)
|
|||||||
echo '<tr>';
|
echo '<tr>';
|
||||||
echo '<td>Computer: '.$list['STATUS']['Description'].'</td>';
|
echo '<td>Computer: '.$list['STATUS']['Description'].'</td>';
|
||||||
if (isset($list['STATUS']['When']))
|
if (isset($list['STATUS']['When']))
|
||||||
|
{
|
||||||
echo '<td>When: '.date($dfmt, $list['STATUS']['When']).'</td>';
|
echo '<td>When: '.date($dfmt, $list['STATUS']['When']).'</td>';
|
||||||
|
$when = $list['STATUS']['When'];
|
||||||
|
}
|
||||||
$sta = $list['STATUS']['STATUS'];
|
$sta = $list['STATUS']['STATUS'];
|
||||||
echo '<td>Status: '.$stas[$sta].'</td>';
|
echo '<td>Status: '.$stas[$sta].'</td>';
|
||||||
echo '<td>Message: '.$list['STATUS']['Msg'].'</td>';
|
echo '<td>Message: '.$list['STATUS']['Msg'].'</td>';
|
||||||
@ -436,7 +540,7 @@ function details($cmd, $list, $rig)
|
|||||||
|
|
||||||
foreach ($values as $name => $value)
|
foreach ($values as $name => $value)
|
||||||
{
|
{
|
||||||
list($showvalue, $class) = fmt($section, $name, $value);
|
list($showvalue, $class) = fmt($section, $name, $value, $when, $values);
|
||||||
echo "<td$class>$showvalue</td>";
|
echo "<td$class>$showvalue</td>";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,6 +691,8 @@ function doforeach($cmd, $des, $sum, $head, $datetime)
|
|||||||
global $tablebegin, $tableend, $warnfont, $warnoff, $dfmt;
|
global $tablebegin, $tableend, $warnfont, $warnoff, $dfmt;
|
||||||
global $rigerror;
|
global $rigerror;
|
||||||
|
|
||||||
|
$when = 0;
|
||||||
|
|
||||||
$header = $head;
|
$header = $head;
|
||||||
$anss = array();
|
$anss = array();
|
||||||
|
|
||||||
@ -652,7 +758,7 @@ function doforeach($cmd, $des, $sum, $head, $datetime)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (isset($row[$name]))
|
if (isset($row[$name]))
|
||||||
list($showvalue, $class) = fmt('STATUS', $name, $row[$name]);
|
list($showvalue, $class) = fmt('STATUS', $name, $row[$name], $when, null);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$class = '';
|
$class = '';
|
||||||
@ -710,6 +816,10 @@ function doforeach($cmd, $des, $sum, $head, $datetime)
|
|||||||
|
|
||||||
foreach ($anss as $rig => $ans)
|
foreach ($anss as $rig => $ans)
|
||||||
{
|
{
|
||||||
|
$when = 0;
|
||||||
|
if (isset($ans['STATUS']['When']))
|
||||||
|
$when = $ans['STATUS']['When'];
|
||||||
|
|
||||||
foreach ($ans as $item => $row)
|
foreach ($ans as $item => $row)
|
||||||
{
|
{
|
||||||
if ($item == 'STATUS')
|
if ($item == 'STATUS')
|
||||||
@ -733,12 +843,11 @@ function doforeach($cmd, $des, $sum, $head, $datetime)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (isset($row[$name]))
|
if (isset($row[$name]))
|
||||||
list($showvalue, $class) = fmt($section, $name, $row[$name]);
|
$value = $row[$name];
|
||||||
else
|
else
|
||||||
{
|
$value = null;
|
||||||
$class = '';
|
|
||||||
$showvalue = ' ';
|
list($showvalue, $class) = fmt($section, $name, $value, $when, $row);
|
||||||
}
|
|
||||||
|
|
||||||
if ($rig === 'total' and $class == '')
|
if ($rig === 'total' and $class == '')
|
||||||
$class = ' class=tot';
|
$class = ' class=tot';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user