Browse Source

Merge pull request #310 from kanoi/master

API debug, API-README, API Correct diff1 name, Device diff1, API diff1 etc.
nfactor-troky
Con Kolivas 12 years ago
parent
commit
3243b91e2d
  1. 83
      API-README
  2. 72
      README
  3. 230
      api.c
  4. 230
      cgminer.c
  5. 62
      driver-bitforce.c
  6. 4
      driver-cpu.c
  7. 12
      driver-icarus.c
  8. 14
      driver-modminer.c
  9. 16
      findnonce.c
  10. 53
      fpgautils.c
  11. 16
      fpgautils.h
  12. 2
      logging.h
  13. 42
      miner.h
  14. 79
      miner.php
  15. 73
      util.c

83
API-README

@ -124,7 +124,10 @@ The list of requests - a (*) means it requires privileged access - and replies a
Log Interval=N, <- log interval (--log N) Log Interval=N, <- log interval (--log N)
Device Code=GPU ICA , <- spaced list of compiled devices Device Code=GPU ICA , <- spaced list of compiled devices
OS=Linux/Apple/..., <- operating System OS=Linux/Apple/..., <- operating System
Failover-Only=true/false | <- failover-only setting Failover-Only=true/false, <- failover-only setting
ScanTime=N, <- --scan-time setting
Queue=N, <- --queue setting
Expiry=N| <- --expiry setting
summary SUMMARY The status summary of the miner summary SUMMARY The status summary of the miner
e.g. Elapsed=NNN,Found Blocks=N,Getworks=N,...| e.g. Elapsed=NNN,Found Blocks=N,Getworks=N,...|
@ -259,6 +262,22 @@ The list of requests - a (*) means it requires privileged access - and replies a
stating the results of the disable request stating the results of the disable request
This is only available if PGA mining is enabled This is only available if PGA mining is enabled
pgaidentify|N (*)
none There is no reply section just the STATUS section
stating the results of the identify request
This is only available if PGA mining is enabled
and currently only BFL singles support this command
On a BFL single it will flash the led on the front
of the device for appoximately 4s
All other non BFL PGA devices will return a warning
status message stating that they dont support it
This adds a 4s delay to the BFL share being processed
so you may get a message stating that procssing took
longer than 7000ms if the request was sent towards
the end of the timing of any work being worked on
e.g.: BFL0: took 8438ms - longer than 7000ms
You should ignore this
devdetails DEVDETAILS Each device with a list of their static details devdetails DEVDETAILS Each device with a list of their static details
This lists all devices including those not supported This lists all devices including those not supported
by the 'devs' command by the 'devs' command
@ -287,6 +306,30 @@ The list of requests - a (*) means it requires privileged access - and replies a
Current Block Hash=XXXX..., <- blank if none Current Block Hash=XXXX..., <- blank if none
LP=true/false| <- LP is in use on at least 1 pool LP=true/false| <- LP is in use on at least 1 pool
debug|setting (*)
DEBUG Debug settings
The optional commands for 'setting' are the same as
the screen curses debug settings
You can only specify one setting
Only the first character is checked (case insensitive):
Silent, Quiet, Verbose, Debug, RPCProto, PerDevice,
WorkTime, Normal
The output fields are (as above):
Silent=true/false,
Quiet=true/false,
Verbose=true/false,
Debug=true/false,
RPCProto=true/false,
PerDevice=true/false,
WorkTime=true/false|
setconfig|name,N (*)
none There is no reply section just the STATUS section
stating the results of setting 'name' to N
The valid values for name are currently:
queue, scantime, expiry
N is an integer in the range 0 to 9999
When you enable, disable or restart a GPU or PGA, you will also get Thread messages When you enable, disable or restart a GPU or PGA, you will also get Thread messages
in the cgminer status window in the cgminer status window
@ -306,8 +349,9 @@ windows
Obviously, the JSON format is simply just the names as given before the '=' Obviously, the JSON format is simply just the names as given before the '='
with the values after the '=' with the values after the '='
If you enable cgminer debug (-D or --debug) you will also get messages showing If you enable cgminer debug (-D or --debug) or, when cgminer debug is off,
details of the requests received and the replies turn on debug with the API command 'debug|debug' you will also get messages
showing some details of the requests received and the replies
There are included 4 program examples for accessing the API: There are included 4 program examples for accessing the API:
@ -339,13 +383,32 @@ miner.php - an example web page to access the API
Feature Changelog for external applications using the API: Feature Changelog for external applications using the API:
API V1.18 API V1.19
Added API commands:
'debug'
'pgaidentify|N' (only works for BFL Singles so far)
'setconfig|name,N'
Modified API commands: Modified API commands:
'stats' - add 'Work Had Roll Time', 'Work Can Roll', 'Work Had Expire', 'devs' - add 'Diff1 Work', 'Difficulty Accepted', 'Difficulty Rejected',
'Work Roll Time' to the pool stats 'Last Share Difficulty' to all devices
'gpu|N' - add 'Diff1 Work', 'Difficulty Accepted',
'Difficulty Rejected', 'Last Share Difficulty'
'pga|N' - add 'Diff1 Work', 'Difficulty Accepted',
'Difficulty Rejected', 'Last Share Difficulty'
'notify' - add '*Dev Throttle' (for BFL Singles)
'pools' - add 'Proxy Type', 'Proxy', 'Difficulty Accepted', 'Difficulty Rejected',
'Difficulty Stale', 'Last Share Difficulty'
'config' - add 'Queue', 'Expiry'
----------
API V1.18 (cgminer v2.7.4)
Modified API commands: Modified API commands:
'stats' - add 'Work Had Roll Time', 'Work Can Roll', 'Work Had Expire',
'Work Roll Time' to the pool stats
'config' - include 'ScanTime' 'config' - include 'ScanTime'
---------- ----------
@ -866,6 +929,14 @@ e.g. $rigs = array('127.0.0.1:4028','myrig.com:4028:Sugoi');
--------- ---------
Default:
$rigipsecurity = true;
Set $rigipsecurity to false to show the IP/Port of the rig
in the socket error messages and also show the full socket message
---------
Default: Default:
$rigtotals = true; $rigtotals = true;
$forcerigtotals = false; $forcerigtotals = false;

72
README

@ -168,7 +168,7 @@ Options for both config file and command line:
--scrypt Use the scrypt algorithm for mining (litecoin only) --scrypt Use the scrypt algorithm for mining (litecoin only)
--sharelog <arg> Append share log to file --sharelog <arg> Append share log to file
--shares <arg> Quit after mining N shares (default: unlimited) --shares <arg> Quit after mining N shares (default: unlimited)
--socks-proxy <arg> Set socks4 proxy (host:port) --socks-proxy <arg> Set socks4 proxy (host:port) for all pools without a proxy specified
--syslog Use system log for output messages (default: standard error) --syslog Use system log for output messages (default: standard error)
--temp-cutoff <arg> Temperature where a device will be automatically disabled, one value or comma separated list (default: 95) --temp-cutoff <arg> Temperature where a device will be automatically disabled, one value or comma separated list (default: 95)
--text-only|-T Disable ncurses formatted screen output --text-only|-T Disable ncurses formatted screen output
@ -239,6 +239,7 @@ The official supplied binaries are compiled with support for all FPGAs.
To force the code to only attempt detection with a specific driver, To force the code to only attempt detection with a specific driver,
prepend the argument with the driver name followed by a colon. prepend the argument with the driver name followed by a colon.
For example, "icarus:/dev/ttyUSB0" or "bitforce:\\.\COM5" For example, "icarus:/dev/ttyUSB0" or "bitforce:\\.\COM5"
or using the short name: "ica:/dev/ttyUSB0" or "bfl:\\.\COM5"
For other FPGA details see the FPGA-README For other FPGA details see the FPGA-README
@ -295,6 +296,28 @@ Add overclocking settings, GPU and fan control with different engine settings fo
cgminer -o http://pool:port -u username -p password -I 9 --auto-fan --auto-gpu --gpu-engine 750-950,945,700-930,960 --gpu-memclock 300 cgminer -o http://pool:port -u username -p password -I 9 --auto-fan --auto-gpu --gpu-engine 750-950,945,700-930,960 --gpu-memclock 300
Single pool with a standard http proxy, regular desktop:
cgminer -o "http:proxy:port|http://pool:port" -u username -p password
Single pool with a socks5 proxy, regular desktop:
cgminer -o "socks5:proxy:port|http://pool:port" -u username -p password
The list of proxy types are:
http: standard http 1.1 proxy
http0: http 1.0 proxy
socks4: socks4 proxy
socks5: socks5 proxy
socks4a: socks4a proxy
socks5h: socks5 proxy using a hostname
If you compile cgminer with a version of CURL before 7.19.4 then some of the above will
not be available. All are available since CURL version 7.19.4
If you specify the --socks-proxy option to cgminer, it will only be applied to all pools
that don't specify their own proxy setting like above
READ WARNINGS AND DOCUMENTATION BELOW ABOUT OVERCLOCKING READ WARNINGS AND DOCUMENTATION BELOW ABOUT OVERCLOCKING
On Linux you virtually always need to export your display settings before On Linux you virtually always need to export your display settings before
@ -451,6 +474,26 @@ it will log to a file called logfile.txt and otherwise work the same.
There is also the -m option on linux which will spawn a command of your choice There is also the -m option on linux which will spawn a command of your choice
and pipe the output directly to that command. and pipe the output directly to that command.
The WorkTime details 'debug' option adds details on the end of each line
displayed for Accepted or Rejected work done. An example would be:
<-00000059.ed4834a3 M:X D:1.0 G:17:02:38:0.405 C:1.855 (2.995) W:3.440 (0.000) S:0.461 R:17:02:47
The first 2 hex codes are the previous block hash, the rest are reported in
seconds unless stated otherwise:
The previous hash is followed by the getwork mode used M:X where X is one of
P:Pool, T:Test Pool, L:LP or B:Benchmark,
then D:d.ddd is the difficulty required to get a share from the work,
then G:hh:mm:ss:n.nnn, which is when the getwork or LP was sent to the pool and
the n.nnn is how long it took to reply,
followed by 'O' on it's own if it is an original getwork, or 'C:n.nnn' if it was
a clone with n.nnn stating how long after the work was recieved that it was cloned,
(m.mmm) is how long from when the original work was received until work started,
W:n.nnn is how long the work took to process until it was ready to submit,
(m.mmm) is how long from ready to submit to actually doing the submit, this is
usually 0.000 unless there was a problem with submitting the work,
S:n.nnn is how long it took to submit the completed work and await the reply,
R:hh:mm:ss is the actual time the work submit reply was received
If you start cgminer with the --sharelog option, you can get detailed If you start cgminer with the --sharelog option, you can get detailed
information for each share found. The argument to the option may be "-" for information for each share found. The argument to the option may be "-" for
@ -816,7 +859,7 @@ driver version and ATI stream version.
Q: cgminer reports no devices or only one device on startup on Linux although Q: cgminer reports no devices or only one device on startup on Linux although
I have multiple devices and drivers+SDK installed properly? I have multiple devices and drivers+SDK installed properly?
A: Try 'export DISPLAY=:0" before running cgminer. A: Try "export DISPLAY=:0" before running cgminer.
Q: My network gets slower and slower and then dies for a minute? Q: My network gets slower and slower and then dies for a minute?
A; Try the --net-delay option. A; Try the --net-delay option.
@ -843,10 +886,27 @@ They are Field-Programmable Gate Arrays that have been programmed to do Bitcoin
mining. Since the acronym needs to be only 3 characters, the "Field-" part has mining. Since the acronym needs to be only 3 characters, the "Field-" part has
been skipped. been skipped.
Q: How do I get my BFL device to auto-recognise? Q: How do I get my BFL/Icarus/Lancelot/Cairnsmore device to auto-recognise?
A: The only thing that needs to be done is to load the driver for them, which A: On linux, if the /dev/ttyUSB* devices don't automatically appear, the only
on linux would require: thing that needs to be done is to load the driver for them:
sudo modprobe ftdi_sio vendor=0x0403 product=0x6014 BFL: sudo modprobe ftdi_sio vendor=0x0403 product=0x6014
Icarus: sudo modprobe pl2303 vendor=0x067b product=0x230
Lancelot: sudo modprobe ftdi_sio vendor=0x0403 product=0x6001
Cairnsmore: sudo modprobe ftdi_sio product=0x8350 vendor=0x0403
On windows you must install the pl2303 or ftdi driver required for the device
pl2303: http://prolificusa.com/pl-2303hx-drivers/
ftdi: http://www.ftdichip.com/Drivers/VCP.htm
Q: On linux I can see the /dev/ttyUSB* devices for my ICA/BFL/MMQ FPGA, but
cgminer can't mine on them
A: Make sure you have the required priviledges to access the /dev/ttyUSB* devices:
sudo ls -las /dev/ttyUSB*
will give output like:
0 crw-rw---- 1 root dialout 188, 0 2012-09-11 13:49 /dev/ttyUSB0
This means your account must have the group 'dialout' or root priviledges
To permanently give your account the 'dialout' group:
sudo usermod -G dialout `whoami`
Then logout and back in again
--- ---

230
api.c

@ -166,11 +166,13 @@ static const char SEPARATOR = '|';
#define SEPSTR "|" #define SEPSTR "|"
static const char GPUSEP = ','; static const char GPUSEP = ',';
static const char *APIVERSION = "1.18"; static const char *APIVERSION = "1.19";
static const char *DEAD = "Dead"; static const char *DEAD = "Dead";
#if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA)
static const char *SICK = "Sick"; static const char *SICK = "Sick";
static const char *NOSTART = "NoStart"; static const char *NOSTART = "NoStart";
static const char *INIT = "Initialising"; static const char *INIT = "Initialising";
#endif
static const char *DISABLED = "Disabled"; static const char *DISABLED = "Disabled";
static const char *ALIVE = "Alive"; static const char *ALIVE = "Alive";
static const char *REJECTING = "Rejecting"; static const char *REJECTING = "Rejecting";
@ -258,6 +260,8 @@ static const char *OSINFO =
#define _MINESTATS "STATS" #define _MINESTATS "STATS"
#define _CHECK "CHECK" #define _CHECK "CHECK"
#define _MINECOIN "COIN" #define _MINECOIN "COIN"
#define _DEBUGSET "DEBUG"
#define _SETCONFIG "SETCONFIG"
static const char ISJSON = '{'; static const char ISJSON = '{';
#define JSON0 "{" #define JSON0 "{"
@ -295,6 +299,8 @@ static const char ISJSON = '{';
#define JSON_MINESTATS JSON1 _MINESTATS JSON2 #define JSON_MINESTATS JSON1 _MINESTATS JSON2
#define JSON_CHECK JSON1 _CHECK JSON2 #define JSON_CHECK JSON1 _CHECK JSON2
#define JSON_MINECOIN JSON1 _MINECOIN JSON2 #define JSON_MINECOIN JSON1 _MINECOIN JSON2
#define JSON_DEBUGSET JSON1 _DEBUGSET JSON2
#define JSON_SETCONFIG JSON1 _SETCONFIG JSON2
#define JSON_END JSON4 JSON5 #define JSON_END JSON4 JSON5
static const char *JSON_COMMAND = "command"; static const char *JSON_COMMAND = "command";
@ -390,6 +396,14 @@ static const char *JSON_PARAMETER = "parameter";
#define MSG_INVBOOL 76 #define MSG_INVBOOL 76
#define MSG_FOO 77 #define MSG_FOO 77
#define MSG_MINECOIN 78 #define MSG_MINECOIN 78
#define MSG_DEBUGSET 79
#define MSG_PGAIDENT 80
#define MSG_PGANOID 81
#define MSG_SETCONFIG 82
#define MSG_UNKCON 83
#define MSG_INVNUM 84
#define MSG_CONPAR 85
#define MSG_CONVAL 86
enum code_severity { enum code_severity {
SEVERITY_ERR, SEVERITY_ERR,
@ -418,6 +432,7 @@ enum code_parameters {
PARAM_STR, PARAM_STR,
PARAM_BOTH, PARAM_BOTH,
PARAM_BOOL, PARAM_BOOL,
PARAM_SET,
PARAM_NONE PARAM_NONE
}; };
@ -543,12 +558,24 @@ struct CODES {
{ SEVERITY_ERR, MSG_INVBOOL, PARAM_NONE, "Invalid parameter should be true or false" }, { SEVERITY_ERR, MSG_INVBOOL, PARAM_NONE, "Invalid parameter should be true or false" },
{ SEVERITY_SUCC, MSG_FOO, PARAM_BOOL, "Failover-Only set to %s" }, { SEVERITY_SUCC, MSG_FOO, PARAM_BOOL, "Failover-Only set to %s" },
{ SEVERITY_SUCC, MSG_MINECOIN,PARAM_NONE, "CGMiner coin" }, { SEVERITY_SUCC, MSG_MINECOIN,PARAM_NONE, "CGMiner coin" },
{ SEVERITY_SUCC, MSG_DEBUGSET,PARAM_STR, "Debug settings" },
#ifdef HAVE_AN_FPGA
{ SEVERITY_SUCC, MSG_PGAIDENT,PARAM_PGA, "Identify command sent to PGA%d" },
{ SEVERITY_WARN, MSG_PGANOID, PARAM_PGA, "PGA%d does not support identify" },
#endif
{ SEVERITY_SUCC, MSG_SETCONFIG,PARAM_SET, "Set config '%s' to %d" },
{ SEVERITY_ERR, MSG_UNKCON, PARAM_STR, "Unknown config '%s'" },
{ SEVERITY_ERR, MSG_INVNUM, PARAM_BOTH, "Invalid number (%d) for '%s' range is 0-9999" },
{ SEVERITY_ERR, MSG_CONPAR, PARAM_NONE, "Missing config parameters 'name,N'" },
{ SEVERITY_ERR, MSG_CONVAL, PARAM_STR, "Missing config value N for '%s,N'" },
{ SEVERITY_FAIL, 0, 0, NULL } { SEVERITY_FAIL, 0, 0, NULL }
}; };
static int my_thr_id = 0; static int my_thr_id = 0;
static bool bye; static bool bye;
#if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA)
static bool ping = true; static bool ping = true;
#endif
// Used to control quit restart access to shutdown variables // Used to control quit restart access to shutdown variables
static pthread_mutex_t quit_restart_lock; static pthread_mutex_t quit_restart_lock;
@ -749,6 +776,7 @@ static struct api_data *api_add_data_full(struct api_data *root, char *name, enu
case API_UTILITY: case API_UTILITY:
case API_FREQ: case API_FREQ:
case API_HS: case API_HS:
case API_DIFF:
api_data->data = (void *)malloc(sizeof(double)); api_data->data = (void *)malloc(sizeof(double));
*((double *)(api_data->data)) = *((double *)data); *((double *)(api_data->data)) = *((double *)data);
break; break;
@ -875,6 +903,11 @@ struct api_data *api_add_hs(struct api_data *root, char *name, double *data, boo
return api_add_data_full(root, name, API_HS, (void *)data, copy_data); return api_add_data_full(root, name, API_HS, (void *)data, copy_data);
} }
struct api_data *api_add_diff(struct api_data *root, char *name, double *data, bool copy_data)
{
return api_add_data_full(root, name, API_DIFF, (void *)data, copy_data);
}
static struct api_data *print_data(struct api_data *root, char *buf, bool isjson) static struct api_data *print_data(struct api_data *root, char *buf, bool isjson)
{ {
struct api_data *tmp; struct api_data *tmp;
@ -946,6 +979,9 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson
case API_HS: case API_HS:
sprintf(buf, "%.15f", *((double *)(root->data))); sprintf(buf, "%.15f", *((double *)(root->data)));
break; break;
case API_DIFF:
sprintf(buf, "%.8f", *((double *)(root->data)));
break;
case API_BOOL: case API_BOOL:
sprintf(buf, "%s", *((bool *)(root->data)) ? TRUESTR : FALSESTR); sprintf(buf, "%s", *((bool *)(root->data)) ? TRUESTR : FALSESTR);
break; break;
@ -1155,6 +1191,9 @@ static char *message(int messageid, int paramid, char *param2, bool isjson)
case PARAM_BOOL: case PARAM_BOOL:
sprintf(buf, codes[i].description, paramid ? TRUESTR : FALSESTR); sprintf(buf, codes[i].description, paramid ? TRUESTR : FALSESTR);
break; break;
case PARAM_SET:
sprintf(buf, codes[i].description, param2, paramid);
break;
case PARAM_NONE: case PARAM_NONE:
default: default:
strcpy(buf, codes[i].description); strcpy(buf, codes[i].description);
@ -1163,8 +1202,8 @@ static char *message(int messageid, int paramid, char *param2, bool isjson)
root = api_add_string(root, _STATUS, severity, false); root = api_add_string(root, _STATUS, severity, false);
root = api_add_time(root, "When", &when, false); root = api_add_time(root, "When", &when, false);
root = api_add_int(root, "Code", &messageid, false); root = api_add_int(root, "Code", &messageid, false);
root = api_add_string(root, "Msg", buf, false); root = api_add_escape(root, "Msg", buf, false);
root = api_add_string(root, "Description", opt_api_description, false); root = api_add_escape(root, "Description", opt_api_description, false);
root = print_data(root, ptr, isjson); root = print_data(root, ptr, isjson);
if (isjson) if (isjson)
@ -1178,8 +1217,8 @@ static char *message(int messageid, int paramid, char *param2, bool isjson)
int id = -1; int id = -1;
root = api_add_int(root, "Code", &id, false); root = api_add_int(root, "Code", &id, false);
sprintf(buf, "%d", messageid); sprintf(buf, "%d", messageid);
root = api_add_string(root, "Msg", buf, false); root = api_add_escape(root, "Msg", buf, false);
root = api_add_string(root, "Description", opt_api_description, false); root = api_add_escape(root, "Description", opt_api_description, false);
root = print_data(root, ptr, isjson); root = print_data(root, ptr, isjson);
if (isjson) if (isjson)
@ -1257,6 +1296,8 @@ static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
root = api_add_const(root, "OS", OSINFO, false); root = api_add_const(root, "OS", OSINFO, false);
root = api_add_bool(root, "Failover-Only", &opt_fail_only, false); root = api_add_bool(root, "Failover-Only", &opt_fail_only, false);
root = api_add_int(root, "ScanTime", &opt_scantime, false); root = api_add_int(root, "ScanTime", &opt_scantime, false);
root = api_add_int(root, "Queue", &opt_queue, false);
root = api_add_int(root, "Expiry", &opt_expiry, false);
root = print_data(root, buf, isjson); root = print_data(root, buf, isjson);
if (isjson) if (isjson)
@ -1264,6 +1305,7 @@ static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
strcat(io_buffer, buf); strcat(io_buffer, buf);
} }
#if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA)
static const char *status2str(enum alive status) static const char *status2str(enum alive status)
{ {
switch (status) { switch (status) {
@ -1281,6 +1323,7 @@ static const char *status2str(enum alive status)
return UNKNOWN; return UNKNOWN;
} }
} }
#endif
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
static void gpustatus(int gpu, bool isjson) static void gpustatus(int gpu, bool isjson)
@ -1341,6 +1384,10 @@ static void gpustatus(int gpu, bool isjson)
root = api_add_int(root, "Last Share Pool", &last_share_pool, false); root = api_add_int(root, "Last Share Pool", &last_share_pool, false);
root = api_add_time(root, "Last Share Time", &(cgpu->last_share_pool_time), false); root = api_add_time(root, "Last Share Time", &(cgpu->last_share_pool_time), false);
root = api_add_mhtotal(root, "Total MH", &(cgpu->total_mhashes), false); root = api_add_mhtotal(root, "Total MH", &(cgpu->total_mhashes), false);
root = api_add_int(root, "Diff1 Work", &(cgpu->diff1), false);
root = api_add_diff(root, "Difficulty Accepted", &(cgpu->diff_accepted), false);
root = api_add_diff(root, "Difficulty Rejected", &(cgpu->diff_rejected), false);
root = api_add_diff(root, "Last Share Difficulty", &(cgpu->last_share_diff), false);
root = print_data(root, buf, isjson); root = print_data(root, buf, isjson);
strcat(io_buffer, buf); strcat(io_buffer, buf);
@ -1424,6 +1471,10 @@ static void pgastatus(int pga, bool isjson)
root = api_add_time(root, "Last Share Time", &(cgpu->last_share_pool_time), false); root = api_add_time(root, "Last Share Time", &(cgpu->last_share_pool_time), false);
root = api_add_mhtotal(root, "Total MH", &(cgpu->total_mhashes), false); root = api_add_mhtotal(root, "Total MH", &(cgpu->total_mhashes), false);
root = api_add_freq(root, "Frequency", &frequency, false); root = api_add_freq(root, "Frequency", &frequency, false);
root = api_add_int(root, "Diff1 Work", &(cgpu->diff1), false);
root = api_add_diff(root, "Difficulty Accepted", &(cgpu->diff_accepted), false);
root = api_add_diff(root, "Difficulty Rejected", &(cgpu->diff_rejected), false);
root = api_add_diff(root, "Last Share Difficulty", &(cgpu->last_share_diff), false);
root = print_data(root, buf, isjson); root = print_data(root, buf, isjson);
strcat(io_buffer, buf); strcat(io_buffer, buf);
@ -1456,6 +1507,10 @@ static void cpustatus(int cpu, bool isjson)
root = api_add_int(root, "Last Share Pool", &last_share_pool, false); root = api_add_int(root, "Last Share Pool", &last_share_pool, false);
root = api_add_time(root, "Last Share Time", &(cgpu->last_share_pool_time), false); root = api_add_time(root, "Last Share Time", &(cgpu->last_share_pool_time), false);
root = api_add_mhtotal(root, "Total MH", &(cgpu->total_mhashes), false); root = api_add_mhtotal(root, "Total MH", &(cgpu->total_mhashes), false);
root = api_add_int(root, "Diff1 Work", &(cgpu->diff1), false);
root = api_add_diff(root, "Difficulty Accepted", &(cgpu->diff_accepted), false);
root = api_add_diff(root, "Difficulty Rejected", &(cgpu->diff_rejected), false);
root = api_add_diff(root, "Last Share Difficulty", &(cgpu->last_share_diff), false);
root = print_data(root, buf, isjson); root = print_data(root, buf, isjson);
strcat(io_buffer, buf); strcat(io_buffer, buf);
@ -1693,6 +1748,44 @@ static void pgadisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __
strcpy(io_buffer, message(MSG_PGADIS, id, NULL, isjson)); strcpy(io_buffer, message(MSG_PGADIS, id, NULL, isjson));
} }
static void pgaidentify(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
{
int numpga = numpgas();
int id;
if (numpga == 0) {
strcpy(io_buffer, message(MSG_PGANON, 0, NULL, isjson));
return;
}
if (param == NULL || *param == '\0') {
strcpy(io_buffer, message(MSG_MISID, 0, NULL, isjson));
return;
}
id = atoi(param);
if (id < 0 || id >= numpga) {
strcpy(io_buffer, message(MSG_INVPGA, id, NULL, isjson));
return;
}
int dev = pgadevice(id);
if (dev < 0) { // Should never happen
strcpy(io_buffer, message(MSG_INVPGA, id, NULL, isjson));
return;
}
struct cgpu_info *cgpu = devices[dev];
struct device_api *api = cgpu->api;
if (!api->identify_device)
strcpy(io_buffer, message(MSG_PGANOID, id, NULL, isjson));
else {
api->identify_device(cgpu);
strcpy(io_buffer, message(MSG_PGAIDENT, id, NULL, isjson));
}
}
#endif #endif
#ifdef WANT_CPUMINE #ifdef WANT_CPUMINE
@ -1790,6 +1883,17 @@ static void poolstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
root = api_add_escape(root, "User", pool->rpc_user, false); root = api_add_escape(root, "User", pool->rpc_user, false);
root = api_add_time(root, "Last Share Time", &(pool->last_share_time), false); root = api_add_time(root, "Last Share Time", &(pool->last_share_time), false);
root = api_add_int(root, "Diff1 Shares", &(pool->diff1), false); root = api_add_int(root, "Diff1 Shares", &(pool->diff1), false);
if (pool->rpc_proxy) {
root = api_add_const(root, "Proxy Type", proxytype(pool->rpc_proxytype), false);
root = api_add_escape(root, "Proxy", pool->rpc_proxy, false);
} else {
root = api_add_const(root, "Proxy Type", BLANK, false);
root = api_add_const(root, "Proxy", BLANK, false);
}
root = api_add_diff(root, "Difficulty Accepted", &(pool->diff_accepted), false);
root = api_add_diff(root, "Difficulty Rejected", &(pool->diff_rejected), false);
root = api_add_diff(root, "Difficulty Stale", &(pool->diff_stale), false);
root = api_add_diff(root, "Last Share Difficulty", &(pool->last_share_diff), false);
if (isjson && (i > 0)) if (isjson && (i > 0))
strcat(io_buffer, COMMA); strcat(io_buffer, COMMA);
@ -1842,6 +1946,9 @@ static void summary(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo
root = api_add_uint(root, "Network Blocks", &(new_blocks), false); root = api_add_uint(root, "Network Blocks", &(new_blocks), false);
root = api_add_mhtotal(root, "Total MH", &(total_mhashes_done), false); root = api_add_mhtotal(root, "Total MH", &(total_mhashes_done), false);
root = api_add_utility(root, "Work Utility", &(work_utility), false); root = api_add_utility(root, "Work Utility", &(work_utility), false);
root = api_add_diff(root, "Difficulty Accepted", &(total_diff_accepted), false);
root = api_add_diff(root, "Difficulty Rejected", &(total_diff_rejected), false);
root = api_add_diff(root, "Difficulty Stale", &(total_diff_stale), false);
root = print_data(root, buf, isjson); root = print_data(root, buf, isjson);
if (isjson) if (isjson)
@ -2554,6 +2661,7 @@ void notifystatus(int device, struct cgpu_info *cgpu, bool isjson, __maybe_unuse
root = api_add_int(root, "*Dev Over Heat", &(cgpu->dev_over_heat_count), false); root = api_add_int(root, "*Dev Over Heat", &(cgpu->dev_over_heat_count), false);
root = api_add_int(root, "*Dev Thermal Cutoff", &(cgpu->dev_thermal_cutoff_count), false); root = api_add_int(root, "*Dev Thermal Cutoff", &(cgpu->dev_thermal_cutoff_count), false);
root = api_add_int(root, "*Dev Comms Error", &(cgpu->dev_comms_error_count), false); root = api_add_int(root, "*Dev Comms Error", &(cgpu->dev_comms_error_count), false);
root = api_add_int(root, "*Dev Throttle", &(cgpu->dev_throttle_count), false);
if (isjson && (device > 0)) if (isjson && (device > 0))
strcat(io_buffer, COMMA); strcat(io_buffer, COMMA);
@ -2791,6 +2899,115 @@ static void minecoin(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo
strcat(io_buffer, buf); strcat(io_buffer, buf);
} }
static void debugstate(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
{
struct api_data *root = NULL;
char buf[TMPBUFSIZ];
if (param == NULL)
param = (char *)BLANK;
else
*param = tolower(*param);
switch(*param) {
case 's':
opt_realquiet = true;
break;
case 'q':
opt_quiet ^= true;
break;
case 'v':
opt_log_output ^= true;
if (opt_log_output)
opt_quiet = false;
break;
case 'd':
opt_debug ^= true;
opt_log_output = opt_debug;
if (opt_debug)
opt_quiet = false;
break;
case 'r':
opt_protocol ^= true;
if (opt_protocol)
opt_quiet = false;
break;
case 'p':
want_per_device_stats ^= true;
opt_log_output = want_per_device_stats;
break;
case 'n':
opt_log_output = false;
opt_debug = false;
opt_quiet = false;
opt_protocol = false;
want_per_device_stats = false;
opt_worktime = false;
break;
case 'w':
opt_worktime ^= true;
break;
default:
// anything else just reports the settings
break;
}
sprintf(io_buffer, isjson
? "%s," JSON_DEBUGSET
: "%s" _DEBUGSET ",",
message(MSG_DEBUGSET, 0, NULL, isjson));
root = api_add_bool(root, "Silent", &opt_realquiet, false);
root = api_add_bool(root, "Quiet", &opt_quiet, false);
root = api_add_bool(root, "Verbose", &opt_log_output, false);
root = api_add_bool(root, "Debug", &opt_debug, false);
root = api_add_bool(root, "RPCProto", &opt_protocol, false);
root = api_add_bool(root, "PerDevice", &want_per_device_stats, false);
root = api_add_bool(root, "WorkTime", &opt_worktime, false);
root = print_data(root, buf, isjson);
if (isjson)
strcat(buf, JSON_CLOSE);
strcat(io_buffer, buf);
}
static void setconfig(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
{
char *comma;
int value;
if (param == NULL || *param == '\0') {
strcpy(io_buffer, message(MSG_CONPAR, 0, NULL, isjson));
return;
}
comma = strchr(param, ',');
if (!comma) {
strcpy(io_buffer, message(MSG_CONVAL, 0, param, isjson));
return;
}
*(comma++) = '\0';
value = atoi(comma);
if (value < 0 || value > 9999) {
strcpy(io_buffer, message(MSG_INVNUM, value, param, isjson));
return;
}
if (strcasecmp(param, "queue") == 0)
opt_queue = value;
else if (strcasecmp(param, "scantime") == 0)
opt_scantime = value;
else if (strcasecmp(param, "expiry") == 0)
opt_expiry = value;
else {
strcpy(io_buffer, message(MSG_UNKCON, 0, param, isjson));
return;
}
strcpy(io_buffer, message(MSG_SETCONFIG, value, param, isjson));
}
static void checkcommand(__maybe_unused SOCKETTYPE c, char *param, bool isjson, char group); static void checkcommand(__maybe_unused SOCKETTYPE c, char *param, bool isjson, char group);
struct CMDS { struct CMDS {
@ -2813,6 +3030,7 @@ struct CMDS {
{ "pga", pgadev, false }, { "pga", pgadev, false },
{ "pgaenable", pgaenable, true }, { "pgaenable", pgaenable, true },
{ "pgadisable", pgadisable, true }, { "pgadisable", pgadisable, true },
{ "pgaidentify", pgaidentify, true },
#endif #endif
#ifdef WANT_CPUMINE #ifdef WANT_CPUMINE
{ "cpu", cpudev, false }, { "cpu", cpudev, false },
@ -2843,6 +3061,8 @@ struct CMDS {
{ "check", checkcommand, false }, { "check", checkcommand, false },
{ "failover-only", failoveronly, true }, { "failover-only", failoveronly, true },
{ "coin", minecoin, false }, { "coin", minecoin, false },
{ "debug", debugstate, true },
{ "setconfig", setconfig, true },
{ NULL, NULL, false } { NULL, NULL, false }
}; };

230
cgminer.c

@ -86,14 +86,14 @@ static char packagename[255];
bool opt_protocol; bool opt_protocol;
static bool opt_benchmark; static bool opt_benchmark;
bool have_longpoll; bool have_longpoll;
static bool want_per_device_stats; bool want_per_device_stats;
bool use_syslog; bool use_syslog;
bool opt_quiet; bool opt_quiet;
static bool opt_realquiet; bool opt_realquiet;
bool opt_loginput; bool opt_loginput;
const int opt_cutofftemp = 95; const int opt_cutofftemp = 95;
int opt_log_interval = 5; int opt_log_interval = 5;
static int opt_queue = 1; int opt_queue = 1;
int opt_scantime = 60; int opt_scantime = 60;
int opt_expiry = 120; int opt_expiry = 120;
int opt_bench_algo = -1; int opt_bench_algo = -1;
@ -142,6 +142,7 @@ bool opt_delaynet;
bool opt_disable_pool = true; bool opt_disable_pool = true;
char *opt_icarus_options = NULL; char *opt_icarus_options = NULL;
char *opt_icarus_timing = NULL; char *opt_icarus_timing = NULL;
bool opt_worktime;
char *opt_kernel_path; char *opt_kernel_path;
char *cgminer_path; char *cgminer_path;
@ -186,6 +187,7 @@ pthread_mutex_t control_lock;
int hw_errors; int hw_errors;
int total_accepted, total_rejected, total_diff1; int total_accepted, total_rejected, total_diff1;
int total_getworks, total_stale, total_discarded; int total_getworks, total_stale, total_discarded;
double total_diff_accepted, total_diff_rejected, total_diff_stale;
static int total_queued, staged_rollable; static int total_queued, staged_rollable;
unsigned int new_blocks; unsigned int new_blocks;
static unsigned int work_block; static unsigned int work_block;
@ -226,6 +228,7 @@ static struct block *blocks = NULL;
char *opt_socks_proxy = NULL; char *opt_socks_proxy = NULL;
static const char def_conf[] = "cgminer.conf"; static const char def_conf[] = "cgminer.conf";
static char *default_config;
static bool config_loaded; static bool config_loaded;
static int include_count; static int include_count;
#define JSON_INCLUDE_CONF "include" #define JSON_INCLUDE_CONF "include"
@ -357,7 +360,7 @@ static void sharelog(const char*disposition, const struct work*work)
thr_id = work->thr_id; thr_id = work->thr_id;
cgpu = thr_info[thr_id].cgpu; cgpu = thr_info[thr_id].cgpu;
pool = work->pool; pool = work->pool;
t = (unsigned long int)work->share_found_time; t = (unsigned long int)(work->tv_work_found.tv_sec);
target = bin2hex(work->target, sizeof(work->target)); target = bin2hex(work->target, sizeof(work->target));
if (unlikely(!target)) { if (unlikely(!target)) {
applog(LOG_ERR, "sharelog target OOM"); applog(LOG_ERR, "sharelog target OOM");
@ -419,6 +422,8 @@ static struct pool *add_pool(void)
/* Make sure the pool doesn't think we've been idle since time 0 */ /* Make sure the pool doesn't think we've been idle since time 0 */
pool->tv_idle.tv_sec = ~0UL; pool->tv_idle.tv_sec = ~0UL;
pool->rpc_proxy = NULL;
return pool; return pool;
} }
@ -547,6 +552,8 @@ static char *set_url(char *arg)
add_pool(); add_pool();
pool = pools[total_urls - 1]; pool = pools[total_urls - 1];
arg = get_proxy(arg, pool);
opt_set_charp(arg, &pool->rpc_url); opt_set_charp(arg, &pool->rpc_url);
if (strncmp(arg, "http://", 7) && if (strncmp(arg, "http://", 7) &&
strncmp(arg, "https://", 8)) { strncmp(arg, "https://", 8)) {
@ -1058,6 +1065,9 @@ static struct opt_table opt_config_table[] = {
OPT_WITH_ARG("--userpass|-O", OPT_WITH_ARG("--userpass|-O",
set_userpass, NULL, NULL, set_userpass, NULL, NULL,
"Username:Password pair for bitcoin JSON-RPC server"), "Username:Password pair for bitcoin JSON-RPC server"),
OPT_WITHOUT_ARG("--worktime",
opt_set_bool, &opt_worktime,
"Display extra work time debug information"),
OPT_WITH_ARG("--pools", OPT_WITH_ARG("--pools",
opt_set_bool, NULL, NULL, opt_hidden), opt_set_bool, NULL, NULL, opt_hidden),
OPT_ENDTABLE OPT_ENDTABLE
@ -1171,21 +1181,21 @@ static char *load_config(const char *arg, void __maybe_unused *unused)
return parse_config(config, true); return parse_config(config, true);
} }
static char *set_default_config(const char *arg)
{
opt_set_charp(arg, &default_config);
return NULL;
}
void default_save_file(char *filename);
static void load_default_config(void) static void load_default_config(void)
{ {
cnfbuf = malloc(PATH_MAX); cnfbuf = malloc(PATH_MAX);
#if defined(unix) default_save_file(cnfbuf);
if (getenv("HOME") && *getenv("HOME")) {
strcpy(cnfbuf, getenv("HOME"));
strcat(cnfbuf, "/");
} else
strcpy(cnfbuf, "");
strcat(cnfbuf, ".cgminer/");
#else
strcpy(cnfbuf, "");
#endif
strcat(cnfbuf, def_conf);
if (!access(cnfbuf, R_OK)) if (!access(cnfbuf, R_OK))
load_config(cnfbuf, NULL); load_config(cnfbuf, NULL);
else { else {
@ -1233,6 +1243,10 @@ static struct opt_table opt_cmdline_table[] = {
load_config, NULL, NULL, load_config, NULL, NULL,
"Load a JSON-format configuration file\n" "Load a JSON-format configuration file\n"
"See example.conf for an example configuration."), "See example.conf for an example configuration."),
OPT_WITH_ARG("--default-config",
set_default_config, NULL, NULL,
"Specify the filename of the default config file\n"
"Loaded at start and used when saving without a name."),
OPT_WITHOUT_ARG("--help|-h", OPT_WITHOUT_ARG("--help|-h",
opt_verusage_and_exit, NULL, opt_verusage_and_exit, NULL,
"Print this message"), "Print this message"),
@ -1755,7 +1769,9 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub
struct pool *pool = work->pool; struct pool *pool = work->pool;
int rolltime; int rolltime;
uint32_t *hash32; uint32_t *hash32;
struct timeval tv_submit, tv_submit_reply;
char hashshow[64+1] = ""; char hashshow[64+1] = "";
char worktime[200] = "";
#ifdef __BIG_ENDIAN__ #ifdef __BIG_ENDIAN__
int swapcounter = 0; int swapcounter = 0;
@ -1780,8 +1796,10 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub
applog(LOG_DEBUG, "DBG: sending %s submit RPC call: %s", pool->rpc_url, sd); applog(LOG_DEBUG, "DBG: sending %s submit RPC call: %s", pool->rpc_url, sd);
gettimeofday(&tv_submit, NULL);
/* issue JSON-RPC request */ /* issue JSON-RPC request */
val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, s, false, false, &rolltime, pool, true); val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, s, false, false, &rolltime, pool, true);
gettimeofday(&tv_submit_reply, NULL);
if (unlikely(!val)) { if (unlikely(!val)) {
applog(LOG_INFO, "submit_upstream_work json_rpc_call failed"); applog(LOG_INFO, "submit_upstream_work json_rpc_call failed");
if (!pool_tset(pool, &pool->submit_fail)) { if (!pool_tset(pool, &pool->submit_fail)) {
@ -1803,6 +1821,47 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub
sprintf(hashshow, "%08lx.%08lx%s", (unsigned long)(hash32[6]), (unsigned long)(hash32[5]), sprintf(hashshow, "%08lx.%08lx%s", (unsigned long)(hash32[6]), (unsigned long)(hash32[5]),
work->block? " BLOCK!" : ""); work->block? " BLOCK!" : "");
} }
if (opt_worktime) {
char workclone[20];
struct tm *tm, tm_getwork, tm_submit_reply;
double getwork_time = tdiff((struct timeval *)&(work->tv_getwork_reply),
(struct timeval *)&(work->tv_getwork));
double getwork_to_work = tdiff((struct timeval *)&(work->tv_work_start),
(struct timeval *)&(work->tv_getwork_reply));
double work_time = tdiff((struct timeval *)&(work->tv_work_found),
(struct timeval *)&(work->tv_work_start));
double work_to_submit = tdiff(&tv_submit,
(struct timeval *)&(work->tv_work_found));
double submit_time = tdiff(&tv_submit_reply, &tv_submit);
int diffplaces = 3;
tm = localtime(&(work->tv_getwork.tv_sec));
memcpy(&tm_getwork, tm, sizeof(struct tm));
tm = localtime(&(tv_submit_reply.tv_sec));
memcpy(&tm_submit_reply, tm, sizeof(struct tm));
if (work->clone) {
sprintf(workclone, "C:%1.3f",
tdiff((struct timeval *)&(work->tv_cloned),
(struct timeval *)&(work->tv_getwork_reply)));
}
else
strcpy(workclone, "O");
if (work->work_difficulty < 1)
diffplaces = 6;
sprintf(worktime, " <-%08lx.%08lx M:%c D:%1.*f G:%02d:%02d:%02d:%1.3f %s (%1.3f) W:%1.3f (%1.3f) S:%1.3f R:%02d:%02d:%02d",
(unsigned long)swab32(*(uint32_t *)&(work->data[opt_scrypt ? 32 : 28])),
(unsigned long)swab32(*(uint32_t *)&(work->data[opt_scrypt ? 28 : 24])),
work->getwork_mode, diffplaces, work->work_difficulty,
tm_getwork.tm_hour, tm_getwork.tm_min,
tm_getwork.tm_sec, getwork_time, workclone,
getwork_to_work, work_time, work_to_submit, submit_time,
tm_submit_reply.tm_hour, tm_submit_reply.tm_min,
tm_submit_reply.tm_sec);
}
} }
/* Theoretically threads could race when modifying accepted and /* Theoretically threads could race when modifying accepted and
@ -1812,18 +1871,23 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub
cgpu->accepted++; cgpu->accepted++;
total_accepted++; total_accepted++;
pool->accepted++; pool->accepted++;
cgpu->diff_accepted += work->work_difficulty;
total_diff_accepted += work->work_difficulty;
pool->diff_accepted += work->work_difficulty;
pool->seq_rejects = 0; pool->seq_rejects = 0;
cgpu->last_share_pool = pool->pool_no; cgpu->last_share_pool = pool->pool_no;
cgpu->last_share_pool_time = time(NULL); cgpu->last_share_pool_time = time(NULL);
cgpu->last_share_diff = work->work_difficulty;
pool->last_share_time = cgpu->last_share_pool_time; pool->last_share_time = cgpu->last_share_pool_time;
pool->last_share_diff = work->work_difficulty;
applog(LOG_DEBUG, "PROOF OF WORK RESULT: true (yay!!!)"); applog(LOG_DEBUG, "PROOF OF WORK RESULT: true (yay!!!)");
if (!QUIET) { if (!QUIET) {
if (total_pools > 1) if (total_pools > 1)
applog(LOG_NOTICE, "Accepted %s %s %d pool %d %s", applog(LOG_NOTICE, "Accepted %s %s %d pool %d %s%s",
hashshow, cgpu->api->name, cgpu->device_id, work->pool->pool_no, resubmit ? "(resubmit)" : ""); hashshow, cgpu->api->name, cgpu->device_id, work->pool->pool_no, resubmit ? "(resubmit)" : "", worktime);
else else
applog(LOG_NOTICE, "Accepted %s %s %d %s", applog(LOG_NOTICE, "Accepted %s %s %d %s%s",
hashshow, cgpu->api->name, cgpu->device_id, resubmit ? "(resubmit)" : ""); hashshow, cgpu->api->name, cgpu->device_id, resubmit ? "(resubmit)" : "", worktime);
} }
sharelog("accept", work); sharelog("accept", work);
if (opt_shares && total_accepted >= opt_shares) { if (opt_shares && total_accepted >= opt_shares) {
@ -1845,6 +1909,9 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub
cgpu->rejected++; cgpu->rejected++;
total_rejected++; total_rejected++;
pool->rejected++; pool->rejected++;
cgpu->diff_rejected += work->work_difficulty;
total_diff_rejected += work->work_difficulty;
pool->diff_rejected += work->work_difficulty;
pool->seq_rejects++; pool->seq_rejects++;
applog(LOG_DEBUG, "PROOF OF WORK RESULT: false (booooo)"); applog(LOG_DEBUG, "PROOF OF WORK RESULT: false (booooo)");
if (!QUIET) { if (!QUIET) {
@ -1872,8 +1939,8 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub
} else } else
strcpy(reason, ""); strcpy(reason, "");
applog(LOG_NOTICE, "Rejected %s %s %d %s%s %s", applog(LOG_NOTICE, "Rejected %s %s %d %s%s %s%s",
hashshow, cgpu->api->name, cgpu->device_id, where, reason, resubmit ? "(resubmit)" : ""); hashshow, cgpu->api->name, cgpu->device_id, where, reason, resubmit ? "(resubmit)" : "", worktime);
sharelog(disposition, work); sharelog(disposition, work);
} }
@ -1973,6 +2040,25 @@ static inline struct pool *select_pool(bool lagging)
return pool; return pool;
} }
static double DIFFEXACTONE = 26959946667150639794667015087019630673637144422540572481103610249216.0;
/*
* Calculate the work share difficulty
*/
static void calc_diff(struct work *work)
{
double targ;
int i;
targ = 0;
for (i = 31; i >= 0; i--) {
targ *= 256;
targ += work->target[i];
}
work->work_difficulty = DIFFEXACTONE / (targ ? : DIFFEXACTONE);
}
static void get_benchmark_work(struct work *work) static void get_benchmark_work(struct work *work)
{ {
// Use a random work block pulled from a pool // Use a random work block pulled from a pool
@ -1985,13 +2071,17 @@ static void get_benchmark_work(struct work *work)
memcpy(work, &bench_block, min_size); memcpy(work, &bench_block, min_size);
work->mandatory = true; work->mandatory = true;
work->pool = pools[0]; work->pool = pools[0];
gettimeofday(&(work->tv_getwork), NULL);
memcpy(&(work->tv_getwork_reply), &(work->tv_getwork), sizeof(struct timeval));
work->getwork_mode = GETWORK_MODE_BENCHMARK;
calc_diff(work);
} }
static bool get_upstream_work(struct work *work, CURL *curl) static bool get_upstream_work(struct work *work, CURL *curl)
{ {
struct pool *pool = work->pool; struct pool *pool = work->pool;
struct cgminer_pool_stats *pool_stats = &(pool->cgminer_pool_stats); struct cgminer_pool_stats *pool_stats = &(pool->cgminer_pool_stats);
struct timeval tv_start, tv_end, tv_elapsed; struct timeval tv_elapsed;
json_t *val = NULL; json_t *val = NULL;
bool rc = false; bool rc = false;
char *url; char *url;
@ -2000,7 +2090,7 @@ static bool get_upstream_work(struct work *work, CURL *curl)
url = pool->rpc_url; url = pool->rpc_url;
gettimeofday(&tv_start, NULL); gettimeofday(&(work->tv_getwork), NULL);
val = json_rpc_call(curl, url, pool->rpc_userpass, rpc_req, false, val = json_rpc_call(curl, url, pool->rpc_userpass, rpc_req, false,
false, &work->rolltime, pool, false); false, &work->rolltime, pool, false);
@ -2013,8 +2103,8 @@ static bool get_upstream_work(struct work *work, CURL *curl)
} else } else
applog(LOG_DEBUG, "Failed json_rpc_call in get_upstream_work"); applog(LOG_DEBUG, "Failed json_rpc_call in get_upstream_work");
gettimeofday(&tv_end, NULL); gettimeofday(&(work->tv_getwork_reply), NULL);
timersub(&tv_end, &tv_start, &tv_elapsed); timersub(&(work->tv_getwork_reply), &(work->tv_getwork), &tv_elapsed);
pool_stats->getwork_wait_rolling += ((double)tv_elapsed.tv_sec + ((double)tv_elapsed.tv_usec / 1000000)) * 0.63; pool_stats->getwork_wait_rolling += ((double)tv_elapsed.tv_sec + ((double)tv_elapsed.tv_usec / 1000000)) * 0.63;
pool_stats->getwork_wait_rolling /= 1.63; pool_stats->getwork_wait_rolling /= 1.63;
@ -2031,6 +2121,8 @@ static bool get_upstream_work(struct work *work, CURL *curl)
work->pool = pool; work->pool = pool;
work->longpoll = false; work->longpoll = false;
work->getwork_mode = GETWORK_MODE_POOL;
calc_diff(work);
total_getworks++; total_getworks++;
pool->getwork_requested++; pool->getwork_requested++;
@ -2339,6 +2431,7 @@ static struct work *make_clone(struct work *work)
memcpy(work_clone, work, sizeof(struct work)); memcpy(work_clone, work, sizeof(struct work));
work_clone->clone = true; work_clone->clone = true;
gettimeofday((struct timeval *)&(work_clone->tv_cloned), NULL);
work_clone->longpoll = false; work_clone->longpoll = false;
work_clone->mandatory = false; work_clone->mandatory = false;
/* Make cloned work appear slightly older to bias towards keeping the /* Make cloned work appear slightly older to bias towards keeping the
@ -2537,6 +2630,8 @@ static void *submit_work_thread(void *userdata)
sharelog("discard", work); sharelog("discard", work);
total_stale++; total_stale++;
pool->stale_shares++; pool->stale_shares++;
total_diff_stale += work->work_difficulty;
pool->diff_stale += work->work_difficulty;
goto out; goto out;
} }
work->stale = true; work->stale = true;
@ -2550,6 +2645,8 @@ static void *submit_work_thread(void *userdata)
applog(LOG_NOTICE, "Share became stale while retrying submit, discarding"); applog(LOG_NOTICE, "Share became stale while retrying submit, discarding");
total_stale++; total_stale++;
pool->stale_shares++; pool->stale_shares++;
total_diff_stale += work->work_difficulty;
pool->diff_stale += work->work_difficulty;
break; break;
} }
@ -2996,6 +3093,8 @@ static void display_pool_summary(struct pool *pool)
wlog(" Share submissions: %d\n", pool->accepted + pool->rejected); wlog(" Share submissions: %d\n", pool->accepted + pool->rejected);
wlog(" Accepted shares: %d\n", pool->accepted); wlog(" Accepted shares: %d\n", pool->accepted);
wlog(" Rejected shares: %d\n", pool->rejected); wlog(" Rejected shares: %d\n", pool->rejected);
wlog(" Accepted difficulty shares: %1.f\n", pool->diff_accepted);
wlog(" Rejected difficulty shares: %1.f\n", pool->diff_rejected);
if (pool->accepted || pool->rejected) if (pool->accepted || pool->rejected)
wlog(" Reject ratio: %.1f%%\n", (double)(pool->rejected * 100) / (double)(pool->accepted + pool->rejected)); wlog(" Reject ratio: %.1f%%\n", (double)(pool->rejected * 100) / (double)(pool->accepted + pool->rejected));
efficiency = pool->getwork_requested ? pool->accepted * 100.0 / pool->getwork_requested : 0.0; efficiency = pool->getwork_requested ? pool->accepted * 100.0 / pool->getwork_requested : 0.0;
@ -3089,7 +3188,11 @@ void write_config(FILE *fcfg)
/* Write pool values */ /* Write pool values */
fputs("{\n\"pools\" : [", fcfg); fputs("{\n\"pools\" : [", fcfg);
for(i = 0; i < total_pools; i++) { for(i = 0; i < total_pools; i++) {
fprintf(fcfg, "%s\n\t{\n\t\t\"url\" : \"%s\",", i > 0 ? "," : "", json_escape(pools[i]->rpc_url)); fprintf(fcfg, "%s\n\t{\n\t\t\"url\" : \"%s%s%s%s\",", i > 0 ? "," : "",
pools[i]->rpc_proxy ? json_escape((char *)proxytype(pools[i]->rpc_proxytype)) : "",
pools[i]->rpc_proxy ? json_escape(pools[i]->rpc_proxy) : "",
pools[i]->rpc_proxy ? "|" : "",
json_escape(pools[i]->rpc_url));
fprintf(fcfg, "\n\t\t\"user\" : \"%s\",", json_escape(pools[i]->rpc_user)); fprintf(fcfg, "\n\t\t\"user\" : \"%s\",", json_escape(pools[i]->rpc_user));
fprintf(fcfg, "\n\t\t\"pass\" : \"%s\"\n\t}", json_escape(pools[i]->rpc_pass)); fprintf(fcfg, "\n\t\t\"pass\" : \"%s\"\n\t}", json_escape(pools[i]->rpc_pass));
} }
@ -3412,12 +3515,13 @@ static void display_options(void)
clear_logwin(); clear_logwin();
retry: retry:
wlogprint("[N]ormal [C]lear [S]ilent mode (disable all output)\n"); wlogprint("[N]ormal [C]lear [S]ilent mode (disable all output)\n");
wlogprint("[D]ebug:%s\n[P]er-device:%s\n[Q]uiet:%s\n[V]erbose:%s\n[R]PC debug:%s\n[L]og interval:%d\n", wlogprint("[D]ebug:%s\n[P]er-device:%s\n[Q]uiet:%s\n[V]erbose:%s\n[R]PC debug:%s\n[W]orkTime details:%s\n[L]og interval:%d\n",
opt_debug ? "on" : "off", opt_debug ? "on" : "off",
want_per_device_stats? "on" : "off", want_per_device_stats? "on" : "off",
opt_quiet ? "on" : "off", opt_quiet ? "on" : "off",
opt_log_output ? "on" : "off", opt_log_output ? "on" : "off",
opt_protocol ? "on" : "off", opt_protocol ? "on" : "off",
opt_worktime ? "on" : "off",
opt_log_interval); opt_log_interval);
wlogprint("Select an option or any other key to return\n"); wlogprint("Select an option or any other key to return\n");
input = getch(); input = getch();
@ -3470,6 +3574,10 @@ retry:
goto retry; goto retry;
} else if (!strncasecmp(&input, "s", 1)) { } else if (!strncasecmp(&input, "s", 1)) {
opt_realquiet = true; opt_realquiet = true;
} else if (!strncasecmp(&input, "w", 1)) {
opt_worktime ^= true;
wlogprint("WorkTime details %s\n", opt_worktime ? "enabled" : "disabled");
goto retry;
} else } else
clear_logwin(); clear_logwin();
@ -3480,6 +3588,11 @@ retry:
void default_save_file(char *filename) void default_save_file(char *filename)
{ {
if (default_config && *default_config) {
strcpy(filename, default_config);
return;
}
#if defined(unix) #if defined(unix)
if (getenv("HOME") && *getenv("HOME")) { if (getenv("HOME") && *getenv("HOME")) {
strcpy(filename, getenv("HOME")); strcpy(filename, getenv("HOME"));
@ -3794,6 +3907,7 @@ static void *longpoll_thread(void *userdata);
static bool pool_active(struct pool *pool, bool pinging) static bool pool_active(struct pool *pool, bool pinging)
{ {
struct timeval tv_getwork, tv_getwork_reply;
bool ret = false; bool ret = false;
json_t *val; json_t *val;
CURL *curl; CURL *curl;
@ -3806,8 +3920,10 @@ static bool pool_active(struct pool *pool, bool pinging)
} }
applog(LOG_INFO, "Testing pool %s", pool->rpc_url); applog(LOG_INFO, "Testing pool %s", pool->rpc_url);
gettimeofday(&tv_getwork, NULL);
val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, rpc_req, val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, rpc_req,
true, false, &rolltime, pool, false); true, false, &rolltime, pool, false);
gettimeofday(&tv_getwork_reply, NULL);
if (val) { if (val) {
struct work *work = make_work(); struct work *work = make_work();
@ -3819,6 +3935,10 @@ static bool pool_active(struct pool *pool, bool pinging)
pool->pool_no, pool->rpc_url); pool->pool_no, pool->rpc_url);
work->pool = pool; work->pool = pool;
work->rolltime = rolltime; work->rolltime = rolltime;
memcpy(&(work->tv_getwork), &tv_getwork, sizeof(struct timeval));
memcpy(&(work->tv_getwork_reply), &tv_getwork_reply, sizeof(struct timeval));
work->getwork_mode = GETWORK_MODE_TESTPOOL;
calc_diff(work);
applog(LOG_DEBUG, "Pushing pooltest work to base pool"); applog(LOG_DEBUG, "Pushing pooltest work to base pool");
tq_push(thr_info[stage_thr_id].q, work); tq_push(thr_info[stage_thr_id].q, work);
@ -4110,7 +4230,7 @@ out:
work->mined = true; work->mined = true;
} }
bool submit_work_sync(struct thr_info *thr, const struct work *work_in) bool submit_work_sync(struct thr_info *thr, const struct work *work_in, struct timeval *tv_work_found)
{ {
struct workio_cmd *wc; struct workio_cmd *wc;
@ -4125,7 +4245,8 @@ bool submit_work_sync(struct thr_info *thr, const struct work *work_in)
wc->cmd = WC_SUBMIT_WORK; wc->cmd = WC_SUBMIT_WORK;
wc->thr = thr; wc->thr = thr;
memcpy(wc->work, work_in, sizeof(*work_in)); memcpy(wc->work, work_in, sizeof(*work_in));
wc->work->share_found_time = time(NULL); if (tv_work_found)
memcpy(&(wc->work->tv_work_found), tv_work_found, sizeof(struct timeval));
applog(LOG_DEBUG, "Pushing submit work to work thread"); applog(LOG_DEBUG, "Pushing submit work to work thread");
@ -4141,7 +4262,7 @@ err_out:
return false; return false;
} }
bool hashtest(const struct work *work) static bool hashtest(struct thr_info *thr, const struct work *work)
{ {
uint32_t *data32 = (uint32_t *)(work->data); uint32_t *data32 = (uint32_t *)(work->data);
unsigned char swap[128]; unsigned char swap[128];
@ -4162,11 +4283,22 @@ bool hashtest(const struct work *work)
memcpy((void*)work->hash, hash2, 32); memcpy((void*)work->hash, hash2, 32);
return fulltest(work->hash, work->target); if (hash2_32[7] != 0) {
applog(LOG_WARNING, "%s%d: invalid nonce - HW error",
thr->cgpu->api->name, thr->cgpu->device_id);
hw_errors++;
thr->cgpu->hw_errors++;
return false;
}
bool test = fulltest(work->hash, work->target);
if (!test)
applog(LOG_INFO, "Share below target");
return test;
} }
bool test_nonce(struct work *work, uint32_t nonce) static bool test_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
{ {
if (opt_scrypt) { if (opt_scrypt) {
uint32_t *work_nonce = (uint32_t *)(work->data + 64 + 12); uint32_t *work_nonce = (uint32_t *)(work->data + 64 + 12);
@ -4180,21 +4312,24 @@ bool test_nonce(struct work *work, uint32_t nonce)
work->data[64 + 12 + 2] = (nonce >> 16) & 0xff; work->data[64 + 12 + 2] = (nonce >> 16) & 0xff;
work->data[64 + 12 + 3] = (nonce >> 24) & 0xff; work->data[64 + 12 + 3] = (nonce >> 24) & 0xff;
return hashtest(work); return hashtest(thr, work);
} }
bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce) bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
{ {
struct timeval tv_work_found;
gettimeofday(&tv_work_found, NULL);
total_diff1++; total_diff1++;
thr->cgpu->diff1++;
work->pool->diff1++; work->pool->diff1++;
/* Do one last check before attempting to submit the work */ /* Do one last check before attempting to submit the work */
/* Side effect: sets work->data for us */ /* Side effect: sets work->data for us */
if (!test_nonce(work, nonce)) { if (!test_nonce(thr, work, nonce))
applog(LOG_INFO, "Share below target");
return true; return true;
}
return submit_work_sync(thr, work); return submit_work_sync(thr, work, &tv_work_found);
} }
static inline bool abandon_work(struct work *work, struct timeval *wdiff, uint64_t hashes) static inline bool abandon_work(struct work *work, struct timeval *wdiff, uint64_t hashes)
@ -4309,6 +4444,8 @@ void *miner_thread(void *userdata)
} }
pool_stats->getwork_calls++; pool_stats->getwork_calls++;
gettimeofday(&(work->tv_work_start), NULL);
thread_reportin(mythr); thread_reportin(mythr);
hashes = api->scanhash(mythr, work, work->blk.nonce + max_nonce); hashes = api->scanhash(mythr, work, work->blk.nonce + max_nonce);
thread_reportin(mythr); thread_reportin(mythr);
@ -4405,7 +4542,7 @@ enum {
}; };
/* Stage another work item from the work returned in a longpoll */ /* Stage another work item from the work returned in a longpoll */
static void convert_to_work(json_t *val, int rolltime, struct pool *pool) static void convert_to_work(json_t *val, int rolltime, struct pool *pool, struct timeval *tv_lp, struct timeval *tv_lp_reply)
{ {
struct work *work; struct work *work;
bool rc; bool rc;
@ -4421,6 +4558,10 @@ static void convert_to_work(json_t *val, int rolltime, struct pool *pool)
work->pool = pool; work->pool = pool;
work->rolltime = rolltime; work->rolltime = rolltime;
work->longpoll = true; work->longpoll = true;
memcpy(&(work->tv_getwork), tv_lp, sizeof(struct timeval));
memcpy(&(work->tv_getwork_reply), tv_lp_reply, sizeof(struct timeval));
work->getwork_mode = GETWORK_MODE_LP;
calc_diff(work);
if (pool->enabled == POOL_REJECTING) if (pool->enabled == POOL_REJECTING)
work->mandatory = true; work->mandatory = true;
@ -4489,7 +4630,7 @@ static void *longpoll_thread(void *userdata)
/* This *pool is the source of the actual longpoll, not the pool we've /* This *pool is the source of the actual longpoll, not the pool we've
* tied it to */ * tied it to */
struct pool *pool = NULL; struct pool *pool = NULL;
struct timeval start, end; struct timeval start, reply, end;
CURL *curl = NULL; CURL *curl = NULL;
int failures = 0; int failures = 0;
int rolltime; int rolltime;
@ -4534,13 +4675,16 @@ retry_pool:
curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1); curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
val = json_rpc_call(curl, pool->lp_url, pool->rpc_userpass, rpc_req, val = json_rpc_call(curl, pool->lp_url, pool->rpc_userpass, rpc_req,
false, true, &rolltime, pool, false); false, true, &rolltime, pool, false);
gettimeofday(&reply, NULL);
if (likely(val)) { if (likely(val)) {
soval = json_object_get(json_object_get(val, "result"), "submitold"); soval = json_object_get(json_object_get(val, "result"), "submitold");
if (soval) if (soval)
pool->submit_old = json_is_true(soval); pool->submit_old = json_is_true(soval);
else else
pool->submit_old = false; pool->submit_old = false;
convert_to_work(val, rolltime, pool); convert_to_work(val, rolltime, pool, &start, &reply);
failures = 0; failures = 0;
json_decref(val); json_decref(val);
} else { } else {
@ -4867,6 +5011,8 @@ static void print_summary(void)
applog(LOG_WARNING, "Share submissions: %d", total_accepted + total_rejected); applog(LOG_WARNING, "Share submissions: %d", total_accepted + total_rejected);
applog(LOG_WARNING, "Accepted shares: %d", total_accepted); applog(LOG_WARNING, "Accepted shares: %d", total_accepted);
applog(LOG_WARNING, "Rejected shares: %d", total_rejected); applog(LOG_WARNING, "Rejected shares: %d", total_rejected);
applog(LOG_WARNING, "Accepted difficulty shares: %1.f", total_diff_accepted);
applog(LOG_WARNING, "Rejected difficulty shares: %1.f", total_diff_rejected);
if (total_accepted || total_rejected) if (total_accepted || total_rejected)
applog(LOG_WARNING, "Reject ratio: %.1f%%", (double)(total_rejected * 100) / (double)(total_accepted + total_rejected)); applog(LOG_WARNING, "Reject ratio: %.1f%%", (double)(total_rejected * 100) / (double)(total_accepted + total_rejected));
applog(LOG_WARNING, "Hardware errors: %d", hw_errors); applog(LOG_WARNING, "Hardware errors: %d", hw_errors);
@ -4892,6 +5038,8 @@ static void print_summary(void)
applog(LOG_WARNING, " Share submissions: %d", pool->accepted + pool->rejected); applog(LOG_WARNING, " Share submissions: %d", pool->accepted + pool->rejected);
applog(LOG_WARNING, " Accepted shares: %d", pool->accepted); applog(LOG_WARNING, " Accepted shares: %d", pool->accepted);
applog(LOG_WARNING, " Rejected shares: %d", pool->rejected); applog(LOG_WARNING, " Rejected shares: %d", pool->rejected);
applog(LOG_WARNING, " Accepted difficulty shares: %1.f", pool->diff_accepted);
applog(LOG_WARNING, " Rejected difficulty shares: %1.f", pool->diff_rejected);
if (pool->accepted || pool->rejected) if (pool->accepted || pool->rejected)
applog(LOG_WARNING, " Reject ratio: %.1f%%", (double)(pool->rejected * 100) / (double)(pool->accepted + pool->rejected)); applog(LOG_WARNING, " Reject ratio: %.1f%%", (double)(pool->rejected * 100) / (double)(pool->accepted + pool->rejected));
efficiency = pool->getwork_requested ? pool->accepted * 100.0 / pool->getwork_requested : 0.0; efficiency = pool->getwork_requested ? pool->accepted * 100.0 / pool->getwork_requested : 0.0;
@ -4988,6 +5136,8 @@ void add_pool_details(bool live, char *url, char *user, char *pass)
pool = add_pool(); pool = add_pool();
url = get_proxy(url, pool);
pool->rpc_url = url; pool->rpc_url = url;
pool->rpc_user = user; pool->rpc_user = user;
pool->rpc_pass = pass; pool->rpc_pass = pass;

62
driver-bitforce.c

@ -45,8 +45,8 @@ enum {
#endif /* WIN32 */ #endif /* WIN32 */
#include "compat.h" #include "compat.h"
#include "fpgautils.h"
#include "miner.h" #include "miner.h"
#include "fpgautils.h"
#define BITFORCE_SLEEP_MS 500 #define BITFORCE_SLEEP_MS 500
#define BITFORCE_TIMEOUT_S 7 #define BITFORCE_TIMEOUT_S 7
@ -99,6 +99,7 @@ static bool bitforce_detect_one(const char *devpath)
} }
BFwrite(fdDev, "ZGX", 3); BFwrite(fdDev, "ZGX", 3);
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
if (unlikely(!pdevbuf[0])) { if (unlikely(!pdevbuf[0])) {
applog(LOG_ERR, "BFL: Error reading/timeout (ZGX)"); applog(LOG_ERR, "BFL: Error reading/timeout (ZGX)");
@ -229,7 +230,7 @@ static int bitforce_detect_auto(void)
static void bitforce_detect(void) static void bitforce_detect(void)
{ {
serial_detect_auto(bitforce_api.dname, bitforce_detect_one, bitforce_detect_auto); serial_detect_auto(&bitforce_api, bitforce_detect_one, bitforce_detect_auto);
} }
static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce) static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
@ -309,6 +310,7 @@ void bitforce_init(struct cgpu_info *bitforce)
do { do {
BFwrite(fdDev, "ZGX", 3); BFwrite(fdDev, "ZGX", 3);
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
if (unlikely(!pdevbuf[0])) { if (unlikely(!pdevbuf[0])) {
@ -338,6 +340,37 @@ void bitforce_init(struct cgpu_info *bitforce)
mutex_unlock(&bitforce->device_mutex); mutex_unlock(&bitforce->device_mutex);
} }
static void bitforce_flash_led(struct cgpu_info *bitforce)
{
int fdDev = bitforce->device_fd;
if (!fdDev)
return;
/* Do not try to flash the led if we're polling for a result to
* minimise the chance of interleaved results */
if (bitforce->polling)
return;
/* It is not critical flashing the led so don't get stuck if we
* can't grab the mutex here */
if (mutex_trylock(&bitforce->device_mutex))
return;
BFwrite(fdDev, "ZMX", 3);
/* Once we've tried - don't do it until told to again */
bitforce->flash_led = false;
/* However, this stops anything else getting a reply
* So best to delay any other access to the BFL */
sleep(4);
mutex_unlock(&bitforce->device_mutex);
return; // nothing is returned by the BFL
}
static bool bitforce_get_temp(struct cgpu_info *bitforce) static bool bitforce_get_temp(struct cgpu_info *bitforce)
{ {
int fdDev = bitforce->device_fd; int fdDev = bitforce->device_fd;
@ -348,16 +381,23 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
return false; return false;
/* Do not try to get the temperature if we're polling for a result to /* Do not try to get the temperature if we're polling for a result to
* minimise the change of interleaved results */ * minimise the chance of interleaved results */
if (bitforce->polling) if (bitforce->polling)
return true; return true;
// Flash instead of Temp - doing both can be too slow
if (bitforce->flash_led) {
bitforce_flash_led(bitforce);
return true;
}
/* It is not critical getting temperature so don't get stuck if we /* It is not critical getting temperature so don't get stuck if we
* can't grab the mutex here */ * can't grab the mutex here */
if (mutex_trylock(&bitforce->device_mutex)) if (mutex_trylock(&bitforce->device_mutex))
return false; return false;
BFwrite(fdDev, "ZLX", 3); BFwrite(fdDev, "ZLX", 3);
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
mutex_unlock(&bitforce->device_mutex); mutex_unlock(&bitforce->device_mutex);
@ -385,11 +425,14 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
/* Use the temperature monitor as a kind of watchdog for when /* Use the temperature monitor as a kind of watchdog for when
* our responses are out of sync and flush the buffer to * our responses are out of sync and flush the buffer to
* hopefully recover */ * hopefully recover */
applog(LOG_WARNING, "BFL%i: Garbled response probably throttling, clearing buffer"); applog(LOG_WARNING, "BFL%i: Garbled response probably throttling, clearing buffer", bitforce->device_id);
bitforce->device_last_not_well = time(NULL);
bitforce->device_not_well_reason = REASON_DEV_THROTTLE;
bitforce->dev_throttle_count++;
/* Count throttling episodes as hardware errors */ /* Count throttling episodes as hardware errors */
bitforce->hw_errors++; bitforce->hw_errors++;
bitforce_clear_buffer(bitforce); bitforce_clear_buffer(bitforce);
return false;; return false;
} }
return true; return true;
@ -411,6 +454,7 @@ re_send:
BFwrite(fdDev, "ZPX", 3); BFwrite(fdDev, "ZPX", 3);
else else
BFwrite(fdDev, "ZDX", 3); BFwrite(fdDev, "ZDX", 3);
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
if (!pdevbuf[0] || !strncasecmp(pdevbuf, "B", 1)) { if (!pdevbuf[0] || !strncasecmp(pdevbuf, "B", 1)) {
mutex_unlock(&bitforce->device_mutex); mutex_unlock(&bitforce->device_mutex);
@ -450,6 +494,7 @@ re_send:
BFwrite(fdDev, ob, 68); BFwrite(fdDev, ob, 68);
} }
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
mutex_unlock(&bitforce->device_mutex); mutex_unlock(&bitforce->device_mutex);
@ -493,6 +538,7 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
mutex_lock(&bitforce->device_mutex); mutex_lock(&bitforce->device_mutex);
BFwrite(fdDev, "ZFX", 3); BFwrite(fdDev, "ZFX", 3);
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
mutex_unlock(&bitforce->device_mutex); mutex_unlock(&bitforce->device_mutex);
@ -637,6 +683,11 @@ static bool bitforce_get_stats(struct cgpu_info *bitforce)
return bitforce_get_temp(bitforce); return bitforce_get_temp(bitforce);
} }
static void bitforce_identify(struct cgpu_info *bitforce)
{
bitforce->flash_led = true;
}
static bool bitforce_thread_init(struct thr_info *thr) static bool bitforce_thread_init(struct thr_info *thr)
{ {
struct cgpu_info *bitforce = thr->cgpu; struct cgpu_info *bitforce = thr->cgpu;
@ -673,6 +724,7 @@ struct device_api bitforce_api = {
.reinit_device = bitforce_init, .reinit_device = bitforce_init,
.get_statline_before = get_bitforce_statline_before, .get_statline_before = get_bitforce_statline_before,
.get_stats = bitforce_get_stats, .get_stats = bitforce_get_stats,
.identify_device = bitforce_identify,
.thread_prepare = bitforce_thread_prepare, .thread_prepare = bitforce_thread_prepare,
.thread_init = bitforce_thread_init, .thread_init = bitforce_thread_init,
.scanhash = bitforce_scanhash, .scanhash = bitforce_scanhash,

4
driver-cpu.c

@ -75,7 +75,7 @@ static inline void affine_to_cpu(int id, int cpu)
/* TODO: resolve externals */ /* TODO: resolve externals */
extern bool submit_work_sync(struct thr_info *thr, const struct work *work_in); extern bool submit_work_sync(struct thr_info *thr, const struct work *work_in, struct timeval *tv);
extern char *set_int_range(const char *arg, int *i, int min, int max); extern char *set_int_range(const char *arg, int *i, int min, int max);
extern int dev_from_id(int thr_id); extern int dev_from_id(int thr_id);
@ -827,7 +827,7 @@ CPUSearch:
/* if nonce found, submit work */ /* if nonce found, submit work */
if (unlikely(rc)) { if (unlikely(rc)) {
applog(LOG_DEBUG, "CPU %d found something?", dev_from_id(thr_id)); applog(LOG_DEBUG, "CPU %d found something?", dev_from_id(thr_id));
if (unlikely(!submit_work_sync(thr, work))) { if (unlikely(!submit_work_sync(thr, work, NULL))) {
applog(LOG_ERR, "Failed to submit_work_sync in miner_thread %d", thr_id); applog(LOG_ERR, "Failed to submit_work_sync in miner_thread %d", thr_id);
} }
work->blk.nonce = last_nonce + 1; work->blk.nonce = last_nonce + 1;

12
driver-icarus.c

@ -49,8 +49,8 @@
#endif #endif
#include "elist.h" #include "elist.h"
#include "fpgautils.h"
#include "miner.h" #include "miner.h"
#include "fpgautils.h"
// The serial I/O speed - Linux uses a define 'B115200' in bits/termios.h // The serial I/O speed - Linux uses a define 'B115200' in bits/termios.h
#define ICARUS_IO_SPEED 115200 #define ICARUS_IO_SPEED 115200
@ -598,7 +598,7 @@ static bool icarus_detect_one(const char *devpath)
static void icarus_detect() static void icarus_detect()
{ {
serial_detect(icarus_api.dname, icarus_detect_one); serial_detect(&icarus_api, icarus_detect_one);
} }
static bool icarus_prepare(struct thr_info *thr) static bool icarus_prepare(struct thr_info *thr)
@ -639,7 +639,8 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
struct timeval tv_start, tv_finish, elapsed; struct timeval tv_start, tv_finish, elapsed;
struct timeval tv_history_start, tv_history_finish; struct timeval tv_history_start, tv_history_finish;
double Ti, Xi; double Ti, Xi;
int i; int curr_hw_errors, i;
bool was_hw_error;
struct ICARUS_HISTORY *history0, *history; struct ICARUS_HISTORY *history0, *history;
int count; int count;
@ -712,7 +713,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
nonce = swab32(nonce); nonce = swab32(nonce);
#endif #endif
curr_hw_errors = icarus->hw_errors;
submit_nonce(thr, work, nonce); submit_nonce(thr, work, nonce);
was_hw_error = (curr_hw_errors > icarus->hw_errors);
hash_count = (nonce & info->nonce_mask); hash_count = (nonce & info->nonce_mask);
hash_count++; hash_count++;
@ -726,8 +729,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
icarus->device_id, nonce, hash_count, elapsed.tv_sec, elapsed.tv_usec); icarus->device_id, nonce, hash_count, elapsed.tv_sec, elapsed.tv_usec);
} }
// ignore possible end condition values // ignore possible end condition values ... and hw errors
if (info->do_icarus_timing if (info->do_icarus_timing
&& !was_hw_error
&& ((nonce & info->nonce_mask) > END_CONDITION) && ((nonce & info->nonce_mask) > END_CONDITION)
&& ((nonce & info->nonce_mask) < (info->nonce_mask & ~END_CONDITION))) { && ((nonce & info->nonce_mask) < (info->nonce_mask & ~END_CONDITION))) {
gettimeofday(&tv_history_start, NULL); gettimeofday(&tv_history_start, NULL);

14
driver-modminer.c

@ -13,9 +13,9 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "fpgautils.h"
#include "logging.h" #include "logging.h"
#include "miner.h" #include "miner.h"
#include "fpgautils.h"
#define BITSTREAM_FILENAME "fpgaminer_top_fixed7_197MHz.ncd" #define BITSTREAM_FILENAME "fpgaminer_top_fixed7_197MHz.ncd"
#define BISTREAM_USER_ID "\2\4$B" #define BISTREAM_USER_ID "\2\4$B"
@ -103,7 +103,7 @@ modminer_detect_auto()
static void static void
modminer_detect() modminer_detect()
{ {
serial_detect_auto(modminer_api.dname, modminer_detect_one, modminer_detect_auto); serial_detect_auto(&modminer_api, modminer_detect_one, modminer_detect_auto);
} }
#define bailout(...) return _bailout(-1, modminer, __VA_ARGS__); #define bailout(...) return _bailout(-1, modminer, __VA_ARGS__);
@ -404,7 +404,7 @@ modminer_process_results(struct thr_info*thr)
char cmd[2], temperature; char cmd[2], temperature;
uint32_t nonce; uint32_t nonce;
long iter; long iter;
bool bad; int curr_hw_errors;
cmd[0] = '\x0a'; cmd[0] = '\x0a';
cmd[1] = fpgaid; cmd[1] = fpgaid;
@ -441,12 +441,10 @@ modminer_process_results(struct thr_info*thr)
mutex_unlock(&modminer->device_mutex); mutex_unlock(&modminer->device_mutex);
if (memcmp(&nonce, "\xff\xff\xff\xff", 4)) { if (memcmp(&nonce, "\xff\xff\xff\xff", 4)) {
state->no_nonce_counter = 0; state->no_nonce_counter = 0;
bad = !test_nonce(work, nonce); curr_hw_errors = modminer->hw_errors;
if (!bad)
submit_nonce(thr, work, nonce); submit_nonce(thr, work, nonce);
else { if (modminer->hw_errors > curr_hw_errors) {
++hw_errors; if (modminer->hw_errors * 100 > 1000 + state->good_share_counter)
if (++modminer->hw_errors * 100 > 1000 + state->good_share_counter)
// Only reduce clocks if hardware errors are more than ~1% of results // Only reduce clocks if hardware errors are more than ~1% of results
modminer_reduce_clock(thr, true); modminer_reduce_clock(thr, true);
} }

16
findnonce.c

@ -131,6 +131,8 @@ void precalc_hash(dev_blk_ctx *blk, uint32_t *state, uint32_t *data)
blk->sevenA = blk->ctx_h + SHA256_K[7]; blk->sevenA = blk->ctx_h + SHA256_K[7];
} }
#if 0 // not used any more
#define P(t) (W[(t)&0xF] = W[(t-16)&0xF] + (rotate(W[(t-15)&0xF], 25) ^ rotate(W[(t-15)&0xF], 14) ^ (W[(t-15)&0xF] >> 3)) + W[(t-7)&0xF] + (rotate(W[(t-2)&0xF], 15) ^ rotate(W[(t-2)&0xF], 13) ^ (W[(t-2)&0xF] >> 10))) #define P(t) (W[(t)&0xF] = W[(t-16)&0xF] + (rotate(W[(t-15)&0xF], 25) ^ rotate(W[(t-15)&0xF], 14) ^ (W[(t-15)&0xF] >> 3)) + W[(t-7)&0xF] + (rotate(W[(t-2)&0xF], 15) ^ rotate(W[(t-2)&0xF], 13) ^ (W[(t-2)&0xF] >> 10)))
#define IR(u) \ #define IR(u) \
@ -167,6 +169,8 @@ void precalc_hash(dev_blk_ctx *blk, uint32_t *state, uint32_t *data)
R(E, F, G, H, A, B, C, D, P(u+4), SHA256_K[u+4]); \ R(E, F, G, H, A, B, C, D, P(u+4), SHA256_K[u+4]); \
R(D, E, F, G, H, A, B, C, P(u+5), SHA256_K[u+5]) R(D, E, F, G, H, A, B, C, P(u+5), SHA256_K[u+5])
#endif
struct pc_data { struct pc_data {
struct thr_info *thr; struct thr_info *thr;
struct work *work; struct work *work;
@ -175,6 +179,8 @@ struct pc_data {
int found; int found;
}; };
#if 0 // not used any more
static void send_sha_nonce(struct pc_data *pcd, cl_uint nonce) static void send_sha_nonce(struct pc_data *pcd, cl_uint nonce)
{ {
dev_blk_ctx *blk = &pcd->work->blk; dev_blk_ctx *blk = &pcd->work->blk;
@ -222,6 +228,8 @@ static void send_sha_nonce(struct pc_data *pcd, cl_uint nonce)
} }
} }
#endif
static void send_scrypt_nonce(struct pc_data *pcd, uint32_t nonce) static void send_scrypt_nonce(struct pc_data *pcd, uint32_t nonce)
{ {
struct thr_info *thr = pcd->thr; struct thr_info *thr = pcd->thr;
@ -238,6 +246,8 @@ static void send_scrypt_nonce(struct pc_data *pcd, uint32_t nonce)
static void *postcalc_hash(void *userdata) static void *postcalc_hash(void *userdata)
{ {
struct pc_data *pcd = (struct pc_data *)userdata; struct pc_data *pcd = (struct pc_data *)userdata;
struct thr_info *thr = pcd->thr;
struct work *work = pcd->work;
unsigned int entry = 0; unsigned int entry = 0;
pthread_detach(pthread_self()); pthread_detach(pthread_self());
@ -248,8 +258,10 @@ static void *postcalc_hash(void *userdata)
applog(LOG_DEBUG, "OCL NONCE %u found in slot %d", nonce, entry); applog(LOG_DEBUG, "OCL NONCE %u found in slot %d", nonce, entry);
if (opt_scrypt) if (opt_scrypt)
send_scrypt_nonce(pcd, nonce); send_scrypt_nonce(pcd, nonce);
else else {
send_sha_nonce(pcd, nonce); if (unlikely(submit_nonce(thr, work, nonce) == false))
applog(LOG_ERR, "Failed to submit work, exiting");
}
} }
free(pcd); free(pcd);

53
fpgautils.c

@ -33,13 +33,12 @@
#endif #endif
#include "elist.h" #include "elist.h"
#include "fpgautils.h"
#include "logging.h" #include "logging.h"
#include "miner.h" #include "miner.h"
#include "fpgautils.h"
#ifdef HAVE_LIBUDEV #ifdef HAVE_LIBUDEV
int int serial_autodetect_udev(detectone_func_t detectone, const char*prodname)
serial_autodetect_udev(detectone_func_t detectone, const char*prodname)
{ {
struct udev *udev = udev_new(); struct udev *udev = udev_new();
struct udev_enumerate *enumerate = udev_enumerate_new(udev); struct udev_enumerate *enumerate = udev_enumerate_new(udev);
@ -69,15 +68,13 @@ serial_autodetect_udev(detectone_func_t detectone, const char*prodname)
return found; return found;
} }
#else #else
int int serial_autodetect_udev(__maybe_unused detectone_func_t detectone, __maybe_unused const char*prodname)
serial_autodetect_udev(__maybe_unused detectone_func_t detectone, __maybe_unused const char*prodname)
{ {
return 0; return 0;
} }
#endif #endif
int int serial_autodetect_devserial(detectone_func_t detectone, const char*prodname)
serial_autodetect_devserial(detectone_func_t detectone, const char*prodname)
{ {
#ifndef WIN32 #ifndef WIN32
DIR *D; DIR *D;
@ -107,30 +104,32 @@ serial_autodetect_devserial(detectone_func_t detectone, const char*prodname)
#endif #endif
} }
int int _serial_detect(struct device_api *api, detectone_func_t detectone, autoscan_func_t autoscan, bool forceauto)
_serial_detect(const char*dname, detectone_func_t detectone, autoscan_func_t autoscan, bool forceauto)
{ {
struct string_elist *iter, *tmp; struct string_elist *iter, *tmp;
const char*s, *p; const char *dev, *colon;
bool inhibitauto = false; bool inhibitauto = false;
char found = 0; char found = 0;
size_t dnamel = strlen(dname); size_t namel = strlen(api->name);
size_t dnamel = strlen(api->dname);
list_for_each_entry_safe(iter, tmp, &scan_devices, list) { list_for_each_entry_safe(iter, tmp, &scan_devices, list) {
s = iter->string; dev = iter->string;
if ((p = strchr(s, ':')) && p[1] != '\0') { if ((colon = strchr(dev, ':')) && colon[1] != '\0') {
size_t plen = p - s; size_t idlen = colon - dev;
if (plen != dnamel || strncasecmp(s, dname, plen))
// allow either name:device or dname:device
if ((idlen != namel || strncasecmp(dev, api->name, idlen))
&& (idlen != dnamel || strncasecmp(dev, api->dname, idlen)))
continue; continue;
s = p + 1;
dev = colon + 1;
} }
if (!strcmp(s, "auto")) if (!strcmp(dev, "auto"))
forceauto = true; forceauto = true;
else else if (!strcmp(dev, "noauto"))
if (!strcmp(s, "noauto"))
inhibitauto = true; inhibitauto = true;
else else if (detectone(dev)) {
if (detectone(s)) {
string_elist_del(iter); string_elist_del(iter);
inhibitauto = true; inhibitauto = true;
++found; ++found;
@ -311,8 +310,7 @@ void termios_debug(const char *devpath, struct termios *my_termios, const char *
#endif #endif
#endif #endif
int int serial_open(const char *devpath, unsigned long baud, signed short timeout, bool purge)
serial_open(const char*devpath, unsigned long baud, signed short timeout, bool purge)
{ {
#ifdef WIN32 #ifdef WIN32
HANDLE hSerial = CreateFile(devpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); HANDLE hSerial = CreateFile(devpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
@ -429,8 +427,7 @@ serial_open(const char*devpath, unsigned long baud, signed short timeout, bool p
#endif #endif
} }
ssize_t ssize_t _serial_read(int fd, char *buf, size_t bufsiz, char *eol)
_serial_read(int fd, char *buf, size_t bufsiz, char *eol)
{ {
ssize_t len, tlen = 0; ssize_t len, tlen = 0;
while (bufsiz) { while (bufsiz) {
@ -446,8 +443,7 @@ _serial_read(int fd, char *buf, size_t bufsiz, char *eol)
return tlen; return tlen;
} }
static FILE* static FILE *_open_bitstream(const char *path, const char *subdir, const char *filename)
_open_bitstream(const char*path, const char*subdir, const char*filename)
{ {
char fullpath[PATH_MAX]; char fullpath[PATH_MAX];
strcpy(fullpath, path); strcpy(fullpath, path);
@ -471,8 +467,7 @@ _open_bitstream(const char*path, const char*subdir, const char*filename)
_open_bitstream(path, NULL); \ _open_bitstream(path, NULL); \
} while(0) } while(0)
FILE* FILE *open_bitstream(const char *dname, const char *filename)
open_bitstream(const char*dname, const char*filename)
{ {
FILE *f; FILE *f;

16
fpgautils.h

@ -16,13 +16,13 @@
typedef bool(*detectone_func_t)(const char*); typedef bool(*detectone_func_t)(const char*);
typedef int(*autoscan_func_t)(); typedef int(*autoscan_func_t)();
extern int _serial_detect(const char*dname, detectone_func_t, autoscan_func_t, bool force_autoscan); extern int _serial_detect(struct device_api *api, detectone_func_t, autoscan_func_t, bool force_autoscan);
#define serial_detect_fauto(dname, detectone, autoscan) \ #define serial_detect_fauto(api, detectone, autoscan) \
_serial_detect(dname, detectone, autoscan, true) _serial_detect(api, detectone, autoscan, true)
#define serial_detect_auto(dname, detectone, autoscan) \ #define serial_detect_auto(api, detectone, autoscan) \
_serial_detect(dname, detectone, autoscan, false) _serial_detect(api, detectone, autoscan, false)
#define serial_detect(dname, detectone) \ #define serial_detect(api, detectone) \
_serial_detect(dname, detectone, NULL, false) _serial_detect(api, detectone, NULL, false)
extern int serial_autodetect_devserial(detectone_func_t, const char *prodname); extern int serial_autodetect_devserial(detectone_func_t, const char *prodname);
extern int serial_autodetect_udev(detectone_func_t, const char *prodname); extern int serial_autodetect_udev(detectone_func_t, const char *prodname);
@ -31,7 +31,7 @@ extern ssize_t _serial_read(int fd, char *buf, size_t buflen, char*eol);
#define serial_read(fd, buf, count) \ #define serial_read(fd, buf, count) \
_serial_read(fd, (char*)(buf), count, NULL) _serial_read(fd, (char*)(buf), count, NULL)
#define serial_read_line(fd, buf, bufsiz, eol) \ #define serial_read_line(fd, buf, bufsiz, eol) \
_serial_read(fd, buf, count, &eol) _serial_read(fd, buf, bufsiz, &eol)
#define serial_close(fd) close(fd) #define serial_close(fd) close(fd)
extern FILE *open_bitstream(const char *dname, const char *filename); extern FILE *open_bitstream(const char *dname, const char *filename);

2
logging.h

@ -20,6 +20,8 @@ enum {
/* original / legacy debug flags */ /* original / legacy debug flags */
extern bool opt_debug; extern bool opt_debug;
extern bool opt_log_output; extern bool opt_log_output;
extern bool opt_realquiet;
extern bool want_per_device_stats;
/* global log_level, messages with lower or equal prio are logged */ /* global log_level, messages with lower or equal prio are logged */
extern int opt_log_level; extern int opt_log_level;

42
miner.h

@ -239,6 +239,7 @@ struct device_api {
void (*get_statline)(char*, struct cgpu_info*); void (*get_statline)(char*, struct cgpu_info*);
struct api_data *(*get_api_stats)(struct cgpu_info*); struct api_data *(*get_api_stats)(struct cgpu_info*);
bool (*get_stats)(struct cgpu_info*); bool (*get_stats)(struct cgpu_info*);
void (*identify_device)(struct cgpu_info*); // e.g. to flash a led
// Thread-specific functions // Thread-specific functions
bool (*thread_prepare)(struct thr_info*); bool (*thread_prepare)(struct thr_info*);
@ -276,6 +277,7 @@ enum dev_reason {
REASON_DEV_OVER_HEAT, REASON_DEV_OVER_HEAT,
REASON_DEV_THERMAL_CUTOFF, REASON_DEV_THERMAL_CUTOFF,
REASON_DEV_COMMS_ERROR, REASON_DEV_COMMS_ERROR,
REASON_DEV_THROTTLE,
}; };
#define REASON_NONE "None" #define REASON_NONE "None"
@ -288,6 +290,7 @@ enum dev_reason {
#define REASON_DEV_OVER_HEAT_STR "Device over heated" #define REASON_DEV_OVER_HEAT_STR "Device over heated"
#define REASON_DEV_THERMAL_CUTOFF_STR "Device reached thermal cutoff" #define REASON_DEV_THERMAL_CUTOFF_STR "Device reached thermal cutoff"
#define REASON_DEV_COMMS_ERROR_STR "Device comms error" #define REASON_DEV_COMMS_ERROR_STR "Device comms error"
#define REASON_DEV_THROTTLE_STR "Device throttle"
#define REASON_UNKNOWN_STR "Unknown reason - code bug" #define REASON_UNKNOWN_STR "Unknown reason - code bug"
#define MIN_SEC_UNSET 99999999 #define MIN_SEC_UNSET 99999999
@ -335,6 +338,7 @@ struct cgpu_info {
uint32_t nonces; uint32_t nonces;
bool nonce_range; bool nonce_range;
bool polling; bool polling;
bool flash_led;
#endif #endif
pthread_mutex_t device_mutex; pthread_mutex_t device_mutex;
@ -395,8 +399,12 @@ struct cgpu_info {
int gpu_powertune; int gpu_powertune;
float gpu_vddc; float gpu_vddc;
#endif #endif
int diff1;
double diff_accepted;
double diff_rejected;
int last_share_pool; int last_share_pool;
time_t last_share_pool_time; time_t last_share_pool_time;
double last_share_diff;
time_t device_last_well; time_t device_last_well;
time_t device_last_not_well; time_t device_last_not_well;
@ -410,6 +418,7 @@ struct cgpu_info {
int dev_over_heat_count; // It's a warning but worth knowing int dev_over_heat_count; // It's a warning but worth knowing
int dev_thermal_cutoff_count; int dev_thermal_cutoff_count;
int dev_comms_error_count; int dev_comms_error_count;
int dev_throttle_count;
struct cgminer_stats cgminer_stats; struct cgminer_stats cgminer_stats;
}; };
@ -449,6 +458,7 @@ extern void thr_info_cancel(struct thr_info *thr);
extern void thr_info_freeze(struct thr_info *thr); extern void thr_info_freeze(struct thr_info *thr);
extern void nmsleep(unsigned int msecs); extern void nmsleep(unsigned int msecs);
extern double us_tdiff(struct timeval *end, struct timeval *start); extern double us_tdiff(struct timeval *end, struct timeval *start);
extern double tdiff(struct timeval *end, struct timeval *start);
struct string_elist { struct string_elist {
char *string; char *string;
@ -575,6 +585,7 @@ extern bool opt_delaynet;
extern bool opt_restart; extern bool opt_restart;
extern char *opt_icarus_options; extern char *opt_icarus_options;
extern char *opt_icarus_timing; extern char *opt_icarus_timing;
extern bool opt_worktime;
#ifdef USE_BITFORCE #ifdef USE_BITFORCE
extern bool opt_bfl_noncerange; extern bool opt_bfl_noncerange;
#endif #endif
@ -585,6 +596,8 @@ extern const uint32_t sha256_init_state[];
extern json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass, extern json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass,
const char *rpc_req, bool, bool, int *, const char *rpc_req, bool, bool, int *,
struct pool *pool, bool); struct pool *pool, bool);
extern const char *proxytype(curl_proxytype proxytype);
extern char *get_proxy(char *url, struct pool *pool);
extern char *bin2hex(const unsigned char *p, size_t len); extern char *bin2hex(const unsigned char *p, size_t len);
extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len); extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len);
@ -598,7 +611,9 @@ typedef bool (*sha256_func)(struct thr_info*, const unsigned char *pmidstate,
extern bool fulltest(const unsigned char *hash, const unsigned char *target); extern bool fulltest(const unsigned char *hash, const unsigned char *target);
extern int opt_queue;
extern int opt_scantime; extern int opt_scantime;
extern int opt_expiry;
extern pthread_mutex_t console_lock; extern pthread_mutex_t console_lock;
extern pthread_mutex_t ch_lock; extern pthread_mutex_t ch_lock;
@ -671,6 +686,7 @@ extern unsigned int new_blocks;
extern unsigned int found_blocks; extern unsigned int found_blocks;
extern int total_accepted, total_rejected, total_diff1;; extern int total_accepted, total_rejected, total_diff1;;
extern int total_getworks, total_stale, total_discarded; extern int total_getworks, total_stale, total_discarded;
extern double total_diff_accepted, total_diff_rejected, total_diff_stale;
extern unsigned int local_work; extern unsigned int local_work;
extern unsigned int total_go, total_ro; extern unsigned int total_go, total_ro;
extern const int opt_cutofftemp; extern const int opt_cutofftemp;
@ -735,6 +751,10 @@ struct pool {
int solved; int solved;
int diff1; int diff1;
double diff_accepted;
double diff_rejected;
double diff_stale;
int queued; int queued;
int staged; int staged;
@ -763,6 +783,8 @@ struct pool {
char *rpc_url; char *rpc_url;
char *rpc_userpass; char *rpc_userpass;
char *rpc_user, *rpc_pass; char *rpc_user, *rpc_pass;
curl_proxytype rpc_proxytype;
char *rpc_proxy;
pthread_mutex_t pool_lock; pthread_mutex_t pool_lock;
@ -778,11 +800,17 @@ struct pool {
struct list_head curlring; struct list_head curlring;
time_t last_share_time; time_t last_share_time;
double last_share_diff;
struct cgminer_stats cgminer_stats; struct cgminer_stats cgminer_stats;
struct cgminer_pool_stats cgminer_pool_stats; struct cgminer_pool_stats cgminer_pool_stats;
}; };
#define GETWORK_MODE_TESTPOOL 'T'
#define GETWORK_MODE_POOL 'P'
#define GETWORK_MODE_LP 'L'
#define GETWORK_MODE_BENCHMARK 'B'
struct work { struct work {
unsigned char data[128]; unsigned char data[128];
unsigned char hash1[64]; unsigned char hash1[64];
@ -815,7 +843,14 @@ struct work {
int id; int id;
UT_hash_handle hh; UT_hash_handle hh;
time_t share_found_time; double work_difficulty;
struct timeval tv_getwork;
struct timeval tv_getwork_reply;
struct timeval tv_cloned;
struct timeval tv_work_start;
struct timeval tv_work_found;
char getwork_mode;
}; };
#ifdef USE_MODMINER #ifdef USE_MODMINER
@ -837,7 +872,6 @@ struct modminer_fpga_state {
#endif #endif
extern void get_datestamp(char *, struct timeval *); extern void get_datestamp(char *, struct timeval *);
extern bool test_nonce(struct work *work, uint32_t nonce);
bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce); bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce);
extern void tailsprintf(char *f, const char *fmt, ...); extern void tailsprintf(char *f, const char *fmt, ...);
extern void wlogprint(const char *f, ...); extern void wlogprint(const char *f, ...);
@ -880,7 +914,8 @@ enum api_data_type {
API_UTILITY, API_UTILITY,
API_FREQ, API_FREQ,
API_VOLTS, API_VOLTS,
API_HS API_HS,
API_DIFF
}; };
struct api_data { struct api_data {
@ -911,5 +946,6 @@ extern struct api_data *api_add_utility(struct api_data *root, char *name, doubl
extern struct api_data *api_add_freq(struct api_data *root, char *name, double *data, bool copy_data); extern struct api_data *api_add_freq(struct api_data *root, char *name, double *data, bool copy_data);
extern struct api_data *api_add_volts(struct api_data *root, char *name, float *data, bool copy_data); extern struct api_data *api_add_volts(struct api_data *root, char *name, float *data, bool copy_data);
extern struct api_data *api_add_hs(struct api_data *root, char *name, double *data, bool copy_data); extern struct api_data *api_add_hs(struct api_data *root, char *name, double *data, bool copy_data);
extern struct api_data *api_add_diff(struct api_data *root, char *name, double *data, bool copy_data);
#endif /* __MINER_H__ */ #endif /* __MINER_H__ */

79
miner.php

@ -2,7 +2,7 @@
session_start(); session_start();
# #
global $title, $miner, $port, $readonly, $notify, $rigs; global $title, $miner, $port, $readonly, $notify, $rigs;
global $rigtotals, $forcerigtotals; global $rigipsecurity, $rigtotals, $forcerigtotals;
global $socksndtimeoutsec, $sockrcvtimeoutsec; global $socksndtimeoutsec, $sockrcvtimeoutsec;
global $checklastshare, $poolinputs, $hidefields; global $checklastshare, $poolinputs, $hidefields;
global $ignorerefresh, $changerefresh, $autorefresh; global $ignorerefresh, $changerefresh, $autorefresh;
@ -40,6 +40,10 @@ $poolinputs = false;
# format: 'IP:Port' or 'Host:Port' or 'Host:Port:Name' # format: 'IP:Port' or 'Host:Port' or 'Host:Port:Name'
$rigs = array('127.0.0.1:4028'); $rigs = array('127.0.0.1:4028');
# #
# Set $rigipsecurity to false to show the IP/Port of the rig
# in the socket error messages and also show the full socket message
$rigipsecurity = true;
#
# Set $rigtotals to true to display totals on the single rig page # Set $rigtotals to true to display totals on the single rig page
# 'false' means no totals (and ignores $forcerigtotals) # 'false' means no totals (and ignores $forcerigtotals)
# You can force it to always show rig totals when there is only # You can force it to always show rig totals when there is only
@ -226,7 +230,7 @@ function htmlhead($checkapi, $rig, $pg = null)
if ($readonly === false && $checkapi === true) if ($readonly === false && $checkapi === true)
{ {
$error = null; $error = null;
$access = api('privileged'); $access = api($rig, 'privileged');
if ($error != null if ($error != null
|| !isset($access['STATUS']['STATUS']) || !isset($access['STATUS']['STATUS'])
|| $access['STATUS']['STATUS'] != 'S') || $access['STATUS']['STATUS'] != 'S')
@ -275,8 +279,9 @@ global $haderror, $error;
$haderror = false; $haderror = false;
$error = null; $error = null;
# #
function getsock($addr, $port) function getsock($rig, $addr, $port)
{ {
global $rigipsecurity;
global $haderror, $error, $socksndtimeoutsec, $sockrcvtimeoutsec; global $haderror, $error, $socksndtimeoutsec, $sockrcvtimeoutsec;
$error = null; $error = null;
@ -285,9 +290,15 @@ function getsock($addr, $port)
if ($socket === false || $socket === null) if ($socket === false || $socket === null)
{ {
$haderror = true; $haderror = true;
if ($rigipsecurity === false)
{
$error = socket_strerror(socket_last_error()); $error = socket_strerror(socket_last_error());
$msg = "socket create(TCP) failed"; $msg = "socket create(TCP) failed";
$error = "ERR: $msg '$error'\n"; $error = "ERR: $msg '$error'\n";
}
else
$error = "ERR: socket create(TCP) failed\n";
return null; return null;
} }
@ -301,9 +312,15 @@ function getsock($addr, $port)
if ($res === false) if ($res === false)
{ {
$haderror = true; $haderror = true;
if ($rigipsecurity === false)
{
$error = socket_strerror(socket_last_error()); $error = socket_strerror(socket_last_error());
$msg = "socket connect($addr,$port) failed"; $msg = "socket connect($addr,$port) failed";
$error = "ERR: $msg '$error'\n"; $error = "ERR: $msg '$error'\n";
}
else
$error = "ERR: socket connect($rig) failed\n";
socket_close($socket); socket_close($socket);
return null; return null;
} }
@ -365,12 +382,12 @@ function revert($str)
return str_replace(array("\1", "\2", "\3", "\4"), array("|", "\\", "=", ","), $str); return str_replace(array("\1", "\2", "\3", "\4"), array("|", "\\", "=", ","), $str);
} }
# #
function api($cmd) function api($rig, $cmd)
{ {
global $haderror, $error; global $haderror, $error;
global $miner, $port, $hidefields; global $miner, $port, $hidefields;
$socket = getsock($miner, $port); $socket = getsock($rig, $miner, $port);
if ($socket != null) if ($socket != null)
{ {
socket_write($socket, $cmd, strlen($cmd)); socket_write($socket, $cmd, strlen($cmd));
@ -506,7 +523,15 @@ function classlastshare($when, $alldata, $warnclass, $errorclass)
if (!isset($alldata['Last Share Time'])) if (!isset($alldata['Last Share Time']))
return ''; return '';
if (!isset($alldata['Last Share Difficulty']))
return '';
$expected = pow(2, 32) / ($alldata['MHS av'] * pow(10, 6)); $expected = pow(2, 32) / ($alldata['MHS av'] * pow(10, 6));
// If the share difficulty changes while waiting on a share,
// this calculation will of course be incorrect
$expected *= $alldata['Last Share Difficulty'];
$howlong = $when - $alldata['Last Share Time']; $howlong = $when - $alldata['Last Share Time'];
if ($howlong < 1) if ($howlong < 1)
$howlong = 1; $howlong = 1;
@ -641,11 +666,20 @@ function fmt($section, $name, $value, $when, $alldata)
if ($value == 0) if ($value == 0)
$class = $errorclass; $class = $errorclass;
else else
if (isset($alldata['MHS av'])) if (isset($alldata['Difficulty Accepted'])
&& isset($alldata['Accepted'])
&& isset($alldata['MHS av'])
&& ($alldata['Difficulty Accepted'] > 0)
&& ($alldata['Accepted'] > 0))
{ {
$expected = 60 * $alldata['MHS av'] * (pow(10, 6) / pow(2, 32)); $expected = 60 * $alldata['MHS av'] * (pow(10, 6) / pow(2, 32));
if ($expected == 0) if ($expected == 0)
$expected = 0.000001; // 1 H/s $expected = 0.000001; // 1 H/s
$da = $alldata['Difficulty Accepted'];
$a = $alldata['Accepted'];
$expected /= ($da / $a);
$ratio = $value / $expected; $ratio = $value / $expected;
if ($ratio < 0.9) if ($ratio < 0.9)
$class = $loclass; $class = $loclass;
@ -713,16 +747,26 @@ function fmt($section, $name, $value, $when, $alldata)
$dec = ''; $dec = '';
else else
$dec = '.'.$parts[1]; $dec = '.'.$parts[1];
$ret = number_format($parts[0]).$dec; $ret = number_format((float)$parts[0]).$dec;
if ($value == 0) if ($value == 0)
$class = $errorclass; $class = $errorclass;
else else
if (isset($alldata['Utility'])) if (isset($alldata['Difficulty Accepted'])
&& isset($alldata['Accepted'])
&& isset($alldata['Utility'])
&& ($alldata['Difficulty Accepted'] > 0)
&& ($alldata['Accepted'] > 0))
{ {
$expected = 60 * $value * (pow(10, 6) / pow(2, 32)); $expected = 60 * $value * (pow(10, 6) / pow(2, 32));
$utility = $alldata['Utility']; if ($expected == 0)
$ratio = $utility / $expected; $expected = 0.000001; // 1 H/s
$da = $alldata['Difficulty Accepted'];
$a = $alldata['Accepted'];
$expected /= ($da / $a);
$ratio = $alldata['Utility'] / $expected;
if ($ratio < 0.9) if ($ratio < 0.9)
$class = $hiclass; $class = $hiclass;
else else
@ -757,12 +801,15 @@ function fmt($section, $name, $value, $when, $alldata)
case 'total.Discarded': case 'total.Discarded':
case 'POOL.Diff1 Shares': case 'POOL.Diff1 Shares':
case 'total.Diff1 Shares': case 'total.Diff1 Shares':
case 'GPU.Diff1 Work':
case 'PGA.Diff1 Work':
case 'total.Diff1 Work':
$parts = explode('.', $value, 2); $parts = explode('.', $value, 2);
if (count($parts) == 1) if (count($parts) == 1)
$dec = ''; $dec = '';
else else
$dec = '.'.$parts[1]; $dec = '.'.$parts[1];
$ret = number_format($parts[0]).$dec; $ret = number_format((float)$parts[0]).$dec;
break; break;
case 'GPU.Status': case 'GPU.Status':
case 'PGA.Status': case 'PGA.Status':
@ -1067,7 +1114,7 @@ function processgpus($rig)
global $error; global $error;
global $warnfont, $warnoff; global $warnfont, $warnoff;
$gpus = api('gpucount'); $gpus = api($rig, 'gpucount');
if ($error != null) if ($error != null)
otherrow("<td>Error getting GPU count: $warnfont$error$warnoff</td>"); otherrow("<td>Error getting GPU count: $warnfont$error$warnoff</td>");
@ -1136,7 +1183,7 @@ function process($cmds, $rig)
$count = count($cmds); $count = count($cmds);
foreach ($cmds as $cmd => $des) foreach ($cmds as $cmd => $des)
{ {
$process = api($cmd); $process = api($rig, $cmd);
if ($error != null) if ($error != null)
{ {
@ -1251,7 +1298,7 @@ function doforeach($cmd, $des, $sum, $head, $datetime)
else else
$name = $num; $name = $num;
$ans = api($cmd); $ans = api($name, $cmd);
if ($error != null) if ($error != null)
{ {
@ -1763,7 +1810,7 @@ function processcustompage($pagename, $sections, $sum, $namemap)
foreach ($cmds as $cmd => $one) foreach ($cmds as $cmd => $one)
{ {
$process = api($cmd); $process = api($name, $cmd);
if ($error != null) if ($error != null)
{ {
@ -2052,7 +2099,7 @@ function display()
newtable(); newtable();
doforeach('version', 'rig summary', array(), array(), true); doforeach('version', 'rig summary', array(), array(), true);
$sum = array('MHS av', 'Getworks', 'Found Blocks', 'Accepted', 'Rejected', 'Discarded', 'Stale', 'Utility', 'Local Work', 'Total MH', 'Work Utility', 'Diff1 Shares'); $sum = array('MHS av', 'Getworks', 'Found Blocks', 'Accepted', 'Rejected', 'Discarded', 'Stale', 'Utility', 'Local Work', 'Total MH', 'Work Utility', 'Diff1 Shares', 'Diff1 Work');
doforeach('summary', 'summary information', $sum, array(), false); doforeach('summary', 'summary information', $sum, array(), false);
endtable(); endtable();
otherrow('<td><br><br></td>'); otherrow('<td><br><br></td>');

73
util.c

@ -305,7 +305,10 @@ json_t *json_rpc_call(CURL *curl, const char *url,
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, resp_hdr_cb); curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, resp_hdr_cb);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &hi); curl_easy_setopt(curl, CURLOPT_HEADERDATA, &hi);
curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY); curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
if (opt_socks_proxy) { if (pool->rpc_proxy) {
curl_easy_setopt(curl, CURLOPT_PROXY, pool->rpc_proxy);
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, pool->rpc_proxytype);
} else if (opt_socks_proxy) {
curl_easy_setopt(curl, CURLOPT_PROXY, opt_socks_proxy); curl_easy_setopt(curl, CURLOPT_PROXY, opt_socks_proxy);
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4); curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
} }
@ -460,6 +463,68 @@ err_out:
return NULL; return NULL;
} }
#if (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 10) || (LIBCURL_VERSION_MAJOR > 7)
static struct {
const char *name;
curl_proxytype proxytype;
} proxynames[] = {
{ "http:", CURLPROXY_HTTP },
#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MINOR > 19) || (LIBCURL_VERSION_MINOR == 19 && LIBCURL_VERSION_PATCH >= 4)
{ "http0:", CURLPROXY_HTTP_1_0 },
#endif
#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MINOR > 15) || (LIBCURL_VERSION_MINOR == 15 && LIBCURL_VERSION_PATCH >= 2)
{ "socks4:", CURLPROXY_SOCKS4 },
#endif
{ "socks5:", CURLPROXY_SOCKS5 },
#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MINOR >= 18)
{ "socks4a:", CURLPROXY_SOCKS4A },
{ "socks5h:", CURLPROXY_SOCKS5_HOSTNAME },
#endif
};
#endif
const char *proxytype(curl_proxytype proxytype)
{
int i;
for (i = 0; proxynames[i].name; i++)
if (proxynames[i].proxytype == proxytype)
return proxynames[i].name;
return "invalid";
}
char *get_proxy(char *url, struct pool *pool)
{
pool->rpc_proxy = NULL;
#if (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 10) || (LIBCURL_VERSION_MAJOR > 7)
char *split;
int plen, len, i;
for (i = 0; proxynames[i].name; i++) {
plen = strlen(proxynames[i].name);
if (strncmp(url, proxynames[i].name, plen) == 0) {
if (!(split = strchr(url, '|')))
return url;
*split = '\0';
len = split - url;
pool->rpc_proxy = malloc(1 + len - plen);
if (!(pool->rpc_proxy))
quit(1, "Failed to malloc rpc_proxy");
strcpy(pool->rpc_proxy, url + plen);
pool->rpc_proxytype = proxynames[i].proxytype;
url = split + 1;
break;
}
}
#endif
return url;
}
char *bin2hex(const unsigned char *p, size_t len) char *bin2hex(const unsigned char *p, size_t len)
{ {
char *s = malloc((len * 2) + 1); char *s = malloc((len * 2) + 1);
@ -722,3 +787,9 @@ double us_tdiff(struct timeval *end, struct timeval *start)
{ {
return end->tv_sec * 1000000 + end->tv_usec - start->tv_sec * 1000000 - start->tv_usec; return end->tv_sec * 1000000 + end->tv_usec - start->tv_sec * 1000000 - start->tv_usec;
} }
/* Returns the seconds difference between end and start times as a double */
double tdiff(struct timeval *end, struct timeval *start)
{
return end->tv_sec - start->tv_sec + (end->tv_usec - start->tv_usec) / 1000000.0;
}

Loading…
Cancel
Save