diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 47fd2e2ae..bae4b942c 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -171,8 +171,16 @@ public: m_minerType = MinerType::CPU; else if (arg == "-G" || arg == "--opencl") { - m_minerType = MinerType::GPU; - miningThreads = 1; + if (!ProofOfWork::GPUMiner::haveSufficientGPUMemory()) + { + cout << "No GPU device with sufficient memory was found. Defaulting to CPU" << endl; + m_minerType = MinerType::CPU; + } + else + { + m_minerType = MinerType::GPU; + miningThreads = 1; + } } else if (arg == "--no-precompute") { diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 93ce9ab22..7e2dfd46e 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -35,6 +35,7 @@ #include "ethash_cl_miner_kernel.h" #define ETHASH_BYTES 32 +#define ETHASH_CL_MINIMUM_MEMORY 2000000000 // workaround lame platforms #if !CL_VERSION_1_2 @@ -47,6 +48,9 @@ using namespace std; +// TODO: If at any point we can use libdevcore in here then we should switch to using a LogChannel +#define ETHCL_LOG(_contents) cout << "[OPENCL]:" << _contents << endl + static void add_definition(std::string& source, char const* id, unsigned value) { char buf[256]; @@ -72,7 +76,7 @@ std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _devic cl::Platform::get(&platforms); if (platforms.empty()) { - cout << "No OpenCL platforms found." << endl; + ETHCL_LOG("No OpenCL platforms found."); return std::string(); } @@ -82,7 +86,7 @@ std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _devic platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { - cout << "No OpenCL devices found." << endl; + ETHCL_LOG("No OpenCL devices found."); return std::string(); } @@ -107,7 +111,7 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId) cl::Platform::get(&platforms); if (platforms.empty()) { - cout << "No OpenCL platforms found." << endl; + ETHCL_LOG("No OpenCL platforms found."); return 0; } @@ -116,12 +120,53 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId) platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { - cout << "No OpenCL devices found." << endl; + ETHCL_LOG("No OpenCL devices found."); return 0; } return devices.size(); } +bool ethash_cl_miner::haveSufficientGPUMemory(unsigned _platformId) +{ + std::vector platforms; + cl::Platform::get(&platforms); + if (platforms.empty()) + { + ETHCL_LOG("No OpenCL platforms found."); + return false; + } + + std::vector devices; + unsigned platform_num = std::min(_platformId, platforms.size() - 1); + platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); + if (devices.empty()) + { + ETHCL_LOG("No OpenCL devices found."); + return false; + } + + for (cl::Device const& device: devices) + { + cl_ulong result; + device.getInfo(CL_DEVICE_GLOBAL_MEM_SIZE, &result); + if (result >= ETHASH_CL_MINIMUM_MEMORY) + { + ETHCL_LOG( + "Found suitable OpenCL device [" << device.getInfo() + << "] with " << result << " bytes of GPU memory" + ); + return true; + } + else + ETHCL_LOG( + "OpenCL device " << device.getInfo() + << " has insufficient GPU memory." << result << + " bytes of memory found < " << ETHASH_CL_MINIMUM_MEMORY << " bytes of memory required" + ); + } + return false; +} + void ethash_cl_miner::finish() { if (m_queue()) @@ -135,7 +180,7 @@ bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned work cl::Platform::get(&platforms); if (platforms.empty()) { - cout << "No OpenCL platforms found." << endl; + ETHCL_LOG("No OpenCL platforms found."); return false; } @@ -143,25 +188,25 @@ bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned work _platformId = std::min(_platformId, platforms.size() - 1); - cout << "Using platform: " << platforms[_platformId].getInfo().c_str() << endl; + ETHCL_LOG("Using platform: " << platforms[_platformId].getInfo().c_str()); // get GPU device of the default platform std::vector devices; platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { - cout << "No OpenCL devices found." << endl; + ETHCL_LOG("No OpenCL devices found."); return false; } // use selected device cl::Device& device = devices[std::min(_deviceId, devices.size() - 1)]; std::string device_version = device.getInfo(); - cout << "Using device: " << device.getInfo().c_str() << "(" << device_version.c_str() << ")" << endl; + ETHCL_LOG("Using device: " << device.getInfo().c_str() << "(" << device_version.c_str() << ")"); if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0) { - cout << "OpenCL 1.0 is not supported." << endl; + ETHCL_LOG("OpenCL 1.0 is not supported."); return false; } if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0) @@ -193,7 +238,7 @@ bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned work } catch (cl::Error err) { - cout << program.getBuildInfo(device).c_str(); + ETHCL_LOG(program.getBuildInfo(device).c_str()); return false; } m_hash_kernel = cl::Kernel(program, "ethash_hash"); diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index 43bfa2336..ef6745d76 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -35,6 +35,7 @@ public: static unsigned get_num_platforms(); static unsigned get_num_devices(unsigned _platformId = 0); static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0); + static bool haveSufficientGPUMemory(unsigned _platformId = 0); bool init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size = 64, unsigned _platformId = 0, unsigned _deviceId = 0); void finish(); diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index f62c1f9cd..0be0b520c 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -363,6 +363,11 @@ void Ethash::GPUMiner::pause() stopWorking(); } +bool Ethash::GPUMiner::haveSufficientGPUMemory() +{ + return ethash_cl_miner::haveSufficientGPUMemory(s_platformId); +} + std::string Ethash::GPUMiner::platformInfo() { return ethash_cl_miner::platform_info(s_platformId, s_deviceId); diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 86540678f..075b0522b 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -87,6 +87,7 @@ public: static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); + static bool haveSufficientGPUMemory() { return false; } static void setDefaultPlatform(unsigned) {} static void setDefaultDevice(unsigned) {} static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } @@ -115,6 +116,7 @@ public: static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } static std::string platformInfo(); + static bool haveSufficientGPUMemory(); static unsigned getNumDevices(); static void setDefaultPlatform(unsigned _id) { s_platformId = _id; } static void setDefaultDevice(unsigned _id) { s_deviceId = _id; }