summaryrefslogtreecommitdiffstats
path: root/xmrstak/misc/executor.hpp
blob: fbaa265173141c17764f11d7d29c8ad8db81906d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#pragma once

#include "thdq.hpp"
#include "telemetry.hpp"
#include "xmrstak/backend/iBackend.hpp"
#include "xmrstak/misc/environment.hpp"
#include "xmrstak/net/msgstruct.hpp"
#include "xmrstak/donate-level.hpp"

#include <atomic>
#include <array>
#include <list>
#include <vector>
#include <future>
#include <chrono>

class jpsock;

namespace xmrstak
{
namespace cpu
{
class minethd;

} // namespace cpu
} // namepsace xmrstak

class executor
{
public:
	static executor* inst()
	{
		auto& env = xmrstak::environment::inst();
		if(env.pExecutor == nullptr)
			env.pExecutor = new executor;
		return env.pExecutor;
	};

	void ex_start(bool daemon) { daemon ? ex_main() : std::thread(&executor::ex_main, this).detach(); }

	void get_http_report(ex_event_name ev_id, std::string& data);

	inline void push_event(ex_event&& ev) { oEventQ.push(std::move(ev)); }
	void push_timed_event(ex_event&& ev, size_t sec);

private:
	struct timed_event
	{
		ex_event event;
		size_t ticks_left;

		timed_event(ex_event&& ev, size_t ticks) : event(std::move(ev)), ticks_left(ticks) {}
	};

	inline void set_timestamp() { dev_timestamp = get_timestamp(); };

	// In miliseconds, has to divide a second (1000ms) into an integer number
	constexpr static size_t iTickTime = 500;

	// Dev donation time period in seconds. 100 minutes by default.
	// We will divide up this period according to the config setting
	constexpr static size_t iDevDonatePeriod = 100 * 60;

	inline bool is_dev_time()
	{
		//Add 2 seconds to compensate for connect
		constexpr size_t dev_portion = double(iDevDonatePeriod) * fDevDonationLevel + 2;

		if(dev_portion < 12) //No point in bothering with less than 10s
			return false;

		return (get_timestamp() - dev_timestamp) % iDevDonatePeriod >= (iDevDonatePeriod - dev_portion);
	};

	std::list<timed_event> lTimedEvents;
	std::mutex timed_event_mutex;
	thdq<ex_event> oEventQ;

	xmrstak::telemetry* telem;
	std::vector<xmrstak::iBackend*>* pvThreads;

	size_t current_pool_id = invalid_pool_id;
	size_t last_usr_pool_id = invalid_pool_id;
	size_t dev_timestamp;

	std::list<jpsock> pools;

	jpsock* pick_pool_by_id(size_t pool_id);

	executor();

	void ex_main();

	void ex_clock_thd();
	void pool_connect(jpsock* pool);

	constexpr static size_t motd_max_length = 512;
	bool motd_filter_console(std::string& motd);
	bool motd_filter_web(std::string& motd);

	void hashrate_report(std::string& out);
	void result_report(std::string& out);
	void connection_report(std::string& out);

	void http_hashrate_report(std::string& out);
	void http_result_report(std::string& out);
	void http_connection_report(std::string& out);
	void http_json_report(std::string& out);

	void http_report(ex_event_name ev);
	void print_report(ex_event_name ev);

	std::string* pHttpString = nullptr;
	std::promise<void> httpReady;
	std::mutex httpMutex;

	struct sck_error_log
	{
		std::chrono::system_clock::time_point time;
		std::string msg;

		sck_error_log(std::string&& err) : msg(std::move(err))
		{
			time = std::chrono::system_clock::now();
		}
	};
	std::vector<sck_error_log> vSocketLog;

	// Element zero is always the success element.
	// Keep in mind that this is a tally and not a log like above
	struct result_tally
	{
		std::chrono::system_clock::time_point time;
		std::string msg;
		size_t count;

		result_tally() : msg("[OK]"), count(0)
		{
			time = std::chrono::system_clock::now();
		}

		result_tally(std::string&& err) : msg(std::move(err)), count(1)
		{
			time = std::chrono::system_clock::now();
		}

		void increment()
		{
			count++;
			time = std::chrono::system_clock::now();
		}

		bool compare(std::string& err)
		{
			if(msg == err)
				return true;
			else
				return false;
		}
	};
	std::vector<result_tally> vMineResults;

	//More result statistics
	std::array<size_t, 10> iTopDiff { { } }; //Initialize to zero

	std::chrono::system_clock::time_point tPoolConnTime;
	size_t iPoolHashes = 0;
	uint64_t iPoolDiff = 0;

	// Set it to 16 bit so that we can just let it grow
	// Maximum realistic growth rate - 5MB / month
	std::vector<uint16_t> iPoolCallTimes;

	//Those stats are reset if we disconnect
	inline void reset_stats()
	{
		iPoolCallTimes.clear();
		tPoolConnTime = std::chrono::system_clock::now();
		iPoolHashes = 0;
	}

	double fHighestHps = 0.0;

	void log_socket_error(jpsock* pool, std::string&& sError);
	void log_result_error(std::string&& sError);
	void log_result_ok(uint64_t iActualDiff);

	void on_sock_ready(size_t pool_id);
	void on_sock_error(size_t pool_id, std::string&& sError, bool silent);
	void on_pool_have_job(size_t pool_id, pool_job& oPoolJob);
	void on_miner_result(size_t pool_id, job_result& oResult);
	void connect_to_pools(std::list<jpsock*>& eval_pools);
	bool get_live_pools(std::vector<jpsock*>& eval_pools, bool is_dev);
	void eval_pool_choice();

	inline size_t sec_to_ticks(size_t sec) { return sec * (1000 / iTickTime); }
};

OpenPOWER on IntegriCloud