Browse Source

Multi-threaded mining.

cl-refactor
Gav Wood 10 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 ret{0.f, 1e99, 0, false};
MineInfo ret;
static std::mt19937_64 s_eng((time(0) + (unsigned)m_last));
u256 s = (m_last = h256::random(s_eng));

9
libethcore/Dagger.h

@ -38,10 +38,11 @@ inline uint toLog2(u256 _d)
struct MineInfo
{
double requirement;
double best;
uint hashes;
bool completed;
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 requirement = 0;
double best = 1e99;
uint hashes = 0;
bool completed = false;
};
#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_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)),
m_preMine(_us, m_stateDB),
m_postMine(_us, m_stateDB),
m_miner(this)
m_postMine(_us, m_stateDB)
{
setMiningThreads();
if (_dbPath.size())
Defaults::setDBPath(_dbPath);
m_vc.setOk();
@ -115,7 +115,11 @@ void Client::clearPending()
appendFromNewPending(m_postMine.bloom(i), changeds);
changeds.insert(PendingChangedFilter);
m_postMine = m_preMine;
m_miner.noteStateChange();
{
ReadGuard l(x_miners);
for (auto& m: m_miners)
m.noteStateChange();
}
noteChanged(changeds);
}
@ -289,6 +293,46 @@ void Client::connect(std::string const& _seedHost, unsigned short _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)
{
{
@ -410,23 +454,26 @@ void Client::work()
cworkin << "WORK";
h256Set changeds;
if (m_miner.isComplete())
{
cwork << "CHAIN <== postSTATE";
h256s hs;
{
WriteGuard l(x_stateDB);
hs = m_bc.attemptImport(m_miner.blockData(), m_stateDB);
}
if (hs.size())
ReadGuard l(x_miners);
for (auto& m: m_miners)
if (m.isComplete())
{
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.
cwork << "CHAIN <== postSTATE";
h256s hs;
{
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.
// 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
// all blocks.
// Resynchronise state with block chain & trans
bool rsm = false;
{
WriteGuard l(x_stateDB);
cwork << "BQ ==> CHAIN ==> STATE";
@ -451,8 +499,6 @@ void Client::work()
if (newBlocks.size())
m_stateDB = db;
bool rsm = false;
cwork << "preSTATE <== CHAIN";
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.";
rsm = true;
}
if (rsm)
m_miner.noteStateChange();
}
if (rsm)
{
ReadGuard l(x_miners);
for (auto& m: m_miners)
m.noteStateChange();
}
cwork << "noteChanged" << changeds.size() << "items";

34
libethereum/Client.h

@ -217,32 +217,39 @@ public:
bool miningParanoia() const { return m_paranoia; }
/// Change whether we check block validity prior to mining.
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.
void setAddress(Address _us) { m_preMine.setAddress(_us); }
/// Get the coinbase 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.
/// NOT thread-safe
void startMining() { m_miner.start(); ensureWorking(); }
/// NOT thread-safe - call it & stopMining only from a single thread
void startMining() { ensureWorking(); ReadGuard l(x_miners); for (auto& m: m_miners) m.start(); }
/// Stop mining.
/// 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?
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.
MineProgress miningProgress() const { return m_miner.miningProgress(); }
MineProgress miningProgress() const;
/// Get and clear the mining history.
std::list<MineInfo> miningHistory() { return m_miner.miningHistory(); }
bool forceMining() const { return m_forceMining; }
void setForceMining(bool _enable) { m_forceMining = _enable; }
std::list<MineInfo> miningHistory();
/// Clears pending transactions. Just for debug use.
void clearPending();
void setTurboMining(bool _enable = true) { m_turboMining = _enable; }
bool turboMining() const { return m_turboMining; }
private:
/// Ensure the worker thread is running. Needed for blockchain maintenance & mining.
void ensureWorking();
@ -296,7 +303,8 @@ private:
std::unique_ptr<std::thread> m_work; ///< The work thread.
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_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?

3
libethereum/Miner.cpp

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

29
libethereum/Miner.h

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

Loading…
Cancel
Save