Add xenoncat support (AVX1 and AVX2)
This commit is contained in:
parent
9afe293806
commit
d2016f59d7
|
@ -0,0 +1,3 @@
|
|||
[submodule "nheqminer/external/equihash-xenon"]
|
||||
path = nheqminer/external/equihash-xenon
|
||||
url = https://github.com/xenoncat/equihash-xenon
|
|
@ -2,19 +2,42 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
option(STATIC_BUILD "Build with static libraries on Linux")
|
||||
option(XENON "Build options with xenoncat")
|
||||
option(MARCH "GCC options for architecture (default: native)")
|
||||
|
||||
project(nheqminer)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
|
||||
# LINUX
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
if (MARCH)
|
||||
set (GCCMARCH MARCH)
|
||||
else()
|
||||
set (GCCMARCH "-march=native")
|
||||
endif()
|
||||
|
||||
# use native cpu features
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GCCMARCH}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCCMARCH}")
|
||||
# optimizations
|
||||
add_definitions(-O3)
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
if (XENON EQUAL 0)
|
||||
unset (XENONCAT)
|
||||
elseif (XENON EQUAL 1)
|
||||
set (XENONCAT "${nheqminer_SOURCE_DIR}/external/equihash-xenon/Linux/asm/equihash_avx1.o")
|
||||
add_definitions(-DXENONCAT=1)
|
||||
elseif (XENON EQUAL 2)
|
||||
set (XENONCAT "${nheqminer_SOURCE_DIR}/external/equihash-xenon/Linux/asm/equihash_avx2.o")
|
||||
add_definitions(-DXENONCAT=2)
|
||||
else()
|
||||
set (XENONCAT "${nheqminer_SOURCE_DIR}/external/equihash-xenon/Linux/asm/equihash_avx2.o")
|
||||
add_definitions(-DXENONCAT=2)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Common
|
||||
include_directories(${nheqminer_SOURCE_DIR})
|
||||
|
||||
|
@ -24,8 +47,6 @@ else()
|
|||
add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_ALL_DYN_LINK -DBOOST_LOG_DYN_LINK)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
find_package(Threads REQUIRED COMPONENTS)
|
||||
find_package(Boost REQUIRED COMPONENTS system log_setup log date_time filesystem thread)
|
||||
|
||||
|
@ -136,12 +157,15 @@ endif()
|
|||
set(LIBS ${LIBS} ${Threads_LIBRARIES} ${Boost_LIBRARIES})
|
||||
|
||||
message("-- CXXFLAGS: ${CMAKE_CXX_FLAGS}")
|
||||
|
||||
message("-- LIBS: ${LIBS}")
|
||||
message("-- XENON: ${XENON}")
|
||||
message("-- XENONCAT: ${XENONCAT}")
|
||||
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCE_FILES})
|
||||
#target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES})
|
||||
target_link_libraries(${PROJECT_NAME} ${LIBS})
|
||||
# target_link_libraries(${PROJECT_NAME} ${LIBS} ${CMAKE_THREAD_LIBS_INIT} ${nheqminer_SOURCE_DIR}/external/equihash-xenon/Linux/asm/equihash_avx2.o)
|
||||
target_link_libraries(${PROJECT_NAME} ${LIBS} ${CMAKE_THREAD_LIBS_INIT} ${XENONCAT})
|
||||
if (STATIC_BUILD)
|
||||
# set_target_properties(${PROJECT_NAME} PROPERTIES LINK_SEARCH_START_STATIC 1)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_SEARCH_END_STATIC 1)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit ebd7d3d89693a9627f3064851e32f7fca086c259
|
|
@ -30,6 +30,11 @@ typedef uint32_t eh_index;
|
|||
|
||||
#define BOOST_LOG_CUSTOM(sev, pos) BOOST_LOG_TRIVIAL(sev) << "miner#" << pos << " | "
|
||||
|
||||
#ifdef XENONCAT
|
||||
#define CONTEXT_SIZE 178033152
|
||||
extern "C" void EhPrepare(void *context, void *input);
|
||||
extern "C" int32_t EhSolver(void *context, uint32_t nonce);
|
||||
#endif
|
||||
|
||||
void CompressArray(const unsigned char* in, size_t in_len,
|
||||
unsigned char* out, size_t out_len,
|
||||
|
@ -96,8 +101,212 @@ std::vector<unsigned char> GetMinimalFromIndices(std::vector<eh_index> indices,
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef XENONCAT
|
||||
void static XenoncatZcashMinerThread(ZcashMiner* miner, int size, int pos)
|
||||
{
|
||||
BOOST_LOG_CUSTOM(info, pos) << "Starting thread #" << pos;
|
||||
|
||||
void static ZcashMinerThread(ZcashMiner* miner, int size, int pos)
|
||||
unsigned int n = PARAMETER_N;
|
||||
unsigned int k = PARAMETER_K;
|
||||
|
||||
std::shared_ptr<std::mutex> m_zmt(new std::mutex);
|
||||
CBlockHeader header;
|
||||
arith_uint256 space;
|
||||
size_t offset;
|
||||
arith_uint256 inc;
|
||||
arith_uint256 target;
|
||||
std::string jobId;
|
||||
std::string nTime;
|
||||
std::atomic_bool workReady {false};
|
||||
std::atomic_bool cancelSolver {false};
|
||||
std::atomic_bool pauseMining {false};
|
||||
|
||||
miner->NewJob.connect(NewJob_t::slot_type(
|
||||
[&m_zmt, &header, &space, &offset, &inc, &target, &workReady, &cancelSolver, pos, &pauseMining, &jobId, &nTime]
|
||||
(const ZcashJob* job) mutable {
|
||||
std::lock_guard<std::mutex> lock{*m_zmt.get()};
|
||||
if (job) {
|
||||
BOOST_LOG_CUSTOM(debug, pos) << "Loading new job #" << job->jobId();
|
||||
jobId = job->jobId();
|
||||
nTime = job->time;
|
||||
header = job->header;
|
||||
space = job->nonce2Space;
|
||||
offset = job->nonce1Size * 4; // Hex length to bit length
|
||||
inc = job->nonce2Inc;
|
||||
target = job->serverTarget;
|
||||
pauseMining.store(false);
|
||||
workReady.store(true);
|
||||
/*if (job->clean) {
|
||||
cancelSolver.store(true);
|
||||
}*/
|
||||
} else {
|
||||
workReady.store(false);
|
||||
cancelSolver.store(true);
|
||||
pauseMining.store(true);
|
||||
}
|
||||
}
|
||||
).track_foreign(m_zmt)); // So the signal disconnects when the mining thread exits
|
||||
|
||||
// Initialize context memory.
|
||||
void* context_alloc = malloc(CONTEXT_SIZE+4096);
|
||||
void* context = (void*) (((long) context_alloc+4095) & -4096);
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
// Wait for work
|
||||
bool expected;
|
||||
do {
|
||||
expected = true;
|
||||
if (!miner->minerThreadActive[pos])
|
||||
throw boost::thread_interrupted();
|
||||
//boost::this_thread::interruption_point();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
} while (!workReady.compare_exchange_weak(expected, false));
|
||||
// TODO change atomically with workReady
|
||||
cancelSolver.store(false);
|
||||
|
||||
// Calculate nonce limits
|
||||
arith_uint256 nonce;
|
||||
arith_uint256 nonceEnd;
|
||||
CBlockHeader actualHeader;
|
||||
std::string actualJobId;
|
||||
std::string actualTime;
|
||||
size_t actualNonce1size;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{*m_zmt.get()};
|
||||
arith_uint256 baseNonce = UintToArith256(header.nNonce);
|
||||
arith_uint256 add(pos);
|
||||
nonce = baseNonce | (add << (8 * 31));
|
||||
nonceEnd = baseNonce | ((add + 1) << (8 * 31));
|
||||
//nonce = baseNonce + ((space/size)*pos << offset);
|
||||
//nonceEnd = baseNonce + ((space/size)*(pos+1) << offset);
|
||||
|
||||
// save job id and time
|
||||
actualHeader = header;
|
||||
actualJobId = jobId;
|
||||
actualTime = nTime;
|
||||
actualNonce1size = offset / 4;
|
||||
}
|
||||
|
||||
// I = the block header minus nonce and solution.
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
{
|
||||
//std::lock_guard<std::mutex> lock{ *m_zmt.get() };
|
||||
CEquihashInput I{ actualHeader };
|
||||
ss << I;
|
||||
}
|
||||
|
||||
const char *tequihash_header = (char *)&ss[0];
|
||||
unsigned int tequihash_header_len = ss.size();
|
||||
|
||||
// Start working
|
||||
while (true) {
|
||||
BOOST_LOG_CUSTOM(debug, pos) << "Running Equihash solver with nNonce = " << nonce.ToString();
|
||||
|
||||
auto bNonce = ArithToUint256(nonce);
|
||||
std::function<bool(std::vector<unsigned char>)> validBlock =
|
||||
[&m_zmt, &actualHeader, &bNonce, &target, &miner, pos, &actualJobId, &actualTime, &actualNonce1size]
|
||||
(std::vector<unsigned char> soln) {
|
||||
//std::lock_guard<std::mutex> lock{*m_zmt.get()};
|
||||
// Write the solution to the hash and compute the result.
|
||||
BOOST_LOG_CUSTOM(debug, pos) << "Checking solution against target...";
|
||||
actualHeader.nNonce = bNonce;
|
||||
actualHeader.nSolution = soln;
|
||||
|
||||
speed.AddSolution();
|
||||
|
||||
uint256 headerhash = actualHeader.GetHash();
|
||||
if (UintToArith256(headerhash) > target) {
|
||||
BOOST_LOG_CUSTOM(debug, pos) << "Too large: " << headerhash.ToString();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Found a solution
|
||||
BOOST_LOG_CUSTOM(debug, pos) << "Found solution with header hash: " << headerhash.ToString();
|
||||
EquihashSolution solution{ bNonce, soln, actualTime, actualNonce1size };
|
||||
miner->submitSolution(solution, actualJobId);
|
||||
|
||||
// We're a pooled miner, so try all solutions
|
||||
return false;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Xenoncat solver.
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// bnonce is 32 bytes, read last four bytes as nonce int and send it to
|
||||
// eh solver method.
|
||||
unsigned char *tequihash_header = (unsigned char *)&ss[0];
|
||||
unsigned int tequihash_header_len = ss.size();
|
||||
unsigned char inputheader[144];
|
||||
memcpy(inputheader, tequihash_header, tequihash_header_len);
|
||||
|
||||
// Write 32 byte nonce to input header.
|
||||
uint256 arthNonce = ArithToUint256(nonce);
|
||||
memcpy(inputheader + tequihash_header_len, (unsigned char*) arthNonce.begin(), arthNonce.size());
|
||||
|
||||
|
||||
EhPrepare(context, (void *) inputheader);
|
||||
|
||||
unsigned char* nonceBegin = bNonce.begin();
|
||||
uint32_t nonceToApi = *(uint32_t *)(nonceBegin+28);
|
||||
uint32_t numsolutions = EhSolver(context, nonceToApi);
|
||||
if (!cancelSolver.load()) {
|
||||
for (uint32_t i=0; i<numsolutions; i++) {
|
||||
// valid block method expects vector of unsigned chars.
|
||||
unsigned char* solutionStart = (unsigned char*)(((unsigned char*)context)+1344*i);
|
||||
unsigned char* solutionEnd = solutionStart + 1344;
|
||||
std::vector<unsigned char> solution(solutionStart, solutionEnd);
|
||||
validBlock(solution);
|
||||
}
|
||||
}
|
||||
speed.AddHash(); // Metrics, add one hash execution.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Xenoncat solver.
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Check for stop
|
||||
if (!miner->minerThreadActive[pos])
|
||||
throw boost::thread_interrupted();
|
||||
//boost::this_thread::interruption_point();
|
||||
|
||||
// Update nonce
|
||||
nonce += inc;
|
||||
|
||||
if (nonce == nonceEnd) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for new work
|
||||
if (workReady.load()) {
|
||||
BOOST_LOG_CUSTOM(debug, pos) << "New work received, dropping current work";
|
||||
break;
|
||||
}
|
||||
|
||||
if (pauseMining.load())
|
||||
{
|
||||
BOOST_LOG_CUSTOM(debug, pos) << "Mining paused";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const boost::thread_interrupted&)
|
||||
{
|
||||
BOOST_LOG_CUSTOM(info, pos) << "Thread #" << pos << " terminated";
|
||||
//throw;
|
||||
return;
|
||||
}
|
||||
catch (const std::runtime_error &e)
|
||||
{
|
||||
BOOST_LOG_CUSTOM(info, pos) << "Runtime error: " << e.what();
|
||||
return;
|
||||
}
|
||||
// Free the memory allocated previously for xenoncat context.
|
||||
free(context_alloc);
|
||||
}
|
||||
#endif
|
||||
|
||||
void static TrompZcashMinerThread(ZcashMiner* miner, int size, int pos)
|
||||
{
|
||||
BOOST_LOG_CUSTOM(info, pos) << "Starting thread #" << pos;
|
||||
|
||||
|
@ -308,6 +517,32 @@ void static ZcashMinerThread(ZcashMiner* miner, int size, int pos)
|
|||
}
|
||||
}
|
||||
|
||||
void static ZcashMinerThread(ZcashMiner* miner, int size, int pos)
|
||||
{
|
||||
|
||||
#ifdef XENONCAT
|
||||
#if XENONCAT == 2
|
||||
if (__builtin_cpu_supports("avx2")) {
|
||||
BOOST_LOG_CUSTOM(info, pos) << "Using Xenoncat's AVX2 solver. ";
|
||||
XenoncatZcashMinerThread(miner, size, pos);
|
||||
}
|
||||
#elif XENONCAT == 1
|
||||
if (__builtin_cpu_supports("avx")) {
|
||||
BOOST_LOG_CUSTOM(info, pos) << "Using Xenoncat's AVX solver. ";
|
||||
XenoncatZcashMinerThread(miner, size, pos);
|
||||
}
|
||||
#else
|
||||
if (0) {}
|
||||
#endif
|
||||
else {
|
||||
#endif
|
||||
BOOST_LOG_CUSTOM(info, pos) << "Using Tromp's solver.";
|
||||
TrompZcashMinerThread(miner, size, pos);
|
||||
#ifdef XENONCAT
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ZcashJob* ZcashJob::clone() const
|
||||
{
|
||||
ZcashJob* ret = new ZcashJob();
|
||||
|
@ -652,4 +887,4 @@ void do_benchmark(int nThreads, int hashes)
|
|||
std::cout << "Total solutions found: " << benchmark_solutions << std::endl;
|
||||
std::cout << "Speed: " << ((double)hashes_done * 1000 / (double)msec) << " H/s" << std::endl;
|
||||
std::cout << "Speed: " << ((double)benchmark_solutions * 1000 / (double)msec) << " S/s" << std::endl;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue