diff options
author | psychocrypt <psychocrypt@users.noreply.github.com> | 2017-09-29 20:32:31 +0200 |
---|---|---|
committer | psychocrypt <psychocrypt@users.noreply.github.com> | 2017-09-30 23:46:08 +0200 |
commit | cc429b68fadc502b981fd0acd64a5ff6e2ae1d15 (patch) | |
tree | 3fb23fc4db15dbdd08af4c7ea20134b9d82e58fd /executor.cpp | |
parent | e5b0319d5a9f58762fa934ad700113908940cb31 (diff) | |
download | xmr-stak-cc429b68fadc502b981fd0acd64a5ff6e2ae1d15.zip xmr-stak-cc429b68fadc502b981fd0acd64a5ff6e2ae1d15.tar.gz |
group files
- move source code to `src`
- categorize files and move to group folder
- change upper case class files to lower case
- change C++ header to `*.hpp`
Diffstat (limited to 'executor.cpp')
-rw-r--r-- | executor.cpp | 1005 |
1 files changed, 0 insertions, 1005 deletions
diff --git a/executor.cpp b/executor.cpp deleted file mode 100644 index 64f3d40..0000000 --- a/executor.cpp +++ /dev/null @@ -1,1005 +0,0 @@ -/* - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * Additional permission under GNU GPL version 3 section 7 - * - * If you modify this Program, or any covered work, by linking or combining - * it with OpenSSL (or a modified version of that library), containing parts - * covered by the terms of OpenSSL License and SSLeay License, the licensors - * of this Program grant you additional permission to convey the resulting work. - * - */ - -#include <thread> -#include <string> -#include <cmath> -#include <algorithm> -#include <assert.h> -#include <time.h> -#include "executor.h" -#include "jpsock.h" - -#include "telemetry.h" -#include "backend/miner_work.h" -#include "backend/GlobalStates.hpp" -#include "backend/BackendConnector.hpp" - -#include "jconf.h" -#include "console.h" -#include "donate-level.h" -#include "webdesign.h" - -#ifdef _WIN32 -#define strncasecmp _strnicmp -#endif // _WIN32 - -executor::executor() -{ -} - -void executor::push_timed_event(ex_event&& ev, size_t sec) -{ - std::unique_lock<std::mutex> lck(timed_event_mutex); - lTimedEvents.emplace_back(std::move(ev), sec_to_ticks(sec)); -} - -void executor::ex_clock_thd() -{ - size_t iSwitchPeriod = sec_to_ticks(iDevDonatePeriod); - size_t iDevPortion = (size_t)floor(((double)iSwitchPeriod) * fDevDonationLevel); - - //No point in bothering with less than 10 sec - if(iDevPortion < sec_to_ticks(10)) - iDevPortion = 0; - - //Add 2 seconds to compensate for connect - if(iDevPortion != 0) - iDevPortion += sec_to_ticks(2); - - while (true) - { - std::this_thread::sleep_for(std::chrono::milliseconds(size_t(iTickTime))); - - push_event(ex_event(EV_PERF_TICK)); - - // Service timed events - std::unique_lock<std::mutex> lck(timed_event_mutex); - std::list<timed_event>::iterator ev = lTimedEvents.begin(); - while (ev != lTimedEvents.end()) - { - ev->ticks_left--; - if(ev->ticks_left == 0) - { - push_event(std::move(ev->event)); - ev = lTimedEvents.erase(ev); - } - else - ev++; - } - lck.unlock(); - - if(iDevPortion == 0) - continue; - - iSwitchPeriod--; - if(iSwitchPeriod == 0) - { - push_event(ex_event(EV_SWITCH_POOL, usr_pool_id)); - iSwitchPeriod = sec_to_ticks(iDevDonatePeriod); - } - else if(iSwitchPeriod == iDevPortion) - { - push_event(ex_event(EV_SWITCH_POOL, dev_pool_id)); - } - } -} - -void executor::sched_reconnect() -{ - iReconnectAttempts++; - size_t iLimit = jconf::inst()->GetGiveUpLimit(); - if(iLimit != 0 && iReconnectAttempts > iLimit) - { - printer::inst()->print_msg(L0, "Give up limit reached. Exitting."); - exit(0); - } - - long long unsigned int rt = jconf::inst()->GetNetRetry(); - printer::inst()->print_msg(L1, "Pool connection lost. Waiting %lld s before retry (attempt %llu).", - rt, int_port(iReconnectAttempts)); - - auto work = xmrstak::miner_work(); - xmrstak::GlobalStates::inst().switch_work(work); - - push_timed_event(ex_event(EV_RECONNECT, usr_pool_id), rt); -} - -void executor::log_socket_error(std::string&& sError) -{ - vSocketLog.emplace_back(std::move(sError)); - printer::inst()->print_msg(L1, "SOCKET ERROR - %s", vSocketLog.back().msg.c_str()); -} - -void executor::log_result_error(std::string&& sError) -{ - size_t i = 1, ln = vMineResults.size(); - for(; i < ln; i++) - { - if(vMineResults[i].compare(sError)) - { - vMineResults[i].increment(); - break; - } - } - - if(i == ln) //Not found - vMineResults.emplace_back(std::move(sError)); - else - sError.clear(); -} - -void executor::log_result_ok(uint64_t iActualDiff) -{ - iPoolHashes += iPoolDiff; - - size_t ln = iTopDiff.size() - 1; - if(iActualDiff > iTopDiff[ln]) - { - iTopDiff[ln] = iActualDiff; - std::sort(iTopDiff.rbegin(), iTopDiff.rend()); - } - - vMineResults[0].increment(); -} - -jpsock* executor::pick_pool_by_id(size_t pool_id) -{ - assert(pool_id != invalid_pool_id); - - if(pool_id == dev_pool_id) - return dev_pool; - else - return usr_pool; -} - -void executor::on_sock_ready(size_t pool_id) -{ - jpsock* pool = pick_pool_by_id(pool_id); - - if(pool_id == dev_pool_id) - { - if(!pool->cmd_login("", "")) - pool->disconnect(); - - current_pool_id = dev_pool_id; - printer::inst()->print_msg(L1, "Dev pool logged in. Switching work."); - return; - } - - printer::inst()->print_msg(L1, "Connected. Logging in..."); - - if (!pool->cmd_login(jconf::inst()->GetWalletAddress(), jconf::inst()->GetPoolPwd())) - { - if(!pool->have_sock_error()) - { - log_socket_error(pool->get_call_error()); - pool->disconnect(); - } - } - else - { - iReconnectAttempts = 0; - reset_stats(); - } -} - -void executor::on_sock_error(size_t pool_id, std::string&& sError) -{ - jpsock* pool = pick_pool_by_id(pool_id); - - if(pool_id == dev_pool_id) - { - pool->disconnect(); - - if(current_pool_id != dev_pool_id) - return; - - printer::inst()->print_msg(L1, "Dev pool connection error. Switching work."); - on_switch_pool(usr_pool_id); - return; - } - - log_socket_error(std::move(sError)); - pool->disconnect(); - sched_reconnect(); -} - -void executor::on_pool_have_job(size_t pool_id, pool_job& oPoolJob) -{ - if(pool_id != current_pool_id) - return; - - jpsock* pool = pick_pool_by_id(pool_id); - - xmrstak::miner_work oWork(oPoolJob.sJobID, oPoolJob.bWorkBlob, - oPoolJob.iWorkLen, oPoolJob.iResumeCnt, oPoolJob.iTarget, - pool_id); - - oWork.iTarget32 = oPoolJob.iTarget32; - - xmrstak::GlobalStates::inst().switch_work(oWork); - - if(pool_id == dev_pool_id) - return; - - if(iPoolDiff != pool->get_current_diff()) - { - iPoolDiff = pool->get_current_diff(); - printer::inst()->print_msg(L2, "Difficulty changed. Now: %llu.", int_port(iPoolDiff)); - } - - printer::inst()->print_msg(L3, "New block detected."); -} - -void executor::on_miner_result(size_t pool_id, job_result& oResult) -{ - jpsock* pool = pick_pool_by_id(pool_id); - - if(pool_id == dev_pool_id) - { - //Ignore errors silently - if(pool->is_running() && pool->is_logged_in()) - pool->cmd_submit(oResult.sJobID, oResult.iNonce, oResult.bResult); - - return; - } - - if (!pool->is_running() || !pool->is_logged_in()) - { - log_result_error("[NETWORK ERROR]"); - return; - } - - using namespace std::chrono; - size_t t_start = time_point_cast<milliseconds>(high_resolution_clock::now()).time_since_epoch().count(); - bool bResult = pool->cmd_submit(oResult.sJobID, oResult.iNonce, oResult.bResult); - size_t t_len = time_point_cast<milliseconds>(high_resolution_clock::now()).time_since_epoch().count() - t_start; - - if(t_len > 0xFFFF) - t_len = 0xFFFF; - iPoolCallTimes.push_back((uint16_t)t_len); - - if(bResult) - { - uint64_t* targets = (uint64_t*)oResult.bResult; - log_result_ok(jpsock::t64_to_diff(targets[3])); - printer::inst()->print_msg(L3, "Result accepted by the pool."); - } - else - { - if(!pool->have_sock_error()) - { - printer::inst()->print_msg(L3, "Result rejected by the pool."); - - std::string error = pool->get_call_error(); - - if(strncasecmp(error.c_str(), "Unauthenticated", 15) == 0) - { - printer::inst()->print_msg(L2, "Your miner was unable to find a share in time. Either the pool difficulty is too high, or the pool timeout is too low."); - pool->disconnect(); - } - - log_result_error(std::move(error)); - } - else - log_result_error("[NETWORK ERROR]"); - } -} - -void executor::on_reconnect(size_t pool_id) -{ - jpsock* pool = pick_pool_by_id(pool_id); - - std::string error; - if(pool_id == dev_pool_id) - return; - - printer::inst()->print_msg(L1, "Connecting to pool %s ...", jconf::inst()->GetPoolAddress()); - - if(!pool->connect(jconf::inst()->GetPoolAddress(), error)) - { - log_socket_error(std::move(error)); - sched_reconnect(); - } -} - -void executor::on_switch_pool(size_t pool_id) -{ - if(pool_id == current_pool_id) - return; - - jpsock* pool = pick_pool_by_id(pool_id); - if(pool_id == dev_pool_id) - { - std::string error; - - // If it fails, it fails, we carry on on the usr pool - // as we never receive further events - printer::inst()->print_msg(L1, "Connecting to dev pool..."); - const char* dev_pool_addr = jconf::inst()->GetTlsSetting() ? "donate.xmr-stak.net:6666" : "donate.xmr-stak.net:3333"; - if(!pool->connect(dev_pool_addr, error)) - printer::inst()->print_msg(L1, "Error connecting to dev pool. Staying with user pool."); - } - else - { - printer::inst()->print_msg(L1, "Switching back to user pool."); - - current_pool_id = pool_id; - pool_job oPoolJob; - - if(!pool->get_current_job(oPoolJob)) - { - pool->disconnect(); - return; - } - - xmrstak::miner_work oWork(oPoolJob.sJobID, oPoolJob.bWorkBlob, - oPoolJob.iWorkLen, oPoolJob.iResumeCnt, oPoolJob.iTarget, - pool_id); - - oWork.iTarget32 = oPoolJob.iTarget32; - - xmrstak::GlobalStates::inst().switch_work(oWork); - - if(dev_pool->is_running()) - push_timed_event(ex_event(EV_DEV_POOL_EXIT), 5); - } -} - -void executor::ex_main() -{ - assert(1000 % iTickTime == 0); - - xmrstak::miner_work oWork = xmrstak::miner_work(); - - // \todo collect all backend threads - pvThreads = xmrstak::BackendConnector::thread_starter(oWork); - - if(pvThreads->size()==0) - { - printer::inst()->print_msg(L1, "ERROR: No miner backend enabled."); - win_exit(); - } - - telem = new xmrstak::telemetry(pvThreads->size()); - - current_pool_id = usr_pool_id; - usr_pool = new jpsock(usr_pool_id, jconf::inst()->GetTlsSetting()); - dev_pool = new jpsock(dev_pool_id, jconf::inst()->GetTlsSetting()); - - ex_event ev; - std::thread clock_thd(&executor::ex_clock_thd, this); - - //This will connect us to the pool for the first time - push_event(ex_event(EV_RECONNECT, usr_pool_id)); - - // Place the default success result at position 0, it needs to - // be here even if our first result is a failure - vMineResults.emplace_back(); - - // If the user requested it, start the autohash printer - if(jconf::inst()->GetVerboseLevel() >= 4) - push_timed_event(ex_event(EV_HASHRATE_LOOP), jconf::inst()->GetAutohashTime()); - - size_t cnt = 0, i; - while (true) - { - ev = oEventQ.pop(); - switch (ev.iName) - { - case EV_SOCK_READY: - on_sock_ready(ev.iPoolId); - break; - - case EV_SOCK_ERROR: - on_sock_error(ev.iPoolId, std::move(ev.sSocketError)); - break; - - case EV_POOL_HAVE_JOB: - on_pool_have_job(ev.iPoolId, ev.oPoolJob); - break; - - case EV_MINER_HAVE_RESULT: - on_miner_result(ev.iPoolId, ev.oJobResult); - break; - - case EV_RECONNECT: - on_reconnect(ev.iPoolId); - break; - - case EV_SWITCH_POOL: - on_switch_pool(ev.iPoolId); - break; - - case EV_DEV_POOL_EXIT: - dev_pool->disconnect(); - break; - - case EV_PERF_TICK: - for (i = 0; i < pvThreads->size(); i++) - telem->push_perf_value(i, pvThreads->at(i)->iHashCount.load(std::memory_order_relaxed), - pvThreads->at(i)->iTimestamp.load(std::memory_order_relaxed)); - - if((cnt++ & 0xF) == 0) //Every 16 ticks - { - double fHps = 0.0; - double fTelem; - bool normal = true; - - for (i = 0; i < pvThreads->size(); i++) - { - fTelem = telem->calc_telemetry_data(2500, i); - if(std::isnormal(fTelem)) - { - fHps += fTelem; - } - else - { - normal = false; - break; - } - } - - if(normal && fHighestHps < fHps) - fHighestHps = fHps; - } - break; - - case EV_USR_HASHRATE: - case EV_USR_RESULTS: - case EV_USR_CONNSTAT: - print_report(ev.iName); - break; - - case EV_HTML_HASHRATE: - case EV_HTML_RESULTS: - case EV_HTML_CONNSTAT: - case EV_HTML_JSON: - http_report(ev.iName); - break; - - case EV_HASHRATE_LOOP: - print_report(EV_USR_HASHRATE); - push_timed_event(ex_event(EV_HASHRATE_LOOP), jconf::inst()->GetAutohashTime()); - break; - - case EV_INVALID_VAL: - default: - assert(false); - break; - } - } -} - -inline const char* hps_format(double h, char* buf, size_t l) -{ - if(std::isnormal(h) || h == 0.0) - { - snprintf(buf, l, " %03.1f", h); - return buf; - } - else - return " (na)"; -} - -void executor::hashrate_report(std::string& out) -{ - char num[32]; - size_t nthd = pvThreads->size(); - - out.reserve(256 + nthd * 64); - - double fTotal[3] = { 0.0, 0.0, 0.0}; - size_t i; - - out.append("HASHRATE REPORT\n"); - out.append("| ID | 10s | 60s | 15m |"); - if(nthd != 1) - out.append(" ID | 10s | 60s | 15m |\n"); - else - out.append(1, '\n'); - - for (i = 0; i < nthd; i++) - { - double fHps[3]; - - fHps[0] = telem->calc_telemetry_data(10000, i); - fHps[1] = telem->calc_telemetry_data(60000, i); - fHps[2] = telem->calc_telemetry_data(900000, i); - - snprintf(num, sizeof(num), "| %2u |", (unsigned int)i); - out.append(num); - out.append(hps_format(fHps[0], num, sizeof(num))).append(" |"); - out.append(hps_format(fHps[1], num, sizeof(num))).append(" |"); - out.append(hps_format(fHps[2], num, sizeof(num))).append(1, ' '); - - fTotal[0] += fHps[0]; - fTotal[1] += fHps[1]; - fTotal[2] += fHps[2]; - - if((i & 0x1) == 1) //Odd i's - out.append("|\n"); - } - - if((i & 0x1) == 1) //We had odd number of threads - out.append("|\n"); - - if(nthd != 1) - out.append("-----------------------------------------------------\n"); - else - out.append("---------------------------\n"); - - out.append("Totals: "); - out.append(hps_format(fTotal[0], num, sizeof(num))); - out.append(hps_format(fTotal[1], num, sizeof(num))); - out.append(hps_format(fTotal[2], num, sizeof(num))); - out.append(" H/s\nHighest: "); - out.append(hps_format(fHighestHps, num, sizeof(num))); - out.append(" H/s\n"); -} - -char* time_format(char* buf, size_t len, std::chrono::system_clock::time_point time) -{ - time_t ctime = std::chrono::system_clock::to_time_t(time); - tm stime; - - /* - * Oh for god's sake... this feels like we are back to the 90's... - * and don't get me started on lack strcpy_s because NIH - use non-standard strlcpy... - * And of course C++ implements unsafe version because... reasons - */ - -#ifdef _WIN32 - localtime_s(&stime, &ctime); -#else - localtime_r(&ctime, &stime); -#endif // __WIN32 - strftime(buf, len, "%F %T", &stime); - - return buf; -} - -void executor::result_report(std::string& out) -{ - char num[128]; - char date[32]; - - out.reserve(1024); - - size_t iGoodRes = vMineResults[0].count, iTotalRes = iGoodRes; - size_t ln = vMineResults.size(); - - for(size_t i=1; i < ln; i++) - iTotalRes += vMineResults[i].count; - - out.append("RESULT REPORT\n"); - if(iTotalRes == 0) - { - out.append("You haven't found any results yet.\n"); - return; - } - - double dConnSec; - { - using namespace std::chrono; - dConnSec = (double)duration_cast<seconds>(system_clock::now() - tPoolConnTime).count(); - } - - snprintf(num, sizeof(num), " (%.1f %%)\n", 100.0 * iGoodRes / iTotalRes); - - out.append("Difficulty : ").append(std::to_string(iPoolDiff)).append(1, '\n'); - out.append("Good results : ").append(std::to_string(iGoodRes)).append(" / "). - append(std::to_string(iTotalRes)).append(num); - - if(iPoolCallTimes.size() != 0) - { - // Here we use iPoolCallTimes since it also gets reset when we disconnect - snprintf(num, sizeof(num), "%.1f sec\n", dConnSec / iPoolCallTimes.size()); - out.append("Avg result time : ").append(num); - } - out.append("Pool-side hashes : ").append(std::to_string(iPoolHashes)).append(2, '\n'); - out.append("Top 10 best results found:\n"); - - for(size_t i=0; i < 10; i += 2) - { - snprintf(num, sizeof(num), "| %2llu | %16llu | %2llu | %16llu |\n", - int_port(i), int_port(iTopDiff[i]), int_port(i+1), int_port(iTopDiff[i+1])); - out.append(num); - } - - out.append("\nError details:\n"); - if(ln > 1) - { - out.append("| Count | Error text | Last seen |\n"); - for(size_t i=1; i < ln; i++) - { - snprintf(num, sizeof(num), "| %5llu | %-32.32s | %s |\n", int_port(vMineResults[i].count), - vMineResults[i].msg.c_str(), time_format(date, sizeof(date), vMineResults[i].time)); - out.append(num); - } - } - else - out.append("Yay! No errors.\n"); -} - -void executor::connection_report(std::string& out) -{ - char num[128]; - char date[32]; - - out.reserve(512); - - jpsock* pool = pick_pool_by_id(dev_pool_id + 1); - - out.append("CONNECTION REPORT\n"); - out.append("Pool address : ").append(jconf::inst()->GetPoolAddress()).append(1, '\n'); - if (pool->is_running() && pool->is_logged_in()) - out.append("Connected since : ").append(time_format(date, sizeof(date), tPoolConnTime)).append(1, '\n'); - else - out.append("Connected since : <not connected>\n"); - - size_t n_calls = iPoolCallTimes.size(); - if (n_calls > 1) - { - //Not-really-but-good-enough median - std::nth_element(iPoolCallTimes.begin(), iPoolCallTimes.begin() + n_calls/2, iPoolCallTimes.end()); - out.append("Pool ping time : ").append(std::to_string(iPoolCallTimes[n_calls/2])).append(" ms\n"); - } - else - out.append("Pool ping time : (n/a)\n"); - - out.append("\nNetwork error log:\n"); - size_t ln = vSocketLog.size(); - if(ln > 0) - { - out.append("| Date | Error text |\n"); - for(size_t i=0; i < ln; i++) - { - snprintf(num, sizeof(num), "| %s | %-54.54s |\n", - time_format(date, sizeof(date), vSocketLog[i].time), vSocketLog[i].msg.c_str()); - out.append(num); - } - } - else - out.append("Yay! No errors.\n"); -} - -void executor::print_report(ex_event_name ev) -{ - std::string out; - switch(ev) - { - case EV_USR_HASHRATE: - hashrate_report(out); - break; - - case EV_USR_RESULTS: - result_report(out); - break; - - case EV_USR_CONNSTAT: - connection_report(out); - break; - default: - assert(false); - break; - } - - printer::inst()->print_str(out.c_str()); -} - -void executor::http_hashrate_report(std::string& out) -{ - char num_a[32], num_b[32], num_c[32], num_d[32]; - char buffer[4096]; - size_t nthd = pvThreads->size(); - - out.reserve(4096); - - snprintf(buffer, sizeof(buffer), sHtmlCommonHeader, "Hashrate Report", "Hashrate Report"); - out.append(buffer); - - snprintf(buffer, sizeof(buffer), sHtmlHashrateBodyHigh, (unsigned int)nthd + 3); - out.append(buffer); - - double fTotal[3] = { 0.0, 0.0, 0.0}; - for(size_t i=0; i < nthd; i++) - { - double fHps[3]; - - fHps[0] = telem->calc_telemetry_data(2500, i); - fHps[1] = telem->calc_telemetry_data(60000, i); - fHps[2] = telem->calc_telemetry_data(900000, i); - - num_a[0] = num_b[0] = num_c[0] ='\0'; - hps_format(fHps[0], num_a, sizeof(num_a)); - hps_format(fHps[1], num_b, sizeof(num_b)); - hps_format(fHps[2], num_c, sizeof(num_c)); - - fTotal[0] += fHps[0]; - fTotal[1] += fHps[1]; - fTotal[2] += fHps[2]; - - snprintf(buffer, sizeof(buffer), sHtmlHashrateTableRow, (unsigned int)i, num_a, num_b, num_c); - out.append(buffer); - } - - num_a[0] = num_b[0] = num_c[0] = num_d[0] ='\0'; - hps_format(fTotal[0], num_a, sizeof(num_a)); - hps_format(fTotal[1], num_b, sizeof(num_b)); - hps_format(fTotal[2], num_c, sizeof(num_c)); - hps_format(fHighestHps, num_d, sizeof(num_d)); - - snprintf(buffer, sizeof(buffer), sHtmlHashrateBodyLow, num_a, num_b, num_c, num_d); - out.append(buffer); -} - -void executor::http_result_report(std::string& out) -{ - char date[128]; - char buffer[4096]; - - out.reserve(4096); - - snprintf(buffer, sizeof(buffer), sHtmlCommonHeader, "Result Report", "Result Report"); - out.append(buffer); - - size_t iGoodRes = vMineResults[0].count, iTotalRes = iGoodRes; - size_t ln = vMineResults.size(); - - for(size_t i=1; i < ln; i++) - iTotalRes += vMineResults[i].count; - - double fGoodResPrc = 0.0; - if(iTotalRes > 0) - fGoodResPrc = 100.0 * iGoodRes / iTotalRes; - - double fAvgResTime = 0.0; - if(iPoolCallTimes.size() > 0) - { - using namespace std::chrono; - fAvgResTime = ((double)duration_cast<seconds>(system_clock::now() - tPoolConnTime).count()) - / iPoolCallTimes.size(); - } - - snprintf(buffer, sizeof(buffer), sHtmlResultBodyHigh, - iPoolDiff, iGoodRes, iTotalRes, fGoodResPrc, fAvgResTime, iPoolHashes, - int_port(iTopDiff[0]), int_port(iTopDiff[1]), int_port(iTopDiff[2]), int_port(iTopDiff[3]), - int_port(iTopDiff[4]), int_port(iTopDiff[5]), int_port(iTopDiff[6]), int_port(iTopDiff[7]), - int_port(iTopDiff[8]), int_port(iTopDiff[9])); - - out.append(buffer); - - for(size_t i=1; i < vMineResults.size(); i++) - { - snprintf(buffer, sizeof(buffer), sHtmlResultTableRow, vMineResults[i].msg.c_str(), - int_port(vMineResults[i].count), time_format(date, sizeof(date), vMineResults[i].time)); - out.append(buffer); - } - - out.append(sHtmlResultBodyLow); -} - -void executor::http_connection_report(std::string& out) -{ - char date[128]; - char buffer[4096]; - - out.reserve(4096); - - snprintf(buffer, sizeof(buffer), sHtmlCommonHeader, "Connection Report", "Connection Report"); - out.append(buffer); - - jpsock* pool = pick_pool_by_id(dev_pool_id + 1); - const char* cdate = "not connected"; - if (pool->is_running() && pool->is_logged_in()) - cdate = time_format(date, sizeof(date), tPoolConnTime); - - size_t n_calls = iPoolCallTimes.size(); - unsigned int ping_time = 0; - if (n_calls > 1) - { - //Not-really-but-good-enough median - std::nth_element(iPoolCallTimes.begin(), iPoolCallTimes.begin() + n_calls/2, iPoolCallTimes.end()); - ping_time = iPoolCallTimes[n_calls/2]; - } - - snprintf(buffer, sizeof(buffer), sHtmlConnectionBodyHigh, - jconf::inst()->GetPoolAddress(), - cdate, ping_time); - out.append(buffer); - - - for(size_t i=0; i < vSocketLog.size(); i++) - { - snprintf(buffer, sizeof(buffer), sHtmlConnectionTableRow, - time_format(date, sizeof(date), vSocketLog[i].time), vSocketLog[i].msg.c_str()); - out.append(buffer); - } - - out.append(sHtmlConnectionBodyLow); -} - -inline const char* hps_format_json(double h, char* buf, size_t l) -{ - if(std::isnormal(h) || h == 0.0) - { - snprintf(buf, l, "%.1f", h); - return buf; - } - else - return "null"; -} - -void executor::http_json_report(std::string& out) -{ - const char *a, *b, *c; - char num_a[32], num_b[32], num_c[32]; - char hr_buffer[64]; - std::string hr_thds, res_error, cn_error; - - size_t nthd = pvThreads->size(); - double fTotal[3] = { 0.0, 0.0, 0.0}; - hr_thds.reserve(nthd * 32); - - for(size_t i=0; i < nthd; i++) - { - if(i != 0) hr_thds.append(1, ','); - - double fHps[3]; - fHps[0] = telem->calc_telemetry_data(2500, i); - fHps[1] = telem->calc_telemetry_data(60000, i); - fHps[2] = telem->calc_telemetry_data(900000, i); - - fTotal[0] += fHps[0]; - fTotal[1] += fHps[1]; - fTotal[2] += fHps[2]; - - a = hps_format_json(fHps[0], num_a, sizeof(num_a)); - b = hps_format_json(fHps[1], num_b, sizeof(num_b)); - c = hps_format_json(fHps[2], num_c, sizeof(num_c)); - snprintf(hr_buffer, sizeof(hr_buffer), sJsonApiThdHashrate, a, b, c); - hr_thds.append(hr_buffer); - } - - a = hps_format_json(fTotal[0], num_a, sizeof(num_a)); - b = hps_format_json(fTotal[1], num_b, sizeof(num_b)); - c = hps_format_json(fTotal[2], num_c, sizeof(num_c)); - snprintf(hr_buffer, sizeof(hr_buffer), sJsonApiThdHashrate, a, b, c); - - a = hps_format_json(fHighestHps, num_a, sizeof(num_a)); - - size_t iGoodRes = vMineResults[0].count, iTotalRes = iGoodRes; - size_t ln = vMineResults.size(); - - for(size_t i=1; i < ln; i++) - iTotalRes += vMineResults[i].count; - - jpsock* pool = pick_pool_by_id(dev_pool_id + 1); - - size_t iConnSec = 0; - if(pool->is_running() && pool->is_logged_in()) - { - using namespace std::chrono; - iConnSec = duration_cast<seconds>(system_clock::now() - tPoolConnTime).count(); - } - - double fAvgResTime = 0.0; - if(iPoolCallTimes.size() > 0) - fAvgResTime = double(iConnSec) / iPoolCallTimes.size(); - - res_error.reserve((vMineResults.size() - 1) * 128); - char buffer[256]; - for(size_t i=1; i < vMineResults.size(); i++) - { - using namespace std::chrono; - if(i != 1) res_error.append(1, ','); - - snprintf(buffer, sizeof(buffer), sJsonApiResultError, int_port(vMineResults[i].count), - int_port(duration_cast<seconds>(vMineResults[i].time.time_since_epoch()).count()), - vMineResults[i].msg.c_str()); - res_error.append(buffer); - } - - size_t n_calls = iPoolCallTimes.size(); - size_t iPoolPing = 0; - if (n_calls > 1) - { - //Not-really-but-good-enough median - std::nth_element(iPoolCallTimes.begin(), iPoolCallTimes.begin() + n_calls/2, iPoolCallTimes.end()); - iPoolPing = iPoolCallTimes[n_calls/2]; - } - - cn_error.reserve(vSocketLog.size() * 128); - for(size_t i=0; i < vSocketLog.size(); i++) - { - using namespace std::chrono; - if(i != 0) cn_error.append(1, ','); - - snprintf(buffer, sizeof(buffer), sJsonApiConnectionError, - int_port(duration_cast<seconds>(vMineResults[i].time.time_since_epoch()).count()), - vSocketLog[i].msg.c_str()); - cn_error.append(buffer); - } - - size_t bb_size = 1024 + hr_thds.size() + res_error.size() + cn_error.size(); - std::unique_ptr<char[]> bigbuf( new char[ bb_size ] ); - - int bb_len = snprintf(bigbuf.get(), bb_size, sJsonApiFormat, - hr_thds.c_str(), hr_buffer, a, - int_port(iPoolDiff), int_port(iGoodRes), int_port(iTotalRes), fAvgResTime, int_port(iPoolHashes), - int_port(iTopDiff[0]), int_port(iTopDiff[1]), int_port(iTopDiff[2]), int_port(iTopDiff[3]), int_port(iTopDiff[4]), - int_port(iTopDiff[5]), int_port(iTopDiff[6]), int_port(iTopDiff[7]), int_port(iTopDiff[8]), int_port(iTopDiff[9]), - res_error.c_str(), jconf::inst()->GetPoolAddress(), int_port(iConnSec), int_port(iPoolPing), cn_error.c_str()); - - out = std::string(bigbuf.get(), bigbuf.get() + bb_len); -} - -void executor::http_report(ex_event_name ev) -{ - assert(pHttpString != nullptr); - - switch(ev) - { - case EV_HTML_HASHRATE: - http_hashrate_report(*pHttpString); - break; - - case EV_HTML_RESULTS: - http_result_report(*pHttpString); - break; - - case EV_HTML_CONNSTAT: - http_connection_report(*pHttpString); - break; - - case EV_HTML_JSON: - http_json_report(*pHttpString); - break; - - default: - assert(false); - break; - } - - httpReady.set_value(); -} - -void executor::get_http_report(ex_event_name ev_id, std::string& data) -{ - std::lock_guard<std::mutex> lck(httpMutex); - - assert(pHttpString == nullptr); - assert(ev_id == EV_HTML_HASHRATE || ev_id == EV_HTML_RESULTS - || ev_id == EV_HTML_CONNSTAT || ev_id == EV_HTML_JSON); - - pHttpString = &data; - httpReady = std::promise<void>(); - std::future<void> ready = httpReady.get_future(); - - push_event(ex_event(ev_id)); - - ready.wait(); - pHttpString = nullptr; -} |