diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 47fd2e2ae..b6d87e181 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -127,6 +127,10 @@ public: cerr << "Bad " << arg << " option: " << argv[i] << endl; throw BadArgument(); } + else if (arg == "--use-chunks") + { + dagChunks = 4; + } else if (arg == "--phone-home" && i + 1 < argc) { string m = argv[++i]; @@ -293,6 +297,7 @@ public: << " --opencl-platform <n> When mining using -G/--opencl use OpenCL platform n (default: 0)." << endl << " --opencl-device <n> When mining using -G/--opencl use OpenCL device n (default: 0)." << endl << " -t, --mining-threads <n> Limit number of CPU/GPU miners to n (default: use everything available on selected platform)" << endl + << " --use-chunks When using GPU mining upload the DAG to the GPU in 4 chunks. " << endl ; } @@ -480,6 +485,7 @@ private: unsigned openclPlatform = 0; unsigned openclDevice = 0; unsigned miningThreads = UINT_MAX; + unsigned dagChunks = 1; /// DAG initialisation param. unsigned initDAG = 0; diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 520a13180..5e69df1ee 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -43,9 +43,6 @@ #define CL_MEM_HOST_READ_ONLY 0 #endif -// maybe move to CMakeLists.txt ? -// #define ETHASH_CL_CHUNK_UPLOAD - #undef min #undef max @@ -61,7 +58,7 @@ static void add_definition(std::string& source, char const* id, unsigned value) ethash_cl_miner::search_hook::~search_hook() {} ethash_cl_miner::ethash_cl_miner() -: m_opencl_1_1() +: m_dagChunks(nullptr), m_opencl_1_1() { } @@ -130,10 +127,26 @@ void ethash_cl_miner::finish() { if (m_queue()) m_queue.finish(); + + if (m_dagChunks) + delete [] m_dagChunks; } -bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size, unsigned _platformId, unsigned _deviceId) +bool ethash_cl_miner::init( + uint8_t const* _dag, + uint64_t _dagSize, + unsigned workgroup_size, + unsigned _platformId, + unsigned _deviceId, + unsigned _dagChunksNum +) { + // for now due to the .cl kernels we can only have either 1 big chunk or 4 chunks + assert(_dagChunksNum == 1 || _dagChunksNum == 4); + // now create the number of chunk buffers + m_dagChunks = new cl::Buffer[_dagChunksNum]; + m_dagChunksNum = _dagChunksNum; + // get all platforms try { @@ -205,50 +218,61 @@ bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned work cout << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device).c_str(); return false; } - #ifdef ETHASH_CL_CHUNK_UPLOAD - cout << "loading ethash_hash_chunks" << endl; - m_hash_kernel = cl::Kernel(program, "ethash_hash_chunks"); - cout << "loading ethash_search_chunks" << endl; - m_search_kernel = cl::Kernel(program, "ethash_search_chunks"); - #else - cout << "loading ethash_hash" << endl; - m_hash_kernel = cl::Kernel(program, "ethash_hash"); - cout << "loading ethash_search" << endl; - m_search_kernel = cl::Kernel(program, "ethash_search"); - #endif - - // create buffer for dag - #ifdef ETHASH_CL_CHUNK_UPLOAD - for (unsigned i = 0; i < 4; i++) + if (_dagChunksNum == 1) + { + cout << "loading ethash_hash" << endl; + m_hash_kernel = cl::Kernel(program, "ethash_hash"); + cout << "loading ethash_search" << endl; + m_search_kernel = cl::Kernel(program, "ethash_search"); + } + else { - cout << "Creating chunky buffer: " << i << endl; - m_dags[i] = cl::Buffer(m_context, CL_MEM_READ_ONLY, (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7); + cout << "loading ethash_hash_chunks" << endl; + m_hash_kernel = cl::Kernel(program, "ethash_hash_chunks"); + cout << "loading ethash_search_chunks" << endl; + m_search_kernel = cl::Kernel(program, "ethash_search_chunks"); } - #else + + // create buffer for dag + if (_dagChunksNum == 1) + m_dagChunks[0] = cl::Buffer(m_context, CL_MEM_READ_ONLY, _dagSize); + else + for (unsigned i = 0; i < _dagChunksNum; i++) + { + // TODO Note: If we ever change to _dagChunksNum other than 4, then the size would need recalculation + cout << "Creating buffer for chunk " << i << endl; + m_dagChunks[i] = cl::Buffer( + m_context, + CL_MEM_READ_ONLY, + (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7 + ); + } cout << "Creating one big buffer." << endl; - m_dag = cl::Buffer(m_context, CL_MEM_READ_ONLY, _dagSize); - #endif // create buffer for header cout << "Creating buffer for header." << endl; m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32); - #ifdef ETHASH_CL_CHUNK_UPLOAD - void* dag_ptr[4]; - for (unsigned i = 0; i < 4; i++) + if (_dagChunksNum == 1) { - cout << "Mapping chunk " << i << endl; - dag_ptr[i] = m_queue.enqueueMapBuffer(m_dags[i], true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7); + cout << "Mapping one big chunk." << endl; + m_queue.enqueueWriteBuffer(m_dagChunks[0], CL_TRUE, 0, _dagSize, _dag); } - for (unsigned i = 0; i < 4; i++) + else { - memcpy(dag_ptr[i], (char *)_dag + i*((_dagSize >> 9) << 7), (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7); - m_queue.enqueueUnmapMemObject(m_dags[i], dag_ptr[i]); + // TODO Note: If we ever change to _dagChunksNum other than 4, then the size would need recalculation + void* dag_ptr[4]; + for (unsigned i = 0; i < _dagChunksNum; i++) + { + cout << "Mapping chunk " << i << endl; + dag_ptr[i] = m_queue.enqueueMapBuffer(m_dagChunks[i], true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7); + } + for (unsigned i = 0; i < _dagChunksNum; i++) + { + memcpy(dag_ptr[i], (char *)_dag + i*((_dagSize >> 9) << 7), (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7); + m_queue.enqueueUnmapMemObject(m_dagChunks[i], dag_ptr[i]); + } } - #else - cout << "Mapping chunk." << endl; - m_queue.enqueueWriteBuffer(m_dag, CL_TRUE, 0, _dagSize, _dag); - #endif // create mining buffers for (unsigned i = 0; i != c_num_buffers; ++i) @@ -288,22 +312,13 @@ void ethash_cl_miner::hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, uint isolate ) */ - #ifdef ETHASH_CL_CHUNK_UPLOAD cout << "Setting chunk hash arguments." << endl; + unsigned argPos = 2; m_hash_kernel.setArg(1, m_header); - m_hash_kernel.setArg(2, m_dags[0]); - m_hash_kernel.setArg(3, m_dags[1]); - m_hash_kernel.setArg(4, m_dags[2]); - m_hash_kernel.setArg(5, m_dags[3]); - m_hash_kernel.setArg(6, nonce); - m_hash_kernel.setArg(7, ~0u); // have to pass this to stop the compile unrolling the loop - #else - cout << "Setting hash arguments." << endl; - m_hash_kernel.setArg(1, m_header); - m_hash_kernel.setArg(2, m_dag); - m_hash_kernel.setArg(3, nonce); - m_hash_kernel.setArg(4, ~0u); // have to pass this to stop the compile unrolling the loop - #endif + for (unsigned i = 0 ; i < m_dagChunksNum; ++i, ++argPos) + m_hash_kernel.setArg(argPos, m_dagChunks[i]); + m_hash_kernel.setArg(argPos + 1, nonce); + m_hash_kernel.setArg(argPos + 2, ~0u); // have to pass this to stop the compiler unrolling the loop unsigned buf = 0; for (unsigned i = 0; i < count || !pending.empty(); ) @@ -381,27 +396,13 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook uint isolate // 5 ) */ - #ifdef ETHASH_CL_CHUNK_UPLOAD - cout << "Setting chunk search arguments." << endl; - m_search_kernel.setArg(1, m_header); - m_search_kernel.setArg(2, m_dags[0]); - m_search_kernel.setArg(3, m_dags[1]); - m_search_kernel.setArg(4, m_dags[2]); - m_search_kernel.setArg(5, m_dags[3]); - - // pass these to stop the compiler unrolling the loops - m_search_kernel.setArg(7, target); - m_search_kernel.setArg(8, ~0u); - - #else - cout << "Setting search arguments." << endl; + unsigned argPos = 2; m_search_kernel.setArg(1, m_header); - m_search_kernel.setArg(2, m_dag); - + for (unsigned i = 0; i < m_dagChunksNum; ++i, ++argPos) + m_search_kernel.setArg(argPos, m_dagChunks[i]); // pass these to stop the compiler unrolling the loops - m_search_kernel.setArg(4, target); - m_search_kernel.setArg(5, ~0u); - #endif + m_search_kernel.setArg(argPos + 1, target); + m_search_kernel.setArg(argPos + 2, ~0u); unsigned buf = 0; std::random_device engine; @@ -410,11 +411,10 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook { // supply output buffer to kernel m_search_kernel.setArg(0, m_search_buf[buf]); - #ifdef ETHASH_CL_CHUNK_UPLOAD - m_search_kernel.setArg(6, start_nonce); - #else - m_search_kernel.setArg(3, start_nonce); - #endif + if (m_dagChunksNum == 1) + m_search_kernel.setArg(3, start_nonce); + else + m_search_kernel.setArg(6, start_nonce); // execute it! m_queue.enqueueNDRangeKernel(m_search_kernel, cl::NullRange, c_search_batch_size, m_workgroup_size); diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index 9c97f2aa4..0f83f8565 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -36,7 +36,14 @@ public: static unsigned get_num_devices(unsigned _platformId = 0); static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0); - bool init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size = 64, unsigned _platformId = 0, unsigned _deviceId = 0); + bool init( + uint8_t const* _dag, + uint64_t _dagSize, + unsigned workgroup_size = 64, + unsigned _platformId = 0, + unsigned _deviceId = 0, + unsigned _dagChunksNum = 1 + ); void finish(); void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count); void search(uint8_t const* header, uint64_t target, search_hook& hook); @@ -51,11 +58,11 @@ private: cl::CommandQueue m_queue; cl::Kernel m_hash_kernel; cl::Kernel m_search_kernel; - cl::Buffer m_dag; - cl::Buffer m_dags[4]; + unsigned m_dagChunksNum; + cl::Buffer* m_dagChunks; cl::Buffer m_header; cl::Buffer m_hash_buf[c_num_buffers]; cl::Buffer m_search_buf[c_num_buffers]; unsigned m_workgroup_size; bool m_opencl_1_1; -}; \ No newline at end of file +}; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index f62c1f9cd..158f40981 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -285,6 +285,7 @@ private: unsigned Ethash::GPUMiner::s_platformId = 0; unsigned Ethash::GPUMiner::s_deviceId = 0; unsigned Ethash::GPUMiner::s_numInstances = 0; +unsigned Ethash::GPUMiner::s_dagChunks = 1; Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): Miner(_ci), @@ -345,7 +346,7 @@ void Ethash::GPUMiner::workLoop() this_thread::sleep_for(chrono::milliseconds(500)); } bytesConstRef dagData = dag->data(); - m_miner->init(dagData.data(), dagData.size(), 32, s_platformId, device); + m_miner->init(dagData.data(), dagData.size(), 32, s_platformId, device, s_dagChunks); } uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 86540678f..868c27916 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -119,6 +119,7 @@ public: 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<unsigned>(_instances, getNumDevices()); } + static void setDagChunks(unsigned _dagChunks) { s_dagChunks = _dagChunks; } protected: void kickOff() override; @@ -137,6 +138,7 @@ public: static unsigned s_platformId; static unsigned s_deviceId; static unsigned s_numInstances; + static unsigned s_dagChunks; }; #else using GPUMiner = CPUMiner;