Skip to content
This repository was archived by the owner on Apr 24, 2022. It is now read-only.

Commit 19459aa

Browse files
committedMay 24, 2016
on-GPU DAG generation
1 parent ea73d3e commit 19459aa

18 files changed

+639
-66
lines changed
 

‎CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
cmake_minimum_required(VERSION 2.8.12)
33

44
set(PROJECT_VERSION "0.9.41")
5-
set(GENOIL_VERSION "1.0.8")
5+
set(GENOIL_VERSION "1.1")
66
if (${CMAKE_VERSION} VERSION_GREATER 3.0)
77
cmake_policy(SET CMP0042 OLD) # fix MACOSX_RPATH
88
cmake_policy(SET CMP0048 NEW) # allow VERSION argument in project()

‎ethminer/MinerAux.h

+19-13
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ class MinerCLI
362362
}
363363
else if (arg == "--current-block" && i + 1 < argc)
364364
m_currentBlock = stol(argv[++i]);
365+
/*
365366
else if ((arg == "-R" || arg == "--dag-dir") && i + 1 < argc)
366367
{
367368
strcpy(s_dagDir, argv[++i]);
@@ -395,6 +396,7 @@ class MinerCLI
395396
BOOST_THROW_EXCEPTION(BadArgument());
396397
}
397398
}
399+
*/
398400
else if ((arg == "-w" || arg == "--check-pow") && i + 4 < argc)
399401
{
400402
string m;
@@ -494,13 +496,15 @@ class MinerCLI
494496

495497
void execute()
496498
{
499+
/*
497500
EthashAux::setDAGDirName(s_dagDir);
498501
EthashAux::setDAGEraseMode(m_eraseMode);
499502
EthashAux::eraseDAGs();
500503
if (m_eraseMode == DAGEraseMode::All)
501504
{
502505
m_eraseMode = DAGEraseMode::None;
503506
}
507+
*/
504508

505509
if (m_shouldListDevices)
506510
{
@@ -596,7 +600,7 @@ class MinerCLI
596600
<< " -FS, --failover-stratum <host:port> Failover stratum server at host:port" << endl
597601
<< " -O, --userpass <username.workername:password> Stratum login credentials" << endl
598602
<< " -FO, --failover-userpass <username.workername:password> Failover stratum login credentials (optional, will use normal credentials when omitted)" << endl
599-
<< " --work-timeout <n> reconnect/failover after n seconds of working on the same (stratum) job. Defaults to 60. Don't set lower than max. avg. block time" << endl
603+
<< " --work-timeout <n> reconnect/failover after n seconds of working on the same (stratum) job. Defaults to 180. Don't set lower than max. avg. block time" << endl
600604
#endif
601605
#if ETH_JSONRPC || ETH_STRATUM || !ETH_TRUE
602606
<< " --farm-recheck <n> Leave n ms between checks for changed work (default: 500). When using stratum, use a high value (i.e. 2000) to get more stable hashrate output" << endl
@@ -615,14 +619,14 @@ class MinerCLI
615619
#if ETH_JSONRPC || !ETH_TRUE
616620
<< " --phone-home <on/off> When benchmarking, publish results (default: off)" << endl
617621
#endif
618-
<< "DAG file management:" << endl
619-
<< " -D,--create-dag <number> Create the DAG in preparation for mining on given block and exit." << endl
620-
<< " -R <s>, --dag-dir <s> Store/Load DAG files in/from the specified directory. Useful for running multiple instances with different configurations." << endl
621-
<< " -E <mode>, --erase-dags <mode> Erase unneeded DAG files. Default is 'none'. Possible values are:" << endl
622-
<< " none - don't erase DAG files (default)" << endl
623-
<< " old - erase all DAG files older than current epoch" << endl
624-
<< " bench - like old, but keep epoch 0 for benchmarking" << endl
625-
<< " all - erase all DAG files. After deleting all files, setting changes to none." << endl
622+
// << "DAG file management:" << endl
623+
// << " -D,--create-dag <number> Create the DAG in preparation for mining on given block and exit." << endl
624+
// << " -R <s>, --dag-dir <s> Store/Load DAG files in/from the specified directory. Useful for running multiple instances with different configurations." << endl
625+
// << " -E <mode>, --erase-dags <mode> Erase unneeded DAG files. Default is 'none'. Possible values are:" << endl
626+
// << " none - don't erase DAG files (default)" << endl
627+
// << " old - erase all DAG files older than current epoch" << endl
628+
// << " bench - like old, but keep epoch 0 for benchmarking" << endl
629+
// << " all - erase all DAG files. After deleting all files, setting changes to none." << endl
626630
<< "Mining configuration:" << endl
627631
<< " -C,--cpu When mining, use the CPU." << endl
628632
<< " -G,--opencl When mining use the GPU via OpenCL." << endl
@@ -691,7 +695,7 @@ class MinerCLI
691695
cout << "Benchmarking on platform: " << platformInfo << endl;
692696

693697
cout << "Preparing DAG for block #" << m_benchmarkBlock << endl;
694-
genesis.prep();
698+
//genesis.prep();
695699

696700
genesis.setDifficulty(u256(1) << 63);
697701
f.setWork(genesis);
@@ -774,7 +778,7 @@ class MinerCLI
774778
cout << "Running mining simulation on platform: " << platformInfo << endl;
775779

776780
cout << "Preparing DAG for block #" << m_benchmarkBlock << endl;
777-
genesis.prep();
781+
//genesis.prep();
778782

779783
genesis.setDifficulty(u256(1) << difficulty);
780784
f.setWork(genesis);
@@ -911,6 +915,7 @@ class MinerCLI
911915
Json::Value v = prpc->eth_getWork();
912916
h256 hh(v[0].asString());
913917
h256 newSeedHash(v[1].asString());
918+
/*
914919
if (current.seedHash != newSeedHash)
915920
{
916921
minelog << "Grabbing DAG for" << newSeedHash;
@@ -923,6 +928,7 @@ class MinerCLI
923928
{
924929
EthashAux::computeFull(sha3(newSeedHash), true);
925930
}
931+
*/
926932
if (hh != current.headerHash)
927933
{
928934
x_current.lock();
@@ -1104,7 +1110,7 @@ class MinerCLI
11041110

11051111
/// Benchmarking params
11061112
bool m_phoneHome = false;
1107-
unsigned m_benchmarkWarmup = 3;
1113+
unsigned m_benchmarkWarmup = 15;
11081114
unsigned m_benchmarkTrial = 3;
11091115
unsigned m_benchmarkTrials = 5;
11101116
unsigned m_benchmarkBlock = 0;
@@ -1119,7 +1125,7 @@ class MinerCLI
11191125
unsigned m_farmRecheckPeriod = 500;
11201126
unsigned m_defaultStratumFarmRecheckPeriod = 2000;
11211127
bool m_farmRecheckSet = false;
1122-
int m_worktimeout = 90;
1128+
int m_worktimeout = 180;
11231129
bool m_precompute = true;
11241130

11251131
#if ETH_STRATUM || !ETH_TRUE

‎libethash-cl/ethash_cl_miner.cpp

+41-9
Original file line numberDiff line numberDiff line change
@@ -324,9 +324,11 @@ void ethash_cl_miner::finish()
324324
m_queue.finish();
325325
}
326326

327+
327328
bool ethash_cl_miner::init(
328-
uint8_t const* _dag,
329-
uint64_t _dagSize,
329+
ethash_light_t _light,
330+
uint8_t const* _lightData,
331+
uint64_t _lightSize,
330332
unsigned _platformId,
331333
unsigned _deviceId
332334
)
@@ -399,12 +401,17 @@ bool ethash_cl_miner::init(
399401
if (m_globalWorkSize % s_workgroupSize != 0)
400402
m_globalWorkSize = ((m_globalWorkSize / s_workgroupSize) + 1) * s_workgroupSize;
401403

404+
uint64_t dagSize = ethash_get_datasize(_light->block_number);
405+
uint32_t dagSize128 = (unsigned)(dagSize / ETHASH_MIX_BYTES);
406+
uint32_t lightSize64 = (unsigned)(_lightSize / sizeof(node));
407+
402408
// patch source code
403409
// note: ETHASH_CL_MINER_KERNEL is simply ethash_cl_miner_kernel.cl compiled
404410
// into a byte array by bin2h.cmake. There is no need to load the file by hand in runtime
405411
string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE);
406412
addDefinition(code, "GROUP_SIZE", s_workgroupSize);
407-
addDefinition(code, "DAG_SIZE", (unsigned)(_dagSize / ETHASH_MIX_BYTES));
413+
addDefinition(code, "DAG_SIZE", dagSize128);
414+
addDefinition(code, "LIGHT_SIZE", lightSize64);
408415
addDefinition(code, "ACCESSES", ETHASH_ACCESSES);
409416
addDefinition(code, "MAX_OUTPUTS", c_maxSearchResults);
410417
addDefinition(code, "PLATFORM", platformId);
@@ -430,16 +437,19 @@ bool ethash_cl_miner::init(
430437
// create buffer for dag
431438
try
432439
{
433-
ETHCL_LOG("Creating one big buffer for the DAG");
434-
m_dag = cl::Buffer(m_context, CL_MEM_READ_ONLY, _dagSize);
435-
ETHCL_LOG("Loading single big chunk kernels");
440+
ETHCL_LOG("Creating cache buffer");
441+
m_light = cl::Buffer(m_context, CL_MEM_READ_ONLY, _lightSize);
442+
ETHCL_LOG("Creating DAG buffer");
443+
m_dag = cl::Buffer(m_context, CL_MEM_READ_ONLY, dagSize);
444+
ETHCL_LOG("Loading kernels");
436445
m_searchKernel = cl::Kernel(program, "ethash_search");
437-
ETHCL_LOG("Mapping one big chunk.");
438-
m_queue.enqueueWriteBuffer(m_dag, CL_TRUE, 0, _dagSize, _dag);
446+
m_dagKernel = cl::Kernel(program, "ethash_calculate_dag_item");
447+
ETHCL_LOG("Writing cache buffer");
448+
m_queue.enqueueWriteBuffer(m_light, CL_TRUE, 0, _lightSize, _lightData);
439449
}
440450
catch (cl::Error const& err)
441451
{
442-
ETHCL_LOG("Allocating/mapping single buffer failed with: " << err.what() << "(" << err.err() << "). GPU can't allocate the DAG in a single chunk. Bailing.");
452+
ETHCL_LOG("Allocating/mapping DAG buffer failed with: " << err.what() << "(" << err.err() << "). GPU can't allocate the DAG in a single chunk. Bailing.");
443453
return false;
444454
}
445455
// create buffer for header
@@ -456,6 +466,28 @@ bool ethash_cl_miner::init(
456466
ETHCL_LOG("Creating mining buffer " << i);
457467
m_searchBuffer[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_maxSearchResults + 1) * sizeof(uint32_t));
458468
}
469+
470+
ETHCL_LOG("Generating DAG data");
471+
472+
uint32_t const work = (uint32_t)(dagSize / sizeof(node));
473+
//while (work < blocks * threads) blocks /= 2;
474+
475+
uint32_t fullRuns = work / m_globalWorkSize;
476+
uint32_t const restWork = work % m_globalWorkSize;
477+
if (restWork > 0) fullRuns++;
478+
479+
m_dagKernel.setArg(1, m_light);
480+
m_dagKernel.setArg(2, m_dag);
481+
m_dagKernel.setArg(3, ~0u);
482+
483+
for (uint32_t i = 0; i < fullRuns; i++)
484+
{
485+
m_dagKernel.setArg(0, i * m_globalWorkSize);
486+
m_queue.enqueueNDRangeKernel(m_dagKernel, cl::NullRange, m_globalWorkSize, s_workgroupSize);
487+
m_queue.finish();
488+
printf("%.0f%%\n", 100.0f * (float)i / (float)fullRuns);
489+
}
490+
459491
}
460492
catch (cl::Error const& err)
461493
{

‎libethash-cl/ethash_cl_miner.h

+9-6
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,13 @@ class ethash_cl_miner
5151
uint64_t _currentBlock
5252
);
5353

54-
bool init(
55-
uint8_t const* _dag,
56-
uint64_t _dagSize,
57-
unsigned _platformId = 0,
58-
unsigned _deviceId = 0
59-
);
54+
bool ethash_cl_miner::init(
55+
ethash_light_t _light,
56+
uint8_t const* _lightData,
57+
uint64_t _lightSize,
58+
unsigned _platformId,
59+
unsigned _deviceId
60+
);
6061
void finish();
6162
void search(uint8_t const* _header, uint64_t _target, search_hook& _hook);
6263

@@ -74,7 +75,9 @@ class ethash_cl_miner
7475
cl::Context m_context;
7576
cl::CommandQueue m_queue;
7677
cl::Kernel m_searchKernel;
78+
cl::Kernel m_dagKernel;
7779
cl::Buffer m_dag;
80+
cl::Buffer m_light;
7881
cl::Buffer m_header;
7982
cl::Buffer m_searchBuffer[c_bufferCount];
8083
unsigned m_globalWorkSize;

‎libethash-cl/ethash_cl_miner_kernel.cl

+47-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
#define OPENCL_PLATFORM_UNKNOWN 0
22
#define OPENCL_PLATFORM_NVIDIA 1
3-
#define OPENCL_PLATFORM_AMD 2
3+
#define OPENCL_PLATFORM_AMD 2
44

5+
#define ETHASH_DATASET_PARENTS 256
6+
#define NODE_WORDS (64/4)
57

68
#define THREADS_PER_HASH (128 / 16)
79
#define HASHES_PER_LOOP (GROUP_SIZE / THREADS_PER_HASH)
8-
910
#define FNV_PRIME 0x01000193
1011

1112
__constant uint2 const Keccak_f1600_RC[24] = {
@@ -176,8 +177,6 @@ static void keccak_f1600_round(uint2* a, uint r)
176177

177178
static void keccak_f1600_no_absorb(uint2* a, uint out_size, uint isolate)
178179
{
179-
180-
181180
// Originally I unrolled the first and last rounds to interface
182181
// better with surrounding code, however I haven't done this
183182
// without causing the AMD compiler to blow up the VGPR usage.
@@ -227,6 +226,18 @@ typedef struct
227226
ulong ulongs[32 / sizeof(ulong)];
228227
} hash32_t;
229228

229+
typedef union {
230+
uint words[64 / sizeof(uint)];
231+
uint2 uint2s[64 / sizeof(uint2)];
232+
uint4 uint4s[64 / sizeof(uint4)];
233+
} hash64_t;
234+
235+
typedef union {
236+
uint words[200 / sizeof(uint)];
237+
uint2 uint2s[200 / sizeof(uint2)];
238+
uint4 uint4s[200 / sizeof(uint4)];
239+
} hash200_t;
240+
230241
typedef struct
231242
{
232243
uint4 uint4s[128 / sizeof(uint4)];
@@ -334,3 +345,35 @@ __kernel void ethash_search(
334345
g_output[slot] = gid;
335346
}
336347
}
348+
349+
static void SHA3_512(uint2* s, uint isolate)
350+
{
351+
for (uint i = 8; i != 25; ++i)
352+
{
353+
s[i] = (uint2){ 0, 0 };
354+
}
355+
s[8].x = 0x00000001;
356+
s[8].y = 0x80000000;
357+
keccak_f1600_no_absorb(s, 8, isolate);
358+
}
359+
360+
__kernel void ethash_calculate_dag_item(uint start, __global hash64_t const* g_light, __global hash64_t * g_dag, uint isolate)
361+
{
362+
uint const node_index = start + get_global_id(0);
363+
if (node_index > DAG_SIZE * 2) return;
364+
365+
hash200_t dag_node;
366+
copy(dag_node.uint4s, g_light[node_index % LIGHT_SIZE].uint4s, 4);
367+
dag_node.words[0] ^= node_index;
368+
SHA3_512(dag_node.uint2s, isolate);
369+
370+
for (uint i = 0; i != ETHASH_DATASET_PARENTS; ++i) {
371+
uint parent_index = fnv(node_index ^ i, dag_node.words[i % NODE_WORDS]) % LIGHT_SIZE;
372+
373+
for (uint w = 0; w != 4; ++w) {
374+
dag_node.uint4s[w] = fnv4(dag_node.uint4s[w], g_light[parent_index].uint4s[w]);
375+
}
376+
}
377+
SHA3_512(dag_node.uint2s, isolate);
378+
copy(g_dag[node_index].uint4s, dag_node.uint4s, 4);
379+
}

‎libethash-cuda/dagger_shared.cuh

-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
#include "ethash_cuda_miner_kernel_globals.h"
22
#include "ethash_cuda_miner_kernel.h"
3-
#include "keccak_u64.cuh"
4-
#include "fnv.cuh"
5-
6-
#define copy(dst, src, count) for (int i = 0; i != count; ++i) { (dst)[i] = (src)[i]; }
73

84
typedef union {
95
uint4 uint4s[4];

‎libethash-cuda/dagger_shuffled.cuh

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#include "ethash_cuda_miner_kernel_globals.h"
22
#include "ethash_cuda_miner_kernel.h"
3-
#include "keccak.cuh"
4-
#include "fnv.cuh"
53

64
#define HASHES_PER_LOOP (GROUP_SIZE / THREADS_PER_HASH)
75

‎libethash-cuda/ethash_cuda_miner.cpp

+18-5
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ void ethash_cuda_miner::finish()
199199
CUDA_SAFE_CALL(cudaDeviceReset());
200200
}
201201

202-
bool ethash_cuda_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned _deviceId)
202+
bool ethash_cuda_miner::init(ethash_light_t _light, uint8_t const* _lightData, uint64_t _lightSize, unsigned _deviceId)
203203
{
204204
try
205205
{
@@ -224,25 +224,38 @@ bool ethash_cuda_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned _d
224224
m_search_buf = new volatile uint32_t *[s_numStreams];
225225
m_streams = new cudaStream_t[s_numStreams];
226226

227-
uint32_t dagSize128 = (unsigned)(_dagSize / ETHASH_MIX_BYTES);
227+
uint64_t dagSize = ethash_get_datasize(_light->block_number);
228+
uint32_t dagSize128 = (unsigned)(dagSize / ETHASH_MIX_BYTES);
229+
uint32_t lightSize64 = (unsigned)(_lightSize / sizeof(node));
230+
231+
// create buffer for cache
232+
hash64_t * light;
233+
CUDA_SAFE_CALL(cudaMalloc(reinterpret_cast<void**>(&light), _lightSize));
234+
// copy dag to CPU.
235+
CUDA_SAFE_CALL(cudaMemcpy(reinterpret_cast<void*>(light), _lightData, _lightSize, cudaMemcpyHostToDevice));
228236

229237
// create buffer for dag
230238
hash128_t * dag;
231-
CUDA_SAFE_CALL(cudaMalloc(reinterpret_cast<void**>(&dag), _dagSize));
239+
CUDA_SAFE_CALL(cudaMalloc(reinterpret_cast<void**>(&dag), dagSize));
232240
// copy dag to CPU.
233-
CUDA_SAFE_CALL(cudaMemcpy(reinterpret_cast<void*>(dag), _dag, _dagSize, cudaMemcpyHostToDevice));
241+
//CUDA_SAFE_CALL(cudaMemcpy(reinterpret_cast<void*>(dag), _dag, _dagSize, cudaMemcpyHostToDevice));
234242

243+
235244
// create mining buffers
236245
for (unsigned i = 0; i != s_numStreams; ++i)
237246
{
238247
CUDA_SAFE_CALL(cudaMallocHost(&m_search_buf[i], SEARCH_RESULT_BUFFER_SIZE * sizeof(uint32_t)));
239248
CUDA_SAFE_CALL(cudaStreamCreate(&m_streams[i]));
240249
}
241-
set_constants(dag, dagSize128);
250+
set_constants(dag, dagSize128, light, lightSize64);
242251
memset(&m_current_header, 0, sizeof(hash32_t));
243252
m_current_target = 0;
244253
m_current_nonce = 0;
245254
m_current_index = 0;
255+
256+
cout << "Generating DAG..." << endl;
257+
ethash_generate_dag(dagSize, s_gridSize, s_blockSize, m_streams[0]);
258+
246259
return true;
247260
}
248261
catch (runtime_error)

0 commit comments

Comments
 (0)
This repository has been archived.