Browse Source

Multi-threaded mining.

cl-refactor
Gav Wood 11 years ago
parent
commit
939ab1be34
  1. 2
      libethcore/Dagger.cpp
  2. 9
      libethcore/Dagger.h
  3. 95
      libethereum/Client.cpp
  4. 34
      libethereum/Client.h
  5. 3
      libethereum/Miner.cpp
  6. 29
      libethereum/Miner.h

2
libethcore/Dagger.cpp

@ -39,7 +39,7 @@ namespace eth
MineInfo Dagger::mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, uint _msTimeout, bool _continue, bool _turbo) MineInfo Dagger::mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, uint _msTimeout, bool _continue, bool _turbo)
{ {
MineInfo ret{0.f, 1e99, 0, false}; MineInfo ret;
static std::mt19937_64 s_eng((time(0) + (unsigned)m_last)); static std::mt19937_64 s_eng((time(0) + (unsigned)m_last));
u256 s = (m_last = h256::random(s_eng)); u256 s = (m_last = h256::random(s_eng));

9
libethcore/Dagger.h

@ -38,10 +38,11 @@ inline uint toLog2(u256 _d)
struct MineInfo struct MineInfo
{ {
double requirement; void combine(MineInfo const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); hashes += _m.hashes; completed = completed || _m.completed; }
double best; double requirement = 0;
uint hashes; double best = 1e99;
bool completed; uint hashes = 0;
bool completed = false;
}; };
#if FAKE_DAGGER #if FAKE_DAGGER

95
libethereum/Client.cpp

@ -56,9 +56,9 @@ Client::Client(std::string const& _clientVersion, Address _us, std::string const
m_bc(_dbPath, !m_vc.ok() || _forceClean), m_bc(_dbPath, !m_vc.ok() || _forceClean),
m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)), m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)),
m_preMine(_us, m_stateDB), m_preMine(_us, m_stateDB),
m_postMine(_us, m_stateDB), m_postMine(_us, m_stateDB)
m_miner(this)
{ {
setMiningThreads();
if (_dbPath.size()) if (_dbPath.size())
Defaults::setDBPath(_dbPath); Defaults::setDBPath(_dbPath);
m_vc.setOk(); m_vc.setOk();
@ -115,7 +115,11 @@ void Client::clearPending()
appendFromNewPending(m_postMine.bloom(i), changeds); appendFromNewPending(m_postMine.bloom(i), changeds);
changeds.insert(PendingChangedFilter); changeds.insert(PendingChangedFilter);
m_postMine = m_preMine; m_postMine = m_preMine;
m_miner.noteStateChange(); {
ReadGuard l(x_miners);
for (auto& m: m_miners)
m.noteStateChange();
}
noteChanged(changeds); noteChanged(changeds);
} }
@ -289,6 +293,46 @@ void Client::connect(std::string const& _seedHost, unsigned short _port)
m_net->connect(_seedHost, _port); m_net->connect(_seedHost, _port);
} }
void Client::setMiningThreads(unsigned _threads)
{
stopMining();
auto t = _threads ? _threads : thread::hardware_concurrency();
WriteGuard l(x_miners);
m_miners.clear();
m_miners.resize(t);
unsigned i = 0;
for (auto& m: m_miners)
m.setup(this, i++);
}
MineProgress Client::miningProgress() const
{
MineProgress ret;
ReadGuard l(x_miners);
for (auto& m: m_miners)
ret.combine(m.miningProgress());
return ret;
}
std::list<MineInfo> Client::miningHistory()
{
std::list<MineInfo> ret;
ReadGuard l(x_miners);
if (m_miners.empty())
return ret;
ret = m_miners[0].miningHistory();
for (unsigned i = 1; i < m_miners.size(); ++i)
{
auto l = m_miners[i].miningHistory();
auto ri = ret.begin();
auto li = l.begin();
for (; ri != ret.end() && li != l.end(); ++ri, ++li)
ri->combine(*li);
}
return ret;
}
void Client::setupState(State& _s) void Client::setupState(State& _s)
{ {
{ {
@ -410,23 +454,26 @@ void Client::work()
cworkin << "WORK"; cworkin << "WORK";
h256Set changeds; h256Set changeds;
if (m_miner.isComplete()) ReadGuard l(x_miners);
{ for (auto& m: m_miners)
cwork << "CHAIN <== postSTATE"; if (m.isComplete())
h256s hs;
{
WriteGuard l(x_stateDB);
hs = m_bc.attemptImport(m_miner.blockData(), m_stateDB);
}
if (hs.size())
{ {
for (auto h: hs) cwork << "CHAIN <== postSTATE";
appendFromNewBlock(h, changeds); h256s hs;
changeds.insert(ChainChangedFilter); {
//changeds.insert(PendingChangedFilter); // if we mined the new block, then we've probably reset the pending transactions. WriteGuard l(x_stateDB);
hs = m_bc.attemptImport(m.blockData(), m_stateDB);
}
if (hs.size())
{
for (auto h: hs)
appendFromNewBlock(h, changeds);
changeds.insert(ChainChangedFilter);
//changeds.insert(PendingChangedFilter); // if we mined the new block, then we've probably reset the pending transactions.
}
for (auto& m: m_miners)
m.noteStateChange();
} }
m_miner.noteStateChange();
}
// Synchronise state to block chain. // Synchronise state to block chain.
// This should remove any transactions on our queue that are included within our state. // This should remove any transactions on our queue that are included within our state.
@ -435,6 +482,7 @@ void Client::work()
// if there are no checkpoints before our fork) reverting to the genesis block and replaying // if there are no checkpoints before our fork) reverting to the genesis block and replaying
// all blocks. // all blocks.
// Resynchronise state with block chain & trans // Resynchronise state with block chain & trans
bool rsm = false;
{ {
WriteGuard l(x_stateDB); WriteGuard l(x_stateDB);
cwork << "BQ ==> CHAIN ==> STATE"; cwork << "BQ ==> CHAIN ==> STATE";
@ -451,8 +499,6 @@ void Client::work()
if (newBlocks.size()) if (newBlocks.size())
m_stateDB = db; m_stateDB = db;
bool rsm = false;
cwork << "preSTATE <== CHAIN"; cwork << "preSTATE <== CHAIN";
if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address()) if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address())
{ {
@ -474,9 +520,12 @@ void Client::work()
cnote << "Additional transaction ready: Restarting mining operation."; cnote << "Additional transaction ready: Restarting mining operation.";
rsm = true; rsm = true;
} }
}
if (rsm) if (rsm)
m_miner.noteStateChange(); {
ReadGuard l(x_miners);
for (auto& m: m_miners)
m.noteStateChange();
} }
cwork << "noteChanged" << changeds.size() << "items"; cwork << "noteChanged" << changeds.size() << "items";

34
libethereum/Client.h

@ -217,32 +217,39 @@ public:
bool miningParanoia() const { return m_paranoia; } bool miningParanoia() const { return m_paranoia; }
/// Change whether we check block validity prior to mining. /// Change whether we check block validity prior to mining.
void setParanoia(bool _p) { m_paranoia = _p; } void setParanoia(bool _p) { m_paranoia = _p; }
/// Should we force mining to happen, even without transactions?
bool forceMining() const { return m_forceMining; }
/// Enable/disable forcing of mining to happen, even without transactions.
void setForceMining(bool _enable) { m_forceMining = _enable; }
/// Are we mining as fast as we can?
bool turboMining() const { return m_turboMining; }
/// Enable/disable fast mining.
void setTurboMining(bool _enable = true) { m_turboMining = _enable; }
/// Set the coinbase address. /// Set the coinbase address.
void setAddress(Address _us) { m_preMine.setAddress(_us); } void setAddress(Address _us) { m_preMine.setAddress(_us); }
/// Get the coinbase address. /// Get the coinbase address.
Address address() const { return m_preMine.address(); } Address address() const { return m_preMine.address(); }
/// Stops mining and sets the number of mining threads (0 for automatic).
void setMiningThreads(unsigned _threads = 0);
/// Get the effective number of mining threads.
unsigned miningThreads() const { ReadGuard l(x_miners); return m_miners.size(); }
/// Start mining. /// Start mining.
/// NOT thread-safe /// NOT thread-safe - call it & stopMining only from a single thread
void startMining() { m_miner.start(); ensureWorking(); } void startMining() { ensureWorking(); ReadGuard l(x_miners); for (auto& m: m_miners) m.start(); }
/// Stop mining. /// Stop mining.
/// NOT thread-safe /// NOT thread-safe
void stopMining() { m_miner.stop(); } void stopMining() { ReadGuard l(x_miners); for (auto& m: m_miners) m.stop(); }
/// Are we mining now? /// Are we mining now?
bool isMining() { return m_miner.isRunning(); } bool isMining() { ReadGuard l(x_miners); return m_miners.size() && m_miners[0].isRunning(); }
/// Check the progress of the mining. /// Check the progress of the mining.
MineProgress miningProgress() const { return m_miner.miningProgress(); } MineProgress miningProgress() const;
/// Get and clear the mining history. /// Get and clear the mining history.
std::list<MineInfo> miningHistory() { return m_miner.miningHistory(); } std::list<MineInfo> miningHistory();
bool forceMining() const { return m_forceMining; }
void setForceMining(bool _enable) { m_forceMining = _enable; }
/// Clears pending transactions. Just for debug use. /// Clears pending transactions. Just for debug use.
void clearPending(); void clearPending();
void setTurboMining(bool _enable = true) { m_turboMining = _enable; }
bool turboMining() const { return m_turboMining; }
private: private:
/// Ensure the worker thread is running. Needed for blockchain maintenance & mining. /// Ensure the worker thread is running. Needed for blockchain maintenance & mining.
void ensureWorking(); void ensureWorking();
@ -296,7 +303,8 @@ private:
std::unique_ptr<std::thread> m_work; ///< The work thread. std::unique_ptr<std::thread> m_work; ///< The work thread.
std::atomic<ClientWorkState> m_workState; std::atomic<ClientWorkState> m_workState;
Miner m_miner; std::vector<Miner> m_miners;
mutable boost::shared_mutex x_miners;
bool m_paranoia = false; ///< Should we be paranoid about our state? bool m_paranoia = false; ///< Should we be paranoid about our state?
bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping. bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping.
bool m_forceMining = false; ///< Mine even when there are no transactions pending? bool m_forceMining = false; ///< Mine even when there are no transactions pending?

3
libethereum/Miner.cpp

@ -33,6 +33,9 @@ Miner::Miner(MinerHost* _host, unsigned _id):
void Miner::start() void Miner::start()
{ {
if (!m_host)
return;
Guard l(x_work); Guard l(x_work);
if (!m_work) if (!m_work)
{ {

29
libethereum/Miner.h

@ -37,11 +37,12 @@ namespace eth
*/ */
struct MineProgress struct MineProgress
{ {
double requirement; ///< The PoW requirement - as the second logarithm of the minimum acceptable hash. void combine(MineProgress const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); current = std::max(current, _m.current); hashes += _m.hashes; ms = std::max(ms, _m.ms); }
double best; ///< The PoW achievement - as the second logarithm of the minimum found hash. double requirement = 0; ///< The PoW requirement - as the second logarithm of the minimum acceptable hash.
double current; ///< The most recent PoW achievement - as the second logarithm of the presently found hash. double best = 1e99; ///< The PoW achievement - as the second logarithm of the minimum found hash.
uint hashes; ///< Total number of hashes computed. double current = 0; ///< The most recent PoW achievement - as the second logarithm of the presently found hash.
uint ms; ///< Total number of milliseconds of mining thus far. uint hashes = 0; ///< Total number of hashes computed.
uint ms = 0; ///< Total number of milliseconds of mining thus far.
}; };
/** /**
@ -74,12 +75,24 @@ public:
class Miner class Miner
{ {
public: public:
/// Constructor. Starts miner. /// Null constructor.
Miner(): m_host(nullptr), m_id(0) {}
/// Constructor.
Miner(MinerHost* _host, unsigned _id = 0); Miner(MinerHost* _host, unsigned _id = 0);
/// Move-constructor.
Miner(Miner&& _m) { std::swap(m_host, _m.m_host); std::swap(m_id, _m.m_id); }
/// Move-assignment.
Miner& operator=(Miner&& _m) { std::swap(m_host, _m.m_host); std::swap(m_id, _m.m_id); return *this; }
/// Destructor. Stops miner. /// Destructor. Stops miner.
~Miner() { stop(); } ~Miner() { stop(); }
/// Setup its basics.
void setup(MinerHost* _host, unsigned _id = 0) { m_host = _host; m_id = _id; }
/// Start mining. /// Start mining.
void start(); void start();
@ -108,8 +121,8 @@ private:
/// Do some work on the mining. /// Do some work on the mining.
void work(); void work();
MinerHost* m_host; ///< Our host. MinerHost* m_host = nullptr; ///< Our host.
unsigned m_id; ///< Our identity. unsigned m_id = 0; ///< Our identity.
std::mutex x_work; ///< Mutex protecting the creation of the work thread. std::mutex x_work; ///< Mutex protecting the creation of the work thread.
std::unique_ptr<std::thread> m_work; ///< The work thread. std::unique_ptr<std::thread> m_work; ///< The work thread.

Loading…
Cancel
Save