From e2c147f6887a3db0d6333a9507962dc55dc91ee0 Mon Sep 17 00:00:00 2001 From: Jan Willem Penterman Date: Tue, 21 Apr 2015 17:00:02 +0200 Subject: [PATCH] multiple gpu support (and option to use less than maximum cpu threads) --- eth/main.cpp | 38 ++++++++++++++++++++++++-------- libethash-cl/ethash_cl_miner.cpp | 21 ++++++++++++++++++ libethash-cl/ethash_cl_miner.h | 2 ++ libethcore/Ethash.cpp | 10 ++++++++- libethcore/Ethash.h | 14 +++++++----- 5 files changed, 70 insertions(+), 15 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index da8943e46..eabcc2a4d 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -136,6 +136,7 @@ void help() << " -G,--opencl When mining use the GPU via OpenCL." << endl << " --opencl-platform When mining using -G/--opencl use OpenCL platform n (default: 0)." << endl << " --opencl-device When mining using -G/--opencl use OpenCL device n (default: 0)." << endl + << " -t, --mining-threads Limit number of CPU/GPU miners to n (default: use everything available on selected platform)" << endl << "Client networking:" << endl << " --client-name Add a name to your client's version string (default: blank)." << endl << " -b,--bootstrap Connect to the default Ethereum peerserver." << endl @@ -481,7 +482,8 @@ int main(int argc, char** argv) /// Mining options MinerType minerType = MinerType::CPU; unsigned openclPlatform = 0; - unsigned openclDevice = 0; + unsigned openclDevice = 0; + unsigned miningThreads = UINT_MAX; /// File name for import/export. string filename; @@ -601,12 +603,12 @@ int main(int argc, char** argv) else if (arg == "--opencl-platform" && i + 1 < argc) try { openclPlatform= stol(argv[++i]); - } - catch (...) - { - cerr << "Bad " << arg << " option: " << argv[i] << endl; - return -1; - } + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } else if (arg == "--opencl-device" && i + 1 < argc) try { openclDevice = stol(argv[++i]); @@ -850,6 +852,17 @@ int main(int argc, char** argv) return -1; } } + else if ((arg == "-t" || arg == "--mining-threads") && i + 1 < argc) + { + try { + miningThreads = stol(argv[++i]); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } + } else if (arg == "-b" || arg == "--bootstrap") bootstrap = true; else if (arg == "-f" || arg == "--force-mining") @@ -905,9 +918,16 @@ int main(int argc, char** argv) if (sessionSecret) sigKey = KeyPair(sessionSecret); - ProofOfWork::GPUMiner::setDefaultPlatform(openclPlatform); - ProofOfWork::GPUMiner::setDefaultDevice(openclDevice); + + if (minerType == MinerType::CPU) { + ProofOfWork::CPUMiner::setNumInstances(miningThreads); + } + else if (minerType == MinerType::GPU) { + ProofOfWork::GPUMiner::setDefaultPlatform(openclPlatform); + ProofOfWork::GPUMiner::setDefaultDevice(openclDevice); + ProofOfWork::GPUMiner::setNumInstances(miningThreads); + } // Two codepaths is necessary since named block require database, but numbered // blocks are superuseful to have when database is already open in another process. if (mode == OperationMode::DAGInit && !(initDAG == LatestBlock || initDAG == PendingBlock)) diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 53eabe349..891d3f97d 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -85,6 +85,27 @@ std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _devic return "{ \"platform\": \"" + platforms[platform_num].getInfo() + "\", \"device\": \"" + device.getInfo() + "\", \"version\": \"" + device_version + "\" }"; } +unsigned ethash_cl_miner::get_num_devices(unsigned _platformId) +{ + std::vector platforms; + cl::Platform::get(&platforms); + if (platforms.empty()) + { + debugf("No OpenCL platforms found.\n"); + return 0; + } + + std::vector devices; + unsigned platform_num = std::min(_platformId, platforms.size() - 1); + platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); + if (devices.empty()) + { + debugf("No OpenCL devices found.\n"); + return 0; + } + return devices.size(); +} + void ethash_cl_miner::finish() { if (m_queue()) diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index 3046f037b..21635df91 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -33,6 +33,8 @@ public: bool init(ethash_params const& params, std::function _fillDAG, unsigned workgroup_size = 64, unsigned _platformId = 0, unsigned _deviceId = 0); static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0); + static unsigned get_num_devices(unsigned _platformId = 0); + void finish(); void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count); diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 7ff35fd2b..91ba00710 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -264,10 +264,12 @@ private: unsigned Ethash::GPUMiner::s_platformId = 0; unsigned Ethash::GPUMiner::s_deviceId = 0; +unsigned Ethash::GPUMiner::s_numInstances = 1; +unsigned Ethash::CPUMiner::s_numInstances = 1; Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): Miner(_ci), - Worker("gpuminer"), + Worker("gpuminer" + toString(index())), m_hook(new EthashCLHook(this)) { } @@ -308,6 +310,7 @@ void Ethash::GPUMiner::workLoop() auto p = EthashAux::params(m_minerSeed); auto cb = [&](void* d) { EthashAux::full(m_minerSeed, bytesRef((byte*)d, p.full_size)); }; + unsigned device = instances() > 0 ? index() : s_deviceId; m_miner->init(p, cb, 32, s_platformId, s_deviceId); } @@ -331,6 +334,11 @@ std::string Ethash::GPUMiner::platformInfo() return ethash_cl_miner::platform_info(s_platformId, s_deviceId); } +unsigned Ethash::GPUMiner::getNumDevices() +{ + return ethash_cl_miner::get_num_devices(s_platformId); +} + #endif } diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 2bbe7d649..9a66e9865 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -78,17 +78,18 @@ public: static bool preVerify(BlockInfo const& _header); static WorkPackage package(BlockInfo const& _header); static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } + class CPUMiner: public Miner, Worker { public: CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} - static unsigned instances() { return std::thread::hardware_concurrency(); } + static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); static void setDefaultPlatform(unsigned) {} static void setDefaultDevice(unsigned) {} - + static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } protected: void kickOff() override { @@ -100,7 +101,7 @@ public: private: void workLoop() override; - static unsigned s_deviceId; + static unsigned s_numInstances; }; #if ETH_ETHASHCL || !ETH_TRUE @@ -112,11 +113,13 @@ public: GPUMiner(ConstructionInfo const& _ci); ~GPUMiner(); - static unsigned instances() { return 1; } + static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } static std::string platformInfo(); + static unsigned getNumDevices(); static void setDefaultPlatform(unsigned _id) { s_platformId = _id; } static void setDefaultDevice(unsigned _id) { s_deviceId = _id; } - + static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + protected: void kickOff() override; void pause() override; @@ -133,6 +136,7 @@ public: h256 m_minerSeed; ///< Last seed in m_miner static unsigned s_platformId; static unsigned s_deviceId; + static unsigned s_numInstances; }; #else using GPUMiner = CPUMiner;