EthashGPUMiner.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. This file is part of cpp-ethereum.
  3. cpp-ethereum is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. cpp-ethereum is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. /** @file EthashGPUMiner.cpp
  15. * @author Gav Wood <i@gavwood.com>
  16. * @date 2014
  17. *
  18. * Determines the PoW algorithm.
  19. */
  20. #if ETH_ETHASHCL
  21. #include "EthashGPUMiner.h"
  22. #include <thread>
  23. #include <chrono>
  24. #include <libethash-cl/ethash_cl_miner.h>
  25. using namespace std;
  26. using namespace dev;
  27. using namespace eth;
  28. namespace dev
  29. {
  30. namespace eth
  31. {
  32. class EthashCLHook: public ethash_cl_miner::search_hook
  33. {
  34. public:
  35. EthashCLHook(EthashGPUMiner* _owner): m_owner(_owner) {}
  36. EthashCLHook(EthashCLHook const&) = delete;
  37. void abort()
  38. {
  39. {
  40. UniqueGuard l(x_all);
  41. if (m_aborted)
  42. return;
  43. // cdebug << "Attempting to abort";
  44. m_abort = true;
  45. }
  46. // m_abort is true so now searched()/found() will return true to abort the search.
  47. // we hang around on this thread waiting for them to point out that they have aborted since
  48. // otherwise we may end up deleting this object prior to searched()/found() being called.
  49. m_aborted.wait(true);
  50. // for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout)
  51. // std::this_thread::sleep_for(chrono::milliseconds(30));
  52. // if (!m_aborted)
  53. // cwarn << "Couldn't abort. Abandoning OpenCL process.";
  54. }
  55. void reset()
  56. {
  57. UniqueGuard l(x_all);
  58. m_aborted = m_abort = false;
  59. }
  60. protected:
  61. virtual bool found(uint64_t const* _nonces, uint32_t _count) override
  62. {
  63. // dev::operator <<(std::cerr << "Found nonces: ", vector<uint64_t>(_nonces, _nonces + _count)) << std::endl;
  64. for (uint32_t i = 0; i < _count; ++i)
  65. if (m_owner->report(_nonces[i]))
  66. return (m_aborted = true);
  67. return m_owner->shouldStop();
  68. }
  69. virtual bool searched(uint64_t _startNonce, uint32_t _count) override
  70. {
  71. UniqueGuard l(x_all);
  72. // std::cerr << "Searched " << _count << " from " << _startNonce << std::endl;
  73. m_owner->accumulateHashes(_count);
  74. m_last = _startNonce + _count;
  75. if (m_abort || m_owner->shouldStop())
  76. return (m_aborted = true);
  77. return false;
  78. }
  79. private:
  80. Mutex x_all;
  81. uint64_t m_last;
  82. bool m_abort = false;
  83. Notified<bool> m_aborted = {true};
  84. EthashGPUMiner* m_owner = nullptr;
  85. };
  86. }
  87. }
  88. unsigned EthashGPUMiner::s_platformId = 0;
  89. unsigned EthashGPUMiner::s_deviceId = 0;
  90. unsigned EthashGPUMiner::s_numInstances = 0;
  91. EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci):
  92. GenericMiner<EthashProofOfWork>(_ci),
  93. Worker("gpuminer" + toString(index())),
  94. m_hook(new EthashCLHook(this))
  95. {
  96. }
  97. EthashGPUMiner::~EthashGPUMiner()
  98. {
  99. pause();
  100. delete m_miner;
  101. delete m_hook;
  102. }
  103. bool EthashGPUMiner::report(uint64_t _nonce)
  104. {
  105. Nonce n = (Nonce)(u64)_nonce;
  106. EthashProofOfWork::Result r = EthashAux::eval(work().seedHash, work().headerHash, n);
  107. if (r.value < work().boundary)
  108. return submitProof(Solution{n, r.mixHash});
  109. return false;
  110. }
  111. void EthashGPUMiner::kickOff()
  112. {
  113. m_hook->reset();
  114. startWorking();
  115. }
  116. void EthashGPUMiner::workLoop()
  117. {
  118. // take local copy of work since it may end up being overwritten by kickOff/pause.
  119. try {
  120. WorkPackage w = work();
  121. cnote << "workLoop" << !!m_miner << m_minerSeed << w.seedHash;
  122. if (!m_miner || m_minerSeed != w.seedHash)
  123. {
  124. cnote << "Initialising miner...";
  125. m_minerSeed = w.seedHash;
  126. delete m_miner;
  127. m_miner = new ethash_cl_miner;
  128. unsigned device = instances() > 1 ? index() : s_deviceId;
  129. EthashAux::FullType dag;
  130. while (true)
  131. {
  132. if ((dag = EthashAux::full(w.seedHash, true)))
  133. break;
  134. if (shouldStop())
  135. {
  136. delete m_miner;
  137. m_miner = nullptr;
  138. return;
  139. }
  140. cnote << "Awaiting DAG";
  141. this_thread::sleep_for(chrono::milliseconds(500));
  142. }
  143. bytesConstRef dagData = dag->data();
  144. m_miner->init(dagData.data(), dagData.size(), s_platformId, device);
  145. }
  146. uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192);
  147. m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook);
  148. }
  149. catch (cl::Error const& _e)
  150. {
  151. delete m_miner;
  152. m_miner = nullptr;
  153. cwarn << "Error GPU mining: " << _e.what() << "(" << _e.err() << ")";
  154. }
  155. }
  156. void EthashGPUMiner::pause()
  157. {
  158. m_hook->abort();
  159. stopWorking();
  160. }
  161. std::string EthashGPUMiner::platformInfo()
  162. {
  163. return ethash_cl_miner::platform_info(s_platformId, s_deviceId);
  164. }
  165. unsigned EthashGPUMiner::getNumDevices()
  166. {
  167. return ethash_cl_miner::getNumDevices(s_platformId);
  168. }
  169. void EthashGPUMiner::listDevices()
  170. {
  171. return ethash_cl_miner::listDevices();
  172. }
  173. bool EthashGPUMiner::configureGPU(
  174. unsigned _localWorkSize,
  175. unsigned _globalWorkSizeMultiplier,
  176. unsigned _msPerBatch,
  177. unsigned _platformId,
  178. unsigned _deviceId,
  179. bool _allowCPU,
  180. unsigned _extraGPUMemory,
  181. uint64_t _currentBlock
  182. )
  183. {
  184. s_platformId = _platformId;
  185. s_deviceId = _deviceId;
  186. if (_localWorkSize != 32 && _localWorkSize != 64 && _localWorkSize != 128 && _localWorkSize != 256)
  187. {
  188. cout << "Given localWorkSize of " << toString(_localWorkSize) << " is invalid. Must be either 32, 64, 128 or 256" << endl;
  189. return false;
  190. }
  191. if (!ethash_cl_miner::configureGPU(
  192. _platformId,
  193. _localWorkSize,
  194. _globalWorkSizeMultiplier * _localWorkSize,
  195. _msPerBatch,
  196. _allowCPU,
  197. _extraGPUMemory,
  198. _currentBlock)
  199. )
  200. {
  201. cout << "No GPU device with sufficient memory was found. Can't GPU mine. Remove the -G argument" << endl;
  202. return false;
  203. }
  204. return true;
  205. }
  206. #endif // ETH_ETHASHCL