-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Reconnect #1135
Changes from 9 commits
4ccc26a
6e1d650
9d1f99d
11133f7
a713f03
f69078e
0722124
5681a7c
c297baf
da3f08a
4c70f0a
0989ed1
c667186
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,7 @@ | |
#include <boost/algorithm/string.hpp> | ||
#include <boost/algorithm/string/trim_all.hpp> | ||
#include <boost/optional.hpp> | ||
#include <thread> | ||
|
||
#include <libethcore/Exceptions.h> | ||
#include <libethcore/EthashAux.h> | ||
|
@@ -92,6 +93,47 @@ class MinerCLI | |
Stratum | ||
}; | ||
|
||
MinerCLI() : | ||
m_io_work(m_io_service), | ||
m_io_work_timer(m_io_service), | ||
m_io_strand(m_io_service) | ||
{ | ||
// Post first deadline timer to give io_service | ||
// initial work | ||
m_io_work_timer.expires_from_now(boost::posix_time::seconds(60)); | ||
m_io_work_timer.async_wait(m_io_strand.wrap(boost::bind(&MinerCLI::io_work_timer_handler, this, boost::asio::placeholders::error))); | ||
|
||
// Start io_service in it's own thread | ||
m_io_thread = std::thread{ boost::bind(&boost::asio::io_service::run, &m_io_service) }; | ||
|
||
// Io service is now live and running | ||
// All components using io_service should post to reference of m_io_service | ||
// and should not start/stop or even join threads (which heavily time consuming) | ||
|
||
|
||
} | ||
|
||
void io_work_timer_handler(const boost::system::error_code& ec) { | ||
|
||
if (!ec) { | ||
|
||
// This does absolutely nothing aside resubmitting timer | ||
// ensuring io_service's queue has always something to do | ||
m_io_work_timer.expires_from_now(boost::posix_time::seconds(120)); | ||
m_io_work_timer.async_wait(m_io_strand.wrap(boost::bind(&MinerCLI::io_work_timer_handler, this, boost::asio::placeholders::error))); | ||
|
||
} | ||
|
||
} | ||
|
||
void stop_io_service() { | ||
|
||
// Here we stop all io_service's related activities | ||
m_io_service.stop(); | ||
m_io_thread.join(); | ||
|
||
} | ||
|
||
static void signalHandler(int sig) | ||
{ | ||
(void)sig; | ||
|
@@ -197,7 +239,7 @@ class MinerCLI | |
{ | ||
string url = argv[++i]; | ||
if (url == "exit") // add fake scheme and port to 'exit' url | ||
url = "stratum://exit:1"; | ||
url = "stratum+tcp://-:x@exit:0"; | ||
URI uri; | ||
try { | ||
uri = url; | ||
|
@@ -542,6 +584,7 @@ class MinerCLI | |
if (m_minerType == MinerType::CUDA || m_minerType == MinerType::Mixed) | ||
CUDAMiner::listDevices(); | ||
#endif | ||
stop_io_service(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you try return from function instead of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did not change the logic of functions not related to the scope of this pr. |
||
exit(0); | ||
} | ||
|
||
|
@@ -562,16 +605,19 @@ class MinerCLI | |
CLMiner::setThreadsPerHash(m_openclThreadsPerHash); | ||
|
||
if (!CLMiner::configureGPU( | ||
m_localWorkSize, | ||
m_globalWorkSizeMultiplier, | ||
m_openclPlatform, | ||
0, | ||
m_dagLoadMode, | ||
m_dagCreateDevice, | ||
m_noEval, | ||
m_exit | ||
)) | ||
m_localWorkSize, | ||
m_globalWorkSizeMultiplier, | ||
m_openclPlatform, | ||
0, | ||
m_dagLoadMode, | ||
m_dagCreateDevice, | ||
m_noEval, | ||
m_exit | ||
)) { | ||
stop_io_service(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This Long term, I have better way of handling list of devices. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually I start the io_service at MinerCLI constructor thus I need to stop it whenever MinerCLI exits There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also ... aside from list-devices asio_service is always needed. |
||
exit(1); | ||
}; | ||
|
||
CLMiner::setNumInstances(m_miningThreads); | ||
#else | ||
cerr << "Selected GPU mining without having compiled with -DETHASHCL=1" << endl; | ||
|
@@ -597,12 +643,16 @@ class MinerCLI | |
m_dagCreateDevice, | ||
m_noEval, | ||
m_exit | ||
)) | ||
)) | ||
{ | ||
stop_io_service(); | ||
exit(1); | ||
} | ||
|
||
CUDAMiner::setParallelHash(m_parallelHash); | ||
#else | ||
cerr << "CUDA support disabled. Configure project build with -DETHASHCUDA=ON" << endl; | ||
stop_io_service(); | ||
exit(1); | ||
#endif | ||
} | ||
|
@@ -706,7 +756,7 @@ class MinerCLI | |
genesis.setNumber(m_benchmarkBlock); | ||
genesis.setDifficulty(u256(1) << 64); | ||
|
||
Farm f; | ||
Farm f(m_io_service); | ||
map<string, Farm::SealerDescriptor> sealers; | ||
#if ETH_ETHASHCL | ||
sealers["opencl"] = Farm::SealerDescriptor{ | ||
|
@@ -769,7 +819,7 @@ class MinerCLI | |
} | ||
else | ||
cout << "inner mean: n/a" << endl; | ||
|
||
stop_io_service(); | ||
exit(0); | ||
} | ||
|
||
|
@@ -783,10 +833,12 @@ class MinerCLI | |
sealers["cuda"] = Farm::SealerDescriptor{&CUDAMiner::instances, [](FarmFace& _farm, unsigned _index){ return new CUDAMiner(_farm, _index); }}; | ||
#endif | ||
|
||
//EthStratumClient::pointer client = EthStratumClient::create(m_worktimeout, m_responsetimeout, m_email, m_report_stratum_hashrate); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Delete old code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wilco |
||
|
||
PoolClient *client = nullptr; | ||
|
||
if (m_mode == OperationMode::Stratum) { | ||
client = new EthStratumClient(m_worktimeout, m_responsetimeout, m_email, m_report_stratum_hashrate); | ||
client = new EthStratumClient(m_io_service, m_worktimeout, m_responsetimeout, m_email, m_report_stratum_hashrate); | ||
} | ||
else if (m_mode == OperationMode::Farm) { | ||
client = new EthGetworkClient(m_farmRecheckPeriod); | ||
|
@@ -802,15 +854,15 @@ class MinerCLI | |
// Should not happen! | ||
if (!client) { | ||
cwarn << "Invalid PoolClient"; | ||
stop_io_service(); | ||
exit(1); | ||
} | ||
|
||
//sealers, m_minerType | ||
Farm f; | ||
Farm f(m_io_service); | ||
f.setSealers(sealers); | ||
|
||
PoolManager mgr(client, f, m_minerType); | ||
mgr.setReconnectTries(m_maxFarmRetries); | ||
PoolManager mgr(client, f, m_minerType, m_maxFarmRetries); | ||
|
||
// If we are in simulation mode we add a fake connection | ||
if (m_mode == OperationMode::Simulation) { | ||
|
@@ -848,13 +900,22 @@ class MinerCLI | |
} | ||
|
||
mgr.stop(); | ||
stop_io_service(); | ||
|
||
cnote << "Terminated !"; | ||
exit(0); | ||
} | ||
|
||
/// Operating mode. | ||
OperationMode m_mode = OperationMode::None; | ||
|
||
/// Global boost's io_service | ||
std::thread m_io_thread; // The IO service thread | ||
boost::asio::io_service m_io_service; // The IO service itself | ||
boost::asio::io_service::work m_io_work; // The IO work which prevents io_service.run() to return on no work thus terminating thread | ||
boost::asio::deadline_timer m_io_work_timer; // A dummy timer to keep io_service with something to do and prevent io shutdown | ||
boost::asio::io_service::strand m_io_strand; // A strand to serialize posts in multithreaded environment | ||
|
||
/// Mining options | ||
MinerType m_minerType = MinerType::Mixed; | ||
unsigned m_openclPlatform = 0; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,7 +56,9 @@ class Farm: public FarmFace | |
std::function<Miner*(FarmFace&, unsigned)> create; | ||
}; | ||
|
||
Farm(): m_hashrateTimer(m_io_service) | ||
Farm(boost::asio::io_service & io_service): | ||
m_io_strand(io_service), | ||
m_hashrateTimer(io_service) | ||
{ | ||
// Given that all nonces are equally likely to solve the problem | ||
// we could reasonably always start the nonce search ranges | ||
|
@@ -153,14 +155,14 @@ class Farm: public FarmFace | |
// Start hashrate collector | ||
m_hashrateTimer.cancel(); | ||
m_hashrateTimer.expires_from_now(boost::posix_time::milliseconds(1000)); | ||
m_hashrateTimer.async_wait(boost::bind(&Farm::processHashRate, this, boost::asio::placeholders::error)); | ||
m_hashrateTimer.async_wait(m_io_strand.wrap(boost::bind(&Farm::processHashRate, this, boost::asio::placeholders::error))); | ||
|
||
if (m_serviceThread.joinable()) { | ||
m_io_service.reset(); | ||
m_serviceThread.join(); | ||
} | ||
//if (m_serviceThread.joinable()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Delete old code |
||
// m_io_service.reset(); | ||
// m_serviceThread.join(); | ||
//} | ||
|
||
m_serviceThread = std::thread{ boost::bind(&boost::asio::io_service::run, &m_io_service) }; | ||
//m_serviceThread = std::thread{ boost::bind(&boost::asio::io_service::run, &m_io_service) }; | ||
|
||
return true; | ||
} | ||
|
@@ -177,7 +179,6 @@ class Farm: public FarmFace | |
} | ||
|
||
m_hashrateTimer.cancel(); | ||
m_io_service.stop(); | ||
|
||
m_lastProgresses.clear(); | ||
} | ||
|
@@ -219,9 +220,8 @@ class Farm: public FarmFace | |
collectHashRate(); | ||
|
||
// Restart timer | ||
m_hashrateTimer.cancel(); | ||
m_hashrateTimer.expires_from_now(boost::posix_time::milliseconds(1000)); | ||
m_hashrateTimer.async_wait(boost::bind(&Farm::processHashRate, this, boost::asio::placeholders::error)); | ||
m_hashrateTimer.async_wait(m_io_strand.wrap(boost::bind(&Farm::processHashRate, this, boost::asio::placeholders::error))); | ||
} | ||
} | ||
|
||
|
@@ -437,15 +437,17 @@ class Farm: public FarmFace | |
|
||
std::chrono::steady_clock::time_point m_lastStart; | ||
uint64_t m_hashrateSmoothInterval = 10000; | ||
std::thread m_serviceThread; ///< The IO service thread. | ||
boost::asio::io_service m_io_service; | ||
|
||
// std::thread m_serviceThread; ///< The IO service thread. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Delete old code. |
||
|
||
boost::asio::io_service::strand m_io_strand; | ||
boost::asio::deadline_timer m_hashrateTimer; | ||
std::vector<WorkingProgress> m_lastProgresses; | ||
|
||
mutable SolutionStats m_solutionStats; | ||
std::chrono::steady_clock::time_point m_farm_launched = std::chrono::steady_clock::now(); | ||
|
||
string m_pool_addresses; | ||
string m_pool_addresses; | ||
uint64_t m_nonce_scrambler; | ||
|
||
wrap_nvml_handle *nvmlh = NULL; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this fake job is needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Every time io_service starts allocates it's own thread_pool.
When there are no more jobs in the poll queue it destroys all it's threads and recreation is very long time consuming. Also on Windows apparently it does not restart properly.
This fake job gives the poll queue always something to do so it never stops.