CPUMiner.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /* Copyright (C) 1883 Thomas Edison - All Rights Reserved
  2. * You may use, distribute and modify this code under the
  3. * terms of the GPLv3 license, which unfortunately won't be
  4. * written for another century.
  5. *
  6. * You should have received a copy of the LICENSE file with
  7. * this file.
  8. */
  9. #if defined(__linux__)
  10. #if !defined(_GNU_SOURCE)
  11. #define _GNU_SOURCE /* we need sched_setaffinity() */
  12. #endif
  13. #include <error.h>
  14. #include <sched.h>
  15. #include <unistd.h>
  16. #endif
  17. #include <ethash/ethash.hpp>
  18. #include <libeth/Farm.h>
  19. #include <boost/version.hpp>
  20. #if 0
  21. #include <boost/fiber/numa/pin_thread.hpp>
  22. #include <boost/fiber/numa/topology.hpp>
  23. #endif
  24. #include "CPUMiner.h"
  25. /* Sanity check for defined OS */
  26. #if defined(__linux__)
  27. /* linux */
  28. #elif defined(_WIN32)
  29. /* windows */
  30. #else
  31. #error "Invalid OS configuration"
  32. #endif
  33. using namespace std;
  34. using namespace dev;
  35. using namespace eth;
  36. /* ################## OS-specific functions ################## */
  37. /*
  38. * returns physically available memory (no swap)
  39. */
  40. static size_t getTotalPhysAvailableMemory() {
  41. #if defined(__linux__)
  42. long pages = sysconf(_SC_AVPHYS_PAGES);
  43. if (pages == -1L) {
  44. cwarn << "Error in func " << __FUNCTION__ << " at sysconf(_SC_AVPHYS_PAGES) \"" << strerror(errno) << "\"\n";
  45. return 0;
  46. }
  47. long page_size = sysconf(_SC_PAGESIZE);
  48. if (page_size == -1L) {
  49. cwarn << "Error in func " << __FUNCTION__ << " at sysconf(_SC_PAGESIZE) \"" << strerror(errno) << "\"\n";
  50. return 0;
  51. }
  52. return (size_t)pages * (size_t)page_size;
  53. #else
  54. MEMORYSTATUSEX memInfo;
  55. memInfo.dwLength = sizeof(MEMORYSTATUSEX);
  56. if (GlobalMemoryStatusEx(&memInfo) == 0) {
  57. // Handle Errorcode (GetLastError) ??
  58. return 0;
  59. }
  60. return memInfo.ullAvailPhys;
  61. #endif
  62. }
  63. /*
  64. * return numbers of available CPUs
  65. */
  66. unsigned CPUMiner::getNumDevices() {
  67. #if defined(__linux__)
  68. long cpus_available;
  69. cpus_available = sysconf(_SC_NPROCESSORS_ONLN);
  70. if (cpus_available == -1L) {
  71. cwarn << "Error in func " << __FUNCTION__ << " at sysconf(_SC_NPROCESSORS_ONLN) \"" << strerror(errno)
  72. << "\"\n";
  73. return 0;
  74. }
  75. return cpus_available;
  76. #else
  77. SYSTEM_INFO sysinfo;
  78. GetSystemInfo(&sysinfo);
  79. return sysinfo.dwNumberOfProcessors;
  80. #endif
  81. }
  82. /* ######################## CPU Miner ######################## */
  83. CPUMiner::CPUMiner(unsigned _index, DeviceDescriptor& _device) : Miner("cpu-", _index) { m_deviceDescriptor = _device; }
  84. CPUMiner::~CPUMiner() {
  85. stopWorking();
  86. kick_miner();
  87. }
  88. /*
  89. * Bind the current thread to a spcific CPU
  90. */
  91. bool CPUMiner::initDevice() {
  92. cnote << "Using CPU: " << m_deviceDescriptor.cpCpuNumer << " " << m_deviceDescriptor.boardName
  93. << " Memory : " << dev::getFormattedMemory((double)m_deviceDescriptor.totalMemory);
  94. #if defined(__linux__)
  95. cpu_set_t cpuset;
  96. int err;
  97. CPU_ZERO(&cpuset);
  98. CPU_SET(m_deviceDescriptor.cpCpuNumer, &cpuset);
  99. err = sched_setaffinity(0, sizeof(cpuset), &cpuset);
  100. if (err != 0) {
  101. cwarn << "Error in func " << __FUNCTION__ << " at sched_setaffinity() \"" << strerror(errno) << "\"\n";
  102. cwarn << "cp-" << m_index << "could not bind thread to cpu" << m_deviceDescriptor.cpCpuNumer << "\n";
  103. }
  104. #else
  105. DWORD_PTR dwThreadAffinityMask = 1i64 << m_deviceDescriptor.cpCpuNumer;
  106. DWORD_PTR previous_mask;
  107. previous_mask = SetThreadAffinityMask(GetCurrentThread(), dwThreadAffinityMask);
  108. if (previous_mask == NULL) {
  109. cwarn << "cp-" << m_index << "could not bind thread to cpu" << m_deviceDescriptor.cpCpuNumer << "\n";
  110. // Handle Errorcode (GetLastError) ??
  111. }
  112. #endif
  113. return true;
  114. }
  115. /*
  116. * A new epoch was receifed with last work package (called from Miner::initEpoch())
  117. *
  118. * If we get here it means epoch has changed so it's not necessary
  119. * to check again dag sizes. They're changed for sure
  120. * We've all related infos in m_epochContext (.dagSize, .dagNumItems, .lightSize, .lightNumItems)
  121. */
  122. bool CPUMiner::initEpoch() {
  123. m_initialized = true;
  124. return true;
  125. }
  126. /*
  127. Miner should stop working on the current block
  128. This happens if a
  129. * new work arrived or
  130. * miner should stop (eg exit ethminer) or
  131. * miner should pause
  132. */
  133. void CPUMiner::kick_miner() {
  134. m_new_work.store(true, memory_order_relaxed);
  135. m_new_work_signal.notify_one();
  136. }
  137. void CPUMiner::search(const dev::eth::WorkPackage& w) {
  138. constexpr size_t blocksize = 30;
  139. const auto& context = ethash::get_global_epoch_context_full(w.epoch);
  140. const auto header = ethash::hash256_from_bytes(w.header.data());
  141. const auto boundary = ethash::hash256_from_bytes(w.boundary.data());
  142. auto nonce = w.startNonce;
  143. while (true) {
  144. if (m_new_work.load(memory_order_relaxed)) // new work arrived ?
  145. {
  146. m_new_work.store(false, memory_order_relaxed);
  147. break;
  148. }
  149. if (shouldStop())
  150. break;
  151. auto r = ethash::search(context, header, boundary, nonce, blocksize);
  152. if (r.solution_found) {
  153. h256 mix{reinterpret_cast<byte*>(r.mix_hash.bytes), h256::ConstructFromPointer};
  154. auto sol = Solution{r.nonce, mix, w, chrono::steady_clock::now(), m_index};
  155. cnote << EthWhite << "Job: " << w.header.abridged() << " Solution: " << toHex(sol.nonce, HexPrefix::Add);
  156. Farm::f().submitProof(sol);
  157. }
  158. nonce += blocksize;
  159. // Update the hash rate
  160. updateHashRate(blocksize, 1);
  161. }
  162. }
  163. /*
  164. * The main work loop of a Worker thread
  165. */
  166. void CPUMiner::workLoop() {
  167. WorkPackage current;
  168. current.header = h256();
  169. if (!initDevice())
  170. return;
  171. while (!shouldStop()) {
  172. // Wait for work or 3 seconds (whichever the first)
  173. const WorkPackage w = work();
  174. if (!w) {
  175. unique_lock<mutex> l(miner_work_mutex);
  176. m_new_work_signal.wait_for(l, chrono::seconds(3));
  177. continue;
  178. }
  179. // Epoch change ?
  180. if (current.epoch != w.epoch) {
  181. setEpoch(w);
  182. initEpoch();
  183. // As DAG generation takes a while we need to
  184. // ensure we're on latest job, not on the one
  185. // which triggered the epoch change
  186. current = w;
  187. continue;
  188. }
  189. // Persist most recent job.
  190. // Job's differences should be handled at higher level
  191. current = w;
  192. // Start searching
  193. search(w);
  194. }
  195. }
  196. void CPUMiner::enumDevices(map<string, DeviceDescriptor>& _DevicesCollection) {
  197. unsigned numDevices = getNumDevices();
  198. for (unsigned i = 0; i < numDevices; i++) {
  199. string uniqueId;
  200. ostringstream s;
  201. DeviceDescriptor deviceDescriptor;
  202. s << "cpu-" << i;
  203. uniqueId = s.str();
  204. if (_DevicesCollection.find(uniqueId) != _DevicesCollection.end())
  205. deviceDescriptor = _DevicesCollection[uniqueId];
  206. else
  207. deviceDescriptor = DeviceDescriptor();
  208. s.str("");
  209. s.clear();
  210. s << "ethash::eval()/boost " << (BOOST_VERSION / 100000) << "." << (BOOST_VERSION / 100 % 1000) << "."
  211. << (BOOST_VERSION % 100);
  212. deviceDescriptor.boardName = s.str();
  213. deviceDescriptor.uniqueId = uniqueId;
  214. deviceDescriptor.type = DeviceTypeEnum::Cpu;
  215. deviceDescriptor.totalMemory = getTotalPhysAvailableMemory();
  216. deviceDescriptor.cpCpuNumer = i;
  217. _DevicesCollection[uniqueId] = deviceDescriptor;
  218. }
  219. }