Jan Willem Penterman
9 years ago
4 changed files with 322 additions and 2 deletions
@ -0,0 +1,238 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file EthashGPUMiner.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
* |
|||
* Determines the PoW algorithm. |
|||
*/ |
|||
|
|||
#if ETH_ETHASHCU || !ETH_TRUE |
|||
|
|||
#include "EthashCUDAMiner.h" |
|||
#include <thread> |
|||
#include <chrono> |
|||
#include <libethash-cu/ethash_cu_miner.h> |
|||
using namespace std; |
|||
using namespace dev; |
|||
using namespace eth; |
|||
|
|||
namespace dev |
|||
{ |
|||
namespace eth |
|||
{ |
|||
|
|||
class EthashCUHook: public ethash_cu_miner::search_hook |
|||
{ |
|||
public: |
|||
EthashCUHook(EthashCUDAMiner* _owner): m_owner(_owner) {} |
|||
EthashCUHook(EthashCUHook const&) = delete; |
|||
|
|||
void abort() |
|||
{ |
|||
{ |
|||
UniqueGuard l(x_all); |
|||
if (m_aborted) |
|||
return; |
|||
// cdebug << "Attempting to abort";
|
|||
|
|||
m_abort = true; |
|||
} |
|||
// m_abort is true so now searched()/found() will return true to abort the search.
|
|||
// we hang around on this thread waiting for them to point out that they have aborted since
|
|||
// otherwise we may end up deleting this object prior to searched()/found() being called.
|
|||
m_aborted.wait(true); |
|||
// for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout)
|
|||
// std::this_thread::sleep_for(chrono::milliseconds(30));
|
|||
// if (!m_aborted)
|
|||
// cwarn << "Couldn't abort. Abandoning OpenCL process.";
|
|||
} |
|||
|
|||
void reset() |
|||
{ |
|||
UniqueGuard l(x_all); |
|||
m_aborted = m_abort = false; |
|||
} |
|||
|
|||
protected: |
|||
virtual bool found(uint64_t const* _nonces, uint32_t _count) override |
|||
{ |
|||
// dev::operator <<(std::cerr << "Found nonces: ", vector<uint64_t>(_nonces, _nonces + _count)) << std::endl;
|
|||
for (uint32_t i = 0; i < _count; ++i) |
|||
if (m_owner->report(_nonces[i])) |
|||
return (m_aborted = true); |
|||
return m_owner->shouldStop(); |
|||
} |
|||
|
|||
virtual bool searched(uint64_t _startNonce, uint32_t _count) override |
|||
{ |
|||
UniqueGuard l(x_all); |
|||
// std::cerr << "Searched " << _count << " from " << _startNonce << std::endl;
|
|||
m_owner->accumulateHashes(_count); |
|||
m_last = _startNonce + _count; |
|||
if (m_abort || m_owner->shouldStop()) |
|||
return (m_aborted = true); |
|||
return false; |
|||
} |
|||
|
|||
private: |
|||
Mutex x_all; |
|||
uint64_t m_last; |
|||
bool m_abort = false; |
|||
Notified<bool> m_aborted = {true}; |
|||
EthashCUDAMiner* m_owner = nullptr; |
|||
}; |
|||
|
|||
} |
|||
} |
|||
|
|||
unsigned EthashCUDAMiner::s_platformId = 0; |
|||
unsigned EthashCUDAMiner::s_deviceId = 0; |
|||
unsigned EthashCUDAMiner::s_numInstances = 0; |
|||
|
|||
EthashCUDAMiner::EthashCUDAMiner(ConstructionInfo const& _ci) : |
|||
GenericMiner<EthashProofOfWork>(_ci), |
|||
Worker("cudaminer" + toString(index())), |
|||
m_hook(new EthashCUDAMiner(this)) |
|||
{ |
|||
} |
|||
|
|||
EthashCUDAMiner::~EthashCUDAMiner() |
|||
{ |
|||
pause(); |
|||
delete m_miner; |
|||
delete m_hook; |
|||
} |
|||
|
|||
bool EthashCUDAMiner::report(uint64_t _nonce) |
|||
{ |
|||
Nonce n = (Nonce)(u64)_nonce; |
|||
EthashProofOfWork::Result r = EthashAux::eval(work().seedHash, work().headerHash, n); |
|||
if (r.value < work().boundary) |
|||
return submitProof(Solution{n, r.mixHash}); |
|||
return false; |
|||
} |
|||
|
|||
void EthashCUDAMiner::kickOff() |
|||
{ |
|||
m_hook->reset(); |
|||
startWorking(); |
|||
} |
|||
|
|||
void EthashCUDAMiner::workLoop() |
|||
{ |
|||
// take local copy of work since it may end up being overwritten by kickOff/pause.
|
|||
try { |
|||
WorkPackage w = work(); |
|||
cnote << "workLoop" << !!m_miner << m_minerSeed << w.seedHash; |
|||
if (!m_miner || m_minerSeed != w.seedHash) |
|||
{ |
|||
cnote << "Initialising miner..."; |
|||
m_minerSeed = w.seedHash; |
|||
|
|||
delete m_miner; |
|||
m_miner = new ethash_cu_miner; |
|||
|
|||
unsigned device = instances() > 1 ? index() : s_deviceId; |
|||
|
|||
EthashAux::FullType dag; |
|||
while (true) |
|||
{ |
|||
if ((dag = EthashAux::full(w.seedHash, true))) |
|||
break; |
|||
if (shouldStop()) |
|||
{ |
|||
delete m_miner; |
|||
m_miner = nullptr; |
|||
return; |
|||
} |
|||
cnote << "Awaiting DAG"; |
|||
this_thread::sleep_for(chrono::milliseconds(500)); |
|||
} |
|||
bytesConstRef dagData = dag->data(); |
|||
m_miner->init(dagData.data(), dagData.size(), s_platformId, device); |
|||
} |
|||
|
|||
uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); |
|||
m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook); |
|||
} |
|||
catch (cl::Error const& _e) |
|||
{ |
|||
delete m_miner; |
|||
m_miner = nullptr; |
|||
cwarn << "Error GPU mining: " << _e.what() << "(" << _e.err() << ")"; |
|||
} |
|||
} |
|||
|
|||
void EthashCUDAMiner::pause() |
|||
{ |
|||
m_hook->abort(); |
|||
stopWorking(); |
|||
} |
|||
|
|||
std::string EthashCUDAMiner::platformInfo() |
|||
{ |
|||
return ethash_cl_miner::platform_info(s_platformId, s_deviceId); |
|||
} |
|||
|
|||
unsigned EthashCUDAMiner::getNumDevices() |
|||
{ |
|||
return ethash_cl_miner::getNumDevices(s_platformId); |
|||
} |
|||
|
|||
void EthashCUDAMiner::listDevices() |
|||
{ |
|||
return ethash_cl_miner::listDevices(); |
|||
} |
|||
|
|||
bool EthashCUDAMiner::configureGPU( |
|||
unsigned _localWorkSize, |
|||
unsigned _globalWorkSizeMultiplier, |
|||
unsigned _msPerBatch, |
|||
unsigned _platformId, |
|||
unsigned _deviceId, |
|||
bool _allowCPU, |
|||
unsigned _extraGPUMemory, |
|||
uint64_t _currentBlock |
|||
) |
|||
{ |
|||
s_platformId = _platformId; |
|||
s_deviceId = _deviceId; |
|||
|
|||
if (_localWorkSize != 32 && _localWorkSize != 64 && _localWorkSize != 128 && _localWorkSize != 256) |
|||
{ |
|||
cout << "Given localWorkSize of " << toString(_localWorkSize) << "is invalid. Must be either 32,64,128 or 256" << endl; |
|||
return false; |
|||
} |
|||
|
|||
if (!ethash_cu_miner::configureGPU( |
|||
_platformId, |
|||
_localWorkSize, |
|||
_globalWorkSizeMultiplier * _localWorkSize, |
|||
_msPerBatch, |
|||
_allowCPU, |
|||
_extraGPUMemory, |
|||
_currentBlock) |
|||
) |
|||
{ |
|||
cout << "No GPU device with sufficient memory was found. Can't GPU mine. Remove the -G argument" << endl; |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,82 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file EthashGPUMiner.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
* |
|||
* Determines the PoW algorithm. |
|||
*/ |
|||
|
|||
#pragma once |
|||
#if ETH_ETHASHCU || !ETH_TRUE |
|||
|
|||
#include "libdevcore/Worker.h" |
|||
#include "EthashAux.h" |
|||
#include "Miner.h" |
|||
|
|||
namespace dev |
|||
{ |
|||
namespace eth |
|||
{ |
|||
|
|||
class EthashCUDAMiner: public GenericMiner<EthashProofOfWork>, Worker |
|||
{ |
|||
friend class dev::eth::EthashCLHook; |
|||
|
|||
public: |
|||
EthashCUDAMiner(ConstructionInfo const& _ci); |
|||
~EthashCUDAMiner(); |
|||
|
|||
static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } |
|||
static std::string platformInfo(); |
|||
static unsigned getNumDevices(); |
|||
static void listDevices(); |
|||
static bool configureGPU( |
|||
unsigned _localWorkSize, |
|||
unsigned _globalWorkSizeMultiplier, |
|||
unsigned _msPerBatch, |
|||
unsigned _platformId, |
|||
unsigned _deviceId, |
|||
bool _allowCPU, |
|||
unsigned _extraGPUMemory, |
|||
uint64_t _currentBlock |
|||
); |
|||
static void setNumInstances(unsigned _instances) { s_numInstances = std::min<unsigned>(_instances, getNumDevices()); } |
|||
|
|||
protected: |
|||
void kickOff() override; |
|||
void pause() override; |
|||
|
|||
private: |
|||
void workLoop() override; |
|||
bool report(uint64_t _nonce); |
|||
|
|||
using GenericMiner<EthashProofOfWork>::accumulateHashes; |
|||
|
|||
EthashCLHook* m_hook = nullptr; |
|||
ethash_cl_miner* m_miner = nullptr; |
|||
|
|||
h256 m_minerSeed; ///< Last seed in m_miner
|
|||
static unsigned s_platformId; |
|||
static unsigned s_deviceId; |
|||
static unsigned s_numInstances; |
|||
}; |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
Loading…
Reference in new issue