summaryrefslogtreecommitdiffstats
path: root/executor.cpp
diff options
context:
space:
mode:
authorpsychocrypt <psychocrypt@users.noreply.github.com>2017-09-29 20:32:31 +0200
committerpsychocrypt <psychocrypt@users.noreply.github.com>2017-09-30 23:46:08 +0200
commitcc429b68fadc502b981fd0acd64a5ff6e2ae1d15 (patch)
tree3fb23fc4db15dbdd08af4c7ea20134b9d82e58fd /executor.cpp
parente5b0319d5a9f58762fa934ad700113908940cb31 (diff)
downloadxmr-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.cpp1005
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;
-}
OpenPOWER on IntegriCloud