Skip to content
This repository has been archived by the owner on Apr 24, 2022. It is now read-only.

Reconnect #1135

Merged
merged 13 commits into from
May 25, 2018
95 changes: 78 additions & 17 deletions ethminer/MinerAux.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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));
Copy link
Contributor

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?

Copy link
Collaborator Author

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.

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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -542,6 +584,7 @@ class MinerCLI
if (m_minerType == MinerType::CUDA || m_minerType == MinerType::Mixed)
CUDAMiner::listDevices();
#endif
stop_io_service();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you try return from function instead of exit().

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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 was there before: I only addedd the stop_io_service before exiting.

exit(0);
}

Expand All @@ -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();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This stop_io_service() seems to be a bad pattern. Is there a way to start the service only when needed?

Long term, I have better way of handling list of devices.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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;
Expand All @@ -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
}
Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -769,7 +819,7 @@ class MinerCLI
}
else
cout << "inner mean: n/a" << endl;

stop_io_service();
exit(0);
}

Expand All @@ -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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete old code.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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);
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
28 changes: 15 additions & 13 deletions libethcore/Farm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()) {
Copy link
Contributor

Choose a reason for hiding this comment

The 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;
}
Expand All @@ -177,7 +179,6 @@ class Farm: public FarmFace
}

m_hashrateTimer.cancel();
m_io_service.stop();

m_lastProgresses.clear();
}
Expand Down Expand Up @@ -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)));
}
}

Expand Down Expand Up @@ -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.
Copy link
Contributor

Choose a reason for hiding this comment

The 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;
Expand Down
6 changes: 5 additions & 1 deletion libpoolprotocols/PoolClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ namespace dev
class PoolClient
{
public:
virtual ~PoolClient() noexcept = default;


void setConnection(URI &conn)
{
m_conn = conn;
Expand All @@ -28,6 +31,7 @@ namespace dev
virtual void submitHashrate(string const & rate) = 0;
virtual void submitSolution(Solution solution) = 0;
virtual bool isConnected() = 0;
virtual bool isPendingState() = 0;
virtual string ActiveEndPoint() = 0;

using SolutionAccepted = std::function<void(bool const&)>;
Expand All @@ -46,7 +50,7 @@ namespace dev
bool m_authorized = false;
bool m_connected = false;
bool m_connection_changed = false;
boost::asio::ip::tcp::endpoint m_endpoint;
boost::asio::ip::basic_endpoint<boost::asio::ip::tcp> m_endpoint;

URI m_conn;

Expand Down
Loading