From 987641058039b0241cf7e38146b1072c060c7e2c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 29 Aug 2014 21:21:54 +1000 Subject: [PATCH 1/8] Log stats by users instead of workers since they can and will overlap --- src/stratifier.c | 59 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index cef3e8d6..fe630572 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -195,6 +195,12 @@ struct user_instance { bool btcaddress; int workers; + + double dsps1; /* Diff shares per second, 1 minute rolling average */ + double dsps5; /* ... 5 minute ... */ + double dsps60;/* etc */ + double dsps1440; + tv_t last_share; }; typedef struct user_instance user_instance_t; @@ -1505,6 +1511,7 @@ static double sane_tdiff(tv_t *end, tv_t *start) static void add_submit(ckpool_t *ckp, stratum_instance_t *client, int diff, bool valid) { double tdiff, bdiff, dsps, drr, network_diff, bias; + user_instance_t *instance = client->user_instance; int64_t next_blockid, optimal; tv_t now_t; @@ -1527,7 +1534,12 @@ static void add_submit(ckpool_t *ckp, stratum_instance_t *client, int diff, bool decay_time(&client->dsps5, diff, tdiff, 300); decay_time(&client->dsps60, diff, tdiff, 3600); decay_time(&client->dsps1440, diff, tdiff, 86400); + decay_time(&instance->dsps1, diff, tdiff, 60); + decay_time(&instance->dsps5, diff, tdiff, 300); + decay_time(&instance->dsps60, diff, tdiff, 3600); + decay_time(&instance->dsps1440, diff, tdiff, 86400); copy_tv(&client->last_share, &now_t); + copy_tv(&instance->last_share, &now_t); client->idle = false; client->ssdc++; @@ -2417,10 +2429,11 @@ static void *statsupdate(void *arg) while (42) { char suffix1[16], suffix5[16], suffix15[16], suffix60[16], cdfield[64]; - double ghs1, ghs5, ghs15, ghs60, ghs360, ghs1440, tdiff, bias; + double ghs, ghs1, ghs5, ghs15, ghs60, ghs360, ghs1440, tdiff, bias; char suffix360[16], suffix1440[16]; - double sps1, sps5, sps15, sps60; + user_instance_t *instance, *tmpuser; stratum_instance_t *client, *tmp; + double sps1, sps5, sps15, sps60; char fname[512] = {}; tv_t now, diff; ts_t ts_now; @@ -2503,14 +2516,10 @@ static void *statsupdate(void *arg) ck_rlock(&instance_lock); HASH_ITER(hh, stratum_instances, client, tmp) { - double ghs; - bool idle; - if (!client->authorised) continue; if (now.tv_sec - client->last_share.tv_sec > 60) { - idle = true; /* No shares for over a minute, decay to 0 */ decay_time(&client->dsps1, 0, tdiff, 60); decay_time(&client->dsps5, 0, tdiff, 300); @@ -2518,35 +2527,47 @@ static void *statsupdate(void *arg) decay_time(&client->dsps1440, 0, tdiff, 86400); if (now.tv_sec - client->last_share.tv_sec > 600) client->idle = true; - } else - idle = false; - ghs = client->dsps1 * nonces; + continue; + } + } + + HASH_ITER(hh, user_instances, instance, tmpuser) { + bool idle = false; + + if (now.tv_sec - instance->last_share.tv_sec > 60) { + /* No shares for over a minute, decay to 0 */ + decay_time(&instance->dsps1, 0, tdiff, 60); + decay_time(&instance->dsps5, 0, tdiff, 300); + decay_time(&instance->dsps60, 0, tdiff, 3600); + decay_time(&instance->dsps1440, 0, tdiff, 86400); + idle = true; + } + ghs = instance->dsps1 * nonces; suffix_string(ghs, suffix1, 16, 0); - ghs = client->dsps5 * nonces; + ghs = instance->dsps5 * nonces; suffix_string(ghs, suffix5, 16, 0); - ghs = client->dsps60 * nonces; + ghs = instance->dsps60 * nonces; suffix_string(ghs, suffix60, 16, 0); - ghs = client->dsps1440 * nonces; + ghs = instance->dsps1440 * nonces; suffix_string(ghs, suffix1440, 16, 0); - JSON_CPACK(val, "{ss,ss,ss,ss}", + JSON_CPACK(val, "{ss,ss,ss,ss,si}", "hashrate1m", suffix1, "hashrate5m", suffix5, "hashrate1hr", suffix60, - "hashrate1d", suffix1440); + "hashrate1d", suffix1440, + "workers", instance->workers); - snprintf(fname, 511, "%s/%s", ckp->logdir, client->workername); + snprintf(fname, 511, "%s/%s", ckp->logdir, instance->username); fp = fopen(fname, "we"); if (unlikely(!fp)) { LOGERR("Failed to fopen %s", fname); continue; } - s = json_dumps(val, JSON_NO_UTF8); + s = json_dumps(val, JSON_NO_UTF8 | JSON_PRESERVE_ORDER); fprintf(fp, "%s\n", s); - /* Only display the status of connected users to the - * console log. */ if (!idle) - LOGNOTICE("Worker %s:%s", client->workername, s); + LOGNOTICE("User %s:%s", instance->username, s); dealloc(s); json_decref(val); fclose(fp); From 9d04e11bb63a742acc310e7be500ff092132e887 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 31 Aug 2014 09:55:40 +1000 Subject: [PATCH 2/8] Store pool and user logs in separate subdirectories --- src/ckpool.c | 12 ++++++++++++ src/stratifier.c | 10 +++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/ckpool.c b/src/ckpool.c index c88781ad..840057ed 100644 --- a/src/ckpool.c +++ b/src/ckpool.c @@ -1226,6 +1226,18 @@ int main(int argc, char **argv) if (ret && errno != EEXIST) quit(1, "Failed to make log directory %s", ckp.logdir); + /* Create the user logdir */ + sprintf(buf, "%s/users", ckp.logdir); + ret = mkdir(buf, 0750); + if (ret && errno != EEXIST) + quit(1, "Failed to make user log directory %s", buf); + + /* Create the pool logdir */ + sprintf(buf, "%s/pool", ckp.logdir); + ret = mkdir(buf, 0750); + if (ret && errno != EEXIST) + quit(1, "Failed to make pool log directory %s", buf); + /* Create the logfile */ sprintf(buf, "%s%s.log", ckp.logdir, ckp.name); ckp.logfp = fopen(buf, "ae"); diff --git a/src/stratifier.c b/src/stratifier.c index fe630572..26e0f3e7 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -2474,7 +2474,7 @@ static void *statsupdate(void *arg) ghs1440 = stats.dsps1440 * nonces / bias; suffix_string(ghs1440, suffix1440, 16, 0); - snprintf(fname, 511, "%s/pool.status", ckp->logdir); + snprintf(fname, 511, "%s/pool/pool.status", ckp->logdir); fp = fopen(fname, "we"); if (unlikely(!fp)) LOGERR("Failed to fopen %s", fname); @@ -2483,7 +2483,7 @@ static void *statsupdate(void *arg) "runtime", diff.tv_sec, "Users", stats.users, "Workers", stats.workers); - s = json_dumps(val, JSON_NO_UTF8); + s = json_dumps(val, JSON_NO_UTF8 | JSON_PRESERVE_ORDER); json_decref(val); LOGNOTICE("Pool:%s", s); fprintf(fp, "%s\n", s); @@ -2496,7 +2496,7 @@ static void *statsupdate(void *arg) "hashrate1hr", suffix60, "hashrate6hr", suffix360, "hashrate1d", suffix1440); - s = json_dumps(val, JSON_NO_UTF8); + s = json_dumps(val, JSON_NO_UTF8 | JSON_PRESERVE_ORDER); json_decref(val); LOGNOTICE("Pool:%s", s); fprintf(fp, "%s\n", s); @@ -2507,7 +2507,7 @@ static void *statsupdate(void *arg) "SPS5m", sps5, "SPS15m", sps15, "SPS1h", sps60); - s = json_dumps(val, JSON_NO_UTF8); + s = json_dumps(val, JSON_NO_UTF8 | JSON_PRESERVE_ORDER); json_decref(val); LOGNOTICE("Pool:%s", s); fprintf(fp, "%s\n", s); @@ -2558,7 +2558,7 @@ static void *statsupdate(void *arg) "hashrate1d", suffix1440, "workers", instance->workers); - snprintf(fname, 511, "%s/%s", ckp->logdir, instance->username); + snprintf(fname, 511, "%s/users/%s", ckp->logdir, instance->username); fp = fopen(fname, "we"); if (unlikely(!fp)) { LOGERR("Failed to fopen %s", fname); From 780b42a4244f27cb2a5a6171db8a09a180625233 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 1 Sep 2014 19:13:37 +1000 Subject: [PATCH 3/8] Change default block polling to 50ms --- ckpool.conf | 2 +- src/ckpool.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ckpool.conf b/ckpool.conf index fffa2571..ad29587a 100644 --- a/ckpool.conf +++ b/ckpool.conf @@ -13,7 +13,7 @@ ], "btcaddress" : "14BMjogz69qe8hk9thyzbmR5pg34mVKB1e", "btcsig" : "/mined by ck/", -"blockpoll" : 500, +"blockpoll" : 50, "update_interval" : 30, "serverurl" : "ckpool.org:3333", "mindiff" : 1, diff --git a/src/ckpool.c b/src/ckpool.c index 840057ed..6e41347b 100644 --- a/src/ckpool.c +++ b/src/ckpool.c @@ -1208,7 +1208,7 @@ int main(int argc, char **argv) if (!ckp.btcaddress) ckp.btcaddress = ckp.donaddress; if (!ckp.blockpoll) - ckp.blockpoll = 500; + ckp.blockpoll = 50; if (!ckp.update_interval) ckp.update_interval = 30; if (!ckp.mindiff) From f484ffd45b49de7efcecd1ce43db6bdf182f5e6a Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 1 Sep 2014 23:54:26 +1000 Subject: [PATCH 4/8] Allow more rapid adjustment of diff down by restarting calculation with each diff change and not capping diff drop --- src/stratifier.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index 26e0f3e7..07110a29 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1526,7 +1526,7 @@ static void add_submit(ckpool_t *ckp, stratum_instance_t *client, int diff, bool ck_runlock(&workbase_lock); tdiff = sane_tdiff(&now_t, &client->last_share); - if (unlikely(!client->first_share.tv_sec)) { + if (!client->first_share.tv_sec) { copy_tv(&client->first_share, &now_t); copy_tv(&client->ldc, &now_t); } @@ -1562,6 +1562,7 @@ static void add_submit(ckpool_t *ckp, stratum_instance_t *client, int diff, bool if (diff != client->diff) { client->ssdc = 0; + client->first_share.tv_sec = 0; return; } @@ -1574,10 +1575,6 @@ static void add_submit(ckpool_t *ckp, stratum_instance_t *client, int diff, bool return; optimal = round(dsps * 3.33); - /* Don't drop diff to rapidly in case the client simply switched away - * and has just returned */ - if (optimal < client->diff / 2) - optimal = client->diff / 2; /* Clamp to mindiff ~ network_diff */ if (optimal < ckp->mindiff) optimal = ckp->mindiff; @@ -1586,6 +1583,7 @@ static void add_submit(ckpool_t *ckp, stratum_instance_t *client, int diff, bool if (client->diff == optimal) return; + client->first_share.tv_sec = 0; client->ssdc = 0; LOGINFO("Client %d biased dsps %.2f dsps %.2f drr %.2f adjust diff from %ld to: %ld ", From 9ac57f9ee072981db99f8f8009512f874ba04c56 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 2 Sep 2014 00:15:09 +1000 Subject: [PATCH 5/8] Separate user from worker last share times --- src/stratifier.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index 07110a29..d9271010 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1525,20 +1525,23 @@ static void add_submit(ckpool_t *ckp, stratum_instance_t *client, int diff, bool network_diff = current_workbase->network_diff; ck_runlock(&workbase_lock); - tdiff = sane_tdiff(&now_t, &client->last_share); if (!client->first_share.tv_sec) { copy_tv(&client->first_share, &now_t); copy_tv(&client->ldc, &now_t); } + + tdiff = sane_tdiff(&now_t, &client->last_share); decay_time(&client->dsps1, diff, tdiff, 60); decay_time(&client->dsps5, diff, tdiff, 300); decay_time(&client->dsps60, diff, tdiff, 3600); decay_time(&client->dsps1440, diff, tdiff, 86400); + copy_tv(&client->last_share, &now_t); + + tdiff = sane_tdiff(&now_t, &instance->last_share); decay_time(&instance->dsps1, diff, tdiff, 60); decay_time(&instance->dsps5, diff, tdiff, 300); decay_time(&instance->dsps60, diff, tdiff, 3600); decay_time(&instance->dsps1440, diff, tdiff, 86400); - copy_tv(&client->last_share, &now_t); copy_tv(&instance->last_share, &now_t); client->idle = false; From 47084ccead686c076fe86bf376a23c8bebafd3fb Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 2 Sep 2014 14:07:27 +1000 Subject: [PATCH 6/8] Implement an unlocked priority mechanism for the stratifier talking to the generator to not poll it when the responses will be in flux --- src/stratifier.c | 71 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 9 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index d9271010..e12cbcdd 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -266,6 +266,13 @@ static share_t *shares; static cklock_t share_lock; +static int gen_priority; + +/* Priority levels for generator messages */ +#define GEN_LAX 0 +#define GEN_NORMAL 1 +#define GEN_PRIORITY 2 + #define ID_AUTH 0 #define ID_WORKINFO 1 #define ID_AGEWORKINFO 2 @@ -591,17 +598,62 @@ static void add_base(ckpool_t *ckp, workbase_t *wb, bool *new_block) } } +/* Mandatory send_recv to the generator which sets the message priority if this + * message is higher priority. Races galore on gen_priority mean this might + * read the wrong priority but occasional wrong values are harmless. */ +static char *__send_recv_generator(ckpool_t *ckp, const char *msg, int prio) +{ + char *buf = NULL; + bool set; + + if (prio > gen_priority) { + gen_priority = prio; + set = true; + } else + set = false; + buf = send_recv_proc(ckp->generator, msg); + if (set) + gen_priority = 0; + + return buf; +} + +/* Conditionally send_recv a message only if it's equal or higher priority than + * any currently being serviced. */ +static char *send_recv_generator(ckpool_t *ckp, const char *msg, int prio) +{ + char *buf = NULL; + + if (prio >= gen_priority) + buf = __send_recv_generator(ckp, msg, prio); + return buf; +} + +static void send_generator(ckpool_t *ckp, const char *msg, int prio) +{ + bool set; + + if (prio > gen_priority) { + gen_priority = prio; + set = true; + } else + set = false; + send_proc(ckp->generator, msg); + if (set) + gen_priority = 0; +} + /* This function assumes it will only receive a valid json gbt base template * since checking should have been done earlier, and creates the base template * for generating work templates. */ -static void update_base(ckpool_t *ckp) +static void update_base(ckpool_t *ckp, int prio) { bool new_block = false; workbase_t *wb; json_t *val; char *buf; - buf = send_recv_proc(ckp->generator, "getbase"); + buf = send_recv_generator(ckp, "getbase", prio); if (unlikely(!buf)) { LOGWARNING("Failed to get base from generator in update_base"); return; @@ -1026,7 +1078,7 @@ static void block_solve(ckpool_t *ckp) "createinet", ckp->serverurl); ck_runlock(&workbase_lock); - update_base(ckp); + update_base(ckp, GEN_PRIORITY); ck_rlock(&workbase_lock); json_set_string(val, "blockhash", current_workbase->prevhash); @@ -1059,7 +1111,7 @@ retry: copy_tv(&start_tv, &end_tv); LOGDEBUG("%ds elapsed in strat_loop, updating gbt base", ckp->update_interval); - update_base(ckp); + update_base(ckp, GEN_NORMAL); continue; } } @@ -1098,7 +1150,7 @@ retry: ret = 0; goto out; } else if (cmdmatch(buf, "update")) { - update_base(ckp); + update_base(ckp, GEN_PRIORITY); } else if (cmdmatch(buf, "subscribe")) { /* Proxifier has a new subscription */ if (!update_subscribe(ckp)) @@ -1154,7 +1206,7 @@ static void *blockupdate(void *arg) memset(hash, 0, 68); while (42) { dealloc(buf); - buf = send_recv_proc(ckp->generator, request); + buf = send_recv_generator(ckp, request, GEN_LAX); if (buf && strcmp(buf, hash) && !cmdmatch(buf, "failed")) { strcpy(hash, buf); LOGNOTICE("Block hash changed to %s", hash); @@ -1265,7 +1317,8 @@ static bool test_address(ckpool_t *ckp, const char *address) char *buf, *msg; ASPRINTF(&msg, "checkaddr:%s", address); - buf = send_recv_proc(ckp->generator, msg); + /* Must wait for a response here */ + buf = __send_recv_generator(ckp, msg, GEN_LAX); dealloc(msg); if (!buf) return ret; @@ -1649,7 +1702,7 @@ test_blocksolve(stratum_instance_t *client, workbase_t *wb, const uchar *data, c if (wb->transactions) realloc_strcat(&gbt_block, wb->txn_data); ckp = wb->ckp; - send_proc(ckp->generator, gbt_block); + send_generator(ckp, gbt_block, GEN_PRIORITY); free(gbt_block); flip_32(swap, hash); @@ -1770,7 +1823,7 @@ static void submit_share(stratum_instance_t *client, int64_t jobid, const char * "msg_id", msg_id); msg = json_dumps(json_msg, 0); json_decref(json_msg); - send_proc(ckp->generator, msg); + send_generator(ckp, msg, GEN_LAX); free(msg); } From 08ea17dacb3f4959c1471e1dbe0df625e1d63672 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 2 Sep 2014 14:55:58 +1000 Subject: [PATCH 7/8] Resetting first share in diff calculations leads to overshoot. Revert it and start a new diff calculation period when the hashrate appears lower instead. --- src/stratifier.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index e12cbcdd..f31d4949 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1578,7 +1578,7 @@ static void add_submit(ckpool_t *ckp, stratum_instance_t *client, int diff, bool network_diff = current_workbase->network_diff; ck_runlock(&workbase_lock); - if (!client->first_share.tv_sec) { + if (unlikely(!client->first_share.tv_sec)) { copy_tv(&client->first_share, &now_t); copy_tv(&client->ldc, &now_t); } @@ -1618,7 +1618,6 @@ static void add_submit(ckpool_t *ckp, stratum_instance_t *client, int diff, bool if (diff != client->diff) { client->ssdc = 0; - client->first_share.tv_sec = 0; return; } @@ -1639,7 +1638,14 @@ static void add_submit(ckpool_t *ckp, stratum_instance_t *client, int diff, bool if (client->diff == optimal) return; - client->first_share.tv_sec = 0; + /* If this is the first share in a change, reset the last diff change + * to make sure the client hasn't just fallen back after a leave of + * absence */ + if (optimal < client->diff && client->ssdc == 1) { + copy_tv(&client->ldc, &now_t); + return; + } + client->ssdc = 0; LOGINFO("Client %d biased dsps %.2f dsps %.2f drr %.2f adjust diff from %ld to: %ld ", From 907e1c81d3ddc31068ba55bf93a886feb511feed Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 2 Sep 2014 15:06:58 +1000 Subject: [PATCH 8/8] Import jansson huge val fix --- src/jansson-2.6/src/strconv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/jansson-2.6/src/strconv.c b/src/jansson-2.6/src/strconv.c index 3e2cb7c4..58cf4ad3 100644 --- a/src/jansson-2.6/src/strconv.c +++ b/src/jansson-2.6/src/strconv.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "jansson_private.h" #include "strbuffer.h" @@ -69,7 +70,7 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out) value = strtod(strbuffer->value, &end); assert(end == strbuffer->value + strbuffer->length); - if(errno == ERANGE && value != 0) { + if((value == HUGE_VAL || value == -HUGE_VAL) && errno == ERANGE) { /* Overflow */ return -1; }