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

CLMiner: Optimization for frequent work updates #217

Merged
merged 4 commits into from
Aug 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions ethminer/MinerAux.h
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ class MinerCLI
f.start("opencl", false);
else if (_m == MinerType::CUDA)
f.start("cuda", false);
f.setWork(genesis);
f.setWork(WorkPackage{genesis});

map<uint64_t, WorkingProgress> results;
uint64_t mean = 0;
Expand Down Expand Up @@ -682,11 +682,11 @@ class MinerCLI
f.start("opencl", false);
else if (_m == MinerType::CUDA)
f.start("cuda", false);
f.setWork(genesis);

int time = 0;

WorkPackage current = WorkPackage(genesis);
f.setWork(current);
while (true) {
bool completed = false;
Solution solution;
Expand Down
114 changes: 58 additions & 56 deletions libethash-cl/CLMiner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,12 @@ int CLMiner::s_devices[16] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -

CLMiner::CLMiner(FarmFace& _farm, unsigned _index):
Miner("cl-", _farm, _index)
{}
{
// FIXME: Move m_current to local var in the work loop.
// Init with non-zero hashes to distinct from the seed of epoch 0 and empty work.
m_current.header = h256{1u};
m_current.seed = h256{1u};
}

CLMiner::~CLMiner()
{
Expand All @@ -118,13 +123,7 @@ void CLMiner::report(uint64_t _nonce)
}

void CLMiner::kickOff()
{
{
UniqueGuard l(x_hook);
m_hook_aborted = m_hook_abort = false;
}
startWorking();
}
{}

namespace
{
Expand All @@ -140,49 +139,65 @@ void CLMiner::workLoop()
// Memory for zero-ing buffers. Cannot be static because crashes on macOS.
uint32_t const c_zero = 0;

uint64_t startNonce = 0;

// take local copy of work since it may end up being overwritten by kickOff/pause.
try {
const WorkPackage w = work();

if (!w)
while (true)
{
cllog << "No work. Pause.";
return;
}
const WorkPackage w = work();

cllog << "Set work. Header" << w.header << "target" << w.boundary.hex();
if (m_seed != w.seed)
{
if (s_dagLoadMode == DAG_LOAD_MODE_SEQUENTIAL)
if (m_current.header != w.header)
{
while (s_dagLoadIndex < index)
this_thread::sleep_for(chrono::seconds(1));
++s_dagLoadIndex;
}

cllog << "Initialising miner with seed" << w.seed;
init(w.seed);
m_seed = w.seed;
}

uint64_t startNonce = 0;
if (w.exSizeBits >= 0)
startNonce = w.startNonce | ((uint64_t)index << (64 - 4 - w.exSizeBits)); // this can support up to 16 devices
else
startNonce = randomNonce();
// New work received. Update GPU data.
auto localSwitchStart = std::chrono::high_resolution_clock::now();

if (!w)
{
cllog << "No work. Pause for 3 s.";
std::this_thread::sleep_for(std::chrono::seconds(3));
continue;
}

cllog << "New work: header" << w.header << "target" << w.boundary.hex();

if (m_current.seed != w.seed)
{
if (s_dagLoadMode == DAG_LOAD_MODE_SEQUENTIAL)
{
while (s_dagLoadIndex < index)
this_thread::sleep_for(chrono::seconds(1));
++s_dagLoadIndex;
}

cllog << "New seed" << w.seed;
init(w.seed);
}

// Upper 64 bits of the boundary.
const uint64_t target = (uint64_t)(u64)((u256)w.boundary >> 192);
assert(target > 0);

// Update header constant buffer.
m_queue.enqueueWriteBuffer(m_header, CL_FALSE, 0, w.header.size, w.header.data());
m_queue.enqueueWriteBuffer(m_searchBuffer, CL_FALSE, 0, sizeof(c_zero), &c_zero);

// Upper 64 bits of the boundary.
const uint64_t target = (uint64_t)(u64)((u256)w.boundary >> 192);
m_searchKernel.setArg(0, m_searchBuffer); // Supply output buffer to kernel.
m_searchKernel.setArg(4, target);

// Update header constant buffer.
m_queue.enqueueWriteBuffer(m_header, CL_FALSE, 0, w.header.size, w.header.data());
m_queue.enqueueWriteBuffer(m_searchBuffer, CL_FALSE, 0, sizeof(c_zero), &c_zero);
// FIXME: This logic should be move out of here.
if (w.exSizeBits >= 0)
startNonce = w.startNonce | ((uint64_t)index << (64 - 4 - w.exSizeBits)); // This can support up to 16 devices.
else
startNonce = randomNonce();

m_searchKernel.setArg(0, m_searchBuffer); // Supply output buffer to kernel.
m_searchKernel.setArg(4, target);
m_current = w;
auto switchEnd = std::chrono::high_resolution_clock::now();
auto globalSwitchTime = std::chrono::duration_cast<std::chrono::milliseconds>(switchEnd - workSwitchStart).count();
auto localSwitchTime = std::chrono::duration_cast<std::chrono::microseconds>(switchEnd - localSwitchStart).count();
cllog << "Switch time" << globalSwitchTime << "ms /" << localSwitchTime << "us";
}

while (true)
{
// Read results.
// TODO: could use pinned host pointer instead.
uint32_t results[c_maxSearchResults + 1];
Expand Down Expand Up @@ -227,20 +242,7 @@ void CLMiner::workLoop()
}

void CLMiner::pause()
{
{
UniqueGuard l(x_hook);
if (m_hook_aborted)
return;

m_hook_abort = true;
}
// m_abort is true so now searched()/found() will return true to abort the search.
// we hang around on this thread waiting for them to point out that they have aborted since
// otherwise we may end up deleting this object prior to searched()/found() being called.
m_hook_aborted.wait(true);
stopWorking();
}
{}

unsigned CLMiner::getNumDevices()
{
Expand Down
4 changes: 1 addition & 3 deletions libethash-cl/CLMiner.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,7 @@ class CLMiner: public Miner
unsigned m_globalWorkSize = 0;
unsigned m_workgroupSize = 0;

/// The seed the miner was initialized with.
/// Init with non-zero hash to distinct from the seed of epoch 0.
h256 m_seed = h256{1u};
WorkPackage m_current;

static unsigned s_platformId;
static unsigned s_numInstances;
Expand Down
4 changes: 2 additions & 2 deletions libethcore/EthashAux.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ class EthashAux
struct WorkPackage
{
WorkPackage() = default;
WorkPackage(BlockHeader const& _bh) :
explicit WorkPackage(BlockHeader const& _bh) :
boundary(_bh.boundary()),
header(_bh.hashWithout()),
seed(EthashAux::seedHash(static_cast<unsigned>(_bh.number())))
{ }
void reset() { header = h256(); }
operator bool() const { return header != h256(); }
explicit operator bool() const { return header != h256(); }

h256 boundary;
h256 header; ///< When h256() means "pause until notified a new work package is available".
Expand Down
4 changes: 3 additions & 1 deletion libethcore/Miner.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ class Miner: public Worker
{
Guard l(x_work);
m_work = _work;
workSwitchStart = std::chrono::high_resolution_clock::now();
}
assert(!!_work);
if (!!_work)
Expand Down Expand Up @@ -183,7 +184,7 @@ class Miner: public Worker
*/
virtual void pause() = 0;

WorkPackage const& work() const { Guard l(x_work); return m_work; }
WorkPackage work() const { Guard l(x_work); return m_work; }

void accumulateHashes(unsigned _n) { m_hashCount += _n; }

Expand All @@ -194,6 +195,7 @@ class Miner: public Worker

const size_t index = 0;
FarmFace& farm;
std::chrono::high_resolution_clock::time_point workSwitchStart;

private:
uint64_t m_hashCount = 0;
Expand Down
2 changes: 1 addition & 1 deletion libstratum/EthStratumClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class EthStratumClient
bool isRunning() { return m_running; }
bool isConnected() { return m_connected && m_authorized; }
h256 currentHeaderHash() { return m_current.header; }
bool current() { return m_current; }
bool current() { return static_cast<bool>(m_current); }
bool submit(Solution solution);
void reconnect();
private:
Expand Down
2 changes: 1 addition & 1 deletion libstratum/EthStratumClientV2.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class EthStratumClientV2 : public Worker
bool isRunning() { return m_running; }
bool isConnected() { return m_connected && m_authorized; }
h256 currentHeaderHash() { return m_current.header; }
bool current() { return m_current; }
bool current() { return static_cast<bool>(m_current); }
unsigned waitState() { return m_waitState; }
bool submit(Solution solution);
void reconnect();
Expand Down