diff --git a/backend/BackendConnector.cpp b/backend/BackendConnector.cpp new file mode 100644 index 0000000..f7a63fe --- /dev/null +++ b/backend/BackendConnector.cpp @@ -0,0 +1,90 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Additional permission under GNU GPL version 3 section 7 + * + * If you modify this Program, or any covered work, by linking or combining + * it with OpenSSL (or a modified version of that library), containing parts + * covered by the terms of OpenSSL License and SSLeay License, the licensors + * of this Program grant you additional permission to convey the resulting work. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "IBackend.hpp" +#include "BackendConnector.hpp" + +#include "cpu/minethd.h" +#ifndef CONF_NO_CUDA +# include "nvidia/minethd.h" +#endif +#ifndef CONF_NO_OPENCL +# include "amd/minethd.h" +#endif +#include "miner_work.h" +#include "GlobalStates.hpp" + #include + +#include "Plugin.hpp" + +namespace xmrstak +{ + + +bool BackendConnector::self_test() +{ + + return true; +} + +std::vector* BackendConnector::thread_starter(miner_work& pWork) +{ + GlobalStates::iGlobalJobNo = 0; + GlobalStates::iConsumeCnt = 0; + + + std::vector* pvThreads = new std::vector; + + auto cpuThreads = cpu::minethd::thread_starter(pvThreads->size(), pWork); + pvThreads->insert(std::end(*pvThreads), std::begin(cpuThreads), std::end(cpuThreads)); + if(cpuThreads.size() == 0) + printer::inst()->print_msg(L0, "WARNING: backend CPU disabled."); + +#ifndef CONF_NO_CUDA + Plugin nvidiaPlugin("NVIDIA", "./libxmrstak_cuda_backend"); + std::vector* nvidiaThreads = nvidiaPlugin.startBackend(pvThreads->size(), pWork); + pvThreads->insert(std::end(*pvThreads), std::begin(*nvidiaThreads), std::end(*nvidiaThreads)); + if(nvidiaThreads->size() == 0) + printer::inst()->print_msg(L0, "WARNING: backend NVIDIA disabled."); +#endif + +#ifndef CONF_NO_OPENCL + Plugin amdPlugin("AMD", "./libxmrstak_opencl_backend"); + std::vector* amdThreads = amdPlugin.startBackend(pvThreads->size(), pWork); + pvThreads->insert(std::end(*pvThreads), std::begin(*amdThreads), std::end(*amdThreads)); + if(amdThreads->size() == 0) + printer::inst()->print_msg(L0, "WARNING: backend AMD disabled."); +#endif + + GlobalStates::iThreadCount = pvThreads->size(); + return pvThreads; +} + +} // namepsace xmrstak diff --git a/backend/BackendConnector.hpp b/backend/BackendConnector.hpp new file mode 100644 index 0000000..024d9b1 --- /dev/null +++ b/backend/BackendConnector.hpp @@ -0,0 +1,18 @@ +#pragma once +#include +#include +#include +#include +#include "IBackend.hpp" +#include "miner_work.h" + +namespace xmrstak +{ + + struct BackendConnector + { + static std::vector* thread_starter(miner_work& pWork); + static bool self_test(); + }; + +} // namepsace xmrstak diff --git a/backend/GlobalStates.cpp b/backend/GlobalStates.cpp new file mode 100644 index 0000000..99356b5 --- /dev/null +++ b/backend/GlobalStates.cpp @@ -0,0 +1,55 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Additional permission under GNU GPL version 3 section 7 + * + * If you modify this Program, or any covered work, by linking or combining + * it with OpenSSL (or a modified version of that library), containing parts + * covered by the terms of OpenSSL License and SSLeay License, the licensors + * of this Program grant you additional permission to convey the resulting work. + * + */ + +#include +#include +#include +#include + + +#include "miner_work.h" +#include "GlobalStates.hpp" + +namespace xmrstak +{ + +std::atomic GlobalStates::iGlobalJobNo; +std::atomic GlobalStates::iConsumeCnt; //Threads get jobs as they are initialized +miner_work GlobalStates::oGlobalWork; +uint64_t GlobalStates::iThreadCount = 0; + +void GlobalStates::switch_work(miner_work& pWork) +{ + // iConsumeCnt is a basic lock-like polling mechanism just in case we happen to push work + // faster than threads can consume them. This should never happen in real life. + // Pool cant physically send jobs faster than every 250ms or so due to net latency. + + while (iConsumeCnt.load(std::memory_order_seq_cst) < iThreadCount) + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + oGlobalWork = pWork; + iConsumeCnt.store(0, std::memory_order_seq_cst); + iGlobalJobNo++; +} + +} // namepsace xmrstak diff --git a/backend/GlobalStates.hpp b/backend/GlobalStates.hpp new file mode 100644 index 0000000..293009d --- /dev/null +++ b/backend/GlobalStates.hpp @@ -0,0 +1,20 @@ +#pragma once +#include +#include "miner_work.h" + +namespace xmrstak +{ + +struct GlobalStates +{ + + static void switch_work(miner_work& pWork); + + static miner_work oGlobalWork; + static std::atomic iGlobalJobNo; + static std::atomic iConsumeCnt; + static uint64_t iThreadCount; + +}; + +} // namepsace xmrstak diff --git a/backend/IBackend.hpp b/backend/IBackend.hpp new file mode 100644 index 0000000..5037028 --- /dev/null +++ b/backend/IBackend.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + + +namespace xmrstak +{ + + struct IBackend + { + std::atomic iHashCount; + std::atomic iTimestamp; + + IBackend() : iHashCount(0), iTimestamp(0) + { + } + }; + +} // namepsace xmrstak diff --git a/backend/Plugin.hpp b/backend/Plugin.hpp new file mode 100644 index 0000000..762f955 --- /dev/null +++ b/backend/Plugin.hpp @@ -0,0 +1,90 @@ +#pragma once +#include +#include +#include +#include +#include "IBackend.hpp" +#include + +#ifndef USE_PRECOMPILED_HEADERS +#ifdef WIN32 +#include +#include +#else +#include +#include +#endif +#include +#endif + +namespace xmrstak +{ + +struct Plugin +{ + + Plugin(const std::string backendName, const std::string libName) : fn_starterBackend(nullptr), m_backendName(backendName) + { +#ifdef WIN32 + libBackend = LoadLibrary(TEXT((libName + ".dll").c_str())); +#else + libBackend = dlopen((libName + ".so").c_str(), RTLD_LAZY); +#endif + if (!libBackend) + { + std::cerr << "WARNING: "<< m_backendName <<" cannot load backend library: " << dlerror() << std::endl; + return; + } + +#ifdef WIN32 + fn_starterBackend = (func_t*) GetProcAddress(libBackend, "xmrstak_start_backend"); + if (!fn_starterBackend) + { + std::cerr << "WARNING: backend plugin " << libName << " contains no entry 'xmrstak_start_backend'" << std::endl; + } +#else + // reset last error + dlerror(); + fn_starterBackend = (starterBackend_t) dlsym(libBackend, "xmrstak_start_backend"); + const char* dlsym_error = dlerror(); + if (dlsym_error) + { + std::cerr << "WARNING: backend plugin " << libName << " contains no entry 'xmrstak_start_backend'" << std::endl; + } +#endif + } + + std::vector* startBackend(uint32_t threadOffset, miner_work& pWork) + { + if(fn_starterBackend == nullptr) + { + std::vector* pvThreads = new std::vector(); + std::cerr << "WARNING: " << m_backendName << " Backend disabled"<< std::endl; + return pvThreads; + } + + return fn_starterBackend(threadOffset, pWork); + } + + std::string m_backendName; + + typedef std::vector* (*starterBackend_t)(uint32_t threadOffset, miner_work& pWork); + + starterBackend_t fn_starterBackend; + +#ifdef WIN32 + HINSTANCE libBackend; +#else + void *libBackend; +#endif + +/* \todo add unload to destructor and change usage of Plugin that libs keeped open until the miner endss +#ifdef WIN32 + FreeLibrary(libBackend); +#else + dlclose(libBackend); +#endif + * */ +}; + +} // namepsace xmrstak diff --git a/backend/miner_work.h b/backend/miner_work.h new file mode 100644 index 0000000..b922f4a --- /dev/null +++ b/backend/miner_work.h @@ -0,0 +1,102 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace xmrstak +{ + // only allowed for unsigned value \todo add static assert + template + T reverseBits(T value) + { + /* init with value (to get LSB) */ + T result = value; + /* extra shift needed at end */ + int s = sizeof(T) * CHAR_BIT - 1; + for (value >>= 1; value; value >>= 1) + { + result <<= 1; + result |= value & 1; + s--; + } + /* shift when values highest bits are zero */ + result <<= s; + return result; + } + + struct miner_work + { + char sJobID[64]; + uint8_t bWorkBlob[112]; + uint32_t iWorkSize; + uint32_t iResumeCnt; + uint64_t iTarget; + // \todo remove workaround needed for amd + uint32_t iTarget32; + bool bNiceHash; + bool bStall; + size_t iPoolId; + + miner_work() : iWorkSize(0), bNiceHash(false), bStall(true), iPoolId(0) { } + + miner_work(const char* sJobID, const uint8_t* bWork, uint32_t iWorkSize, uint32_t iResumeCnt, + uint64_t iTarget, size_t iPoolId) : iWorkSize(iWorkSize), iResumeCnt(iResumeCnt), + iTarget(iTarget), bNiceHash(false), bStall(false), iPoolId(iPoolId) + { + assert(iWorkSize <= sizeof(bWorkBlob)); + memcpy(this->sJobID, sJobID, sizeof(miner_work::sJobID)); + memcpy(this->bWorkBlob, bWork, iWorkSize); + } + + miner_work(miner_work const&) = delete; + + miner_work& operator=(miner_work const& from) + { + assert(this != &from); + + iWorkSize = from.iWorkSize; + iResumeCnt = from.iResumeCnt; + iTarget = from.iTarget; + iTarget32 = from.iTarget32; + bNiceHash = from.bNiceHash; + bStall = from.bStall; + iPoolId = from.iPoolId; + + assert(iWorkSize <= sizeof(bWorkBlob)); + memcpy(sJobID, from.sJobID, sizeof(sJobID)); + memcpy(bWorkBlob, from.bWorkBlob, iWorkSize); + + return *this; + } + + miner_work(miner_work&& from) : iWorkSize(from.iWorkSize), iTarget(from.iTarget),iTarget32(from.iTarget32), + bStall(from.bStall), iPoolId(from.iPoolId) + { + assert(iWorkSize <= sizeof(bWorkBlob)); + memcpy(sJobID, from.sJobID, sizeof(sJobID)); + memcpy(bWorkBlob, from.bWorkBlob, iWorkSize); + } + + miner_work& operator=(miner_work&& from) + { + assert(this != &from); + + iWorkSize = from.iWorkSize; + iResumeCnt = from.iResumeCnt; + iTarget = from.iTarget; + iTarget32 = from.iTarget32; + bNiceHash = from.bNiceHash; + bStall = from.bStall; + iPoolId = from.iPoolId; + + assert(iWorkSize <= sizeof(bWorkBlob)); + memcpy(sJobID, from.sJobID, sizeof(sJobID)); + memcpy(bWorkBlob, from.bWorkBlob, iWorkSize); + + return *this; + } + }; +} // namepsace xmrstak