Permalink
Browse files

Small miner improvements to make the code more readable

  • Loading branch information...
Martijn Otto
Martijn Otto committed Nov 27, 2018
1 parent 58ce16d commit 44288132cc17355fc1a377841e05cdabe43b98c3
Showing with 181 additions and 61 deletions.
  1. +130 −0 src/cryptonote_basic/atomic_lock.h
  2. +39 −53 src/cryptonote_basic/miner.cpp
  3. +12 −8 src/cryptonote_basic/miner.h
@@ -0,0 +1,130 @@
// Copyright (c) 2014-2018, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <type_traits>
#include <atomic>
namespace cryptonote
{
template <class T>
class atomic_lock
{
public:
// the type of the underlying storage for
// the enum that we are switching between
using storage_type = typename std::underlying_type<T>::type;
atomic_lock() = default;
atomic_lock(T value) : m_value{ static_cast<storage_type>(value) } {}
/**
* Check whether we currently hold a specific lock
* @param value The value to compare to
* @return Do we currently hold the given value
*/
bool is(T value) const noexcept {
return m_value.load() == static_cast<storage_type>(value);
}
/**
* Try to advance to a new value, fails if we were not at
* the given starting point to begin with
* @param from The point to advance from
* @param to The point to advance to
* @return Did we successfully advance
*/
bool try_advance(T from, T to) noexcept
{
// check if the original value is correct
if (m_value.fetch_add(difference(from, to)) != static_cast<storage_type>(from)) {
// we did not start at from so undo the add
m_value.fetch_sub(difference(from, to));
return false;
}
return true;
}
/**
* Unconditionally advance from a given point
* @param from The point to advance from
* @param to The point to advance to
*/
void advance(T from, T to) noexcept
{
// advance the value
m_value.fetch_add(difference(from, to));
}
/**
* Try to go back to an old value, fails if we were not at
* the given starting point to begin with
* @param from The point to recede from
* @param to The point to recede to
* @return Did we successfully recede
*/
bool try_recede(T from, T to) noexcept
{
// check if the original value is correct
if (m_value.fetch_sub(difference(from, to)) != static_cast<storage_type>(from)) {
// we did not start at from so undo the add
m_value.fetch_add(difference(from, to));
return false;
}
return true;
}
/**
* Unconditionally recede from a given point
* @param from The point to recede from
* @apram to the point to recede to
*/
void recede(T from, T to) noexcept
{
// recede the value
m_value.fetch_add(difference(from, to));
}
private:
std::atomic<storage_type> m_value{};
/**
* Calculate the difference between two options
* @param from The option to calculate from
* @param to The option to calculate to
* @return The difference between the two options
*/
static storage_type difference(T from, T to) noexcept
{
// cast them to the underlying storage type for calculation
return static_cast<storage_type>(to) - static_cast<storage_type>(from);
}
};
}
@@ -95,11 +95,11 @@ namespace cryptonote
}
miner::miner(i_miner_handler* phandler):m_stop(1),
miner::miner(i_miner_handler* phandler):
m_status(status::stopped),
m_template(boost::value_initialized<block>()),
m_template_no(0),
m_diffic(0),
m_thread_index(0),
m_phandler(phandler),
m_height(0),
m_pausers_count(0),
@@ -280,7 +280,7 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------------
bool miner::is_mining() const
{
return !m_stop;
return m_status.is(status::running);
}
//-----------------------------------------------------------------------------------------------------
const account_public_address& miner::get_mining_address() const
@@ -294,32 +294,26 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------------
bool miner::start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs, bool do_background, bool ignore_battery)
{
m_mine_address = adr;
m_threads_total = static_cast<uint32_t>(threads_count);
m_starter_nonce = crypto::rand<uint32_t>();
CRITICAL_REGION_LOCAL(m_threads_lock);
if(is_mining())
if (!m_status.try_advance(status::stopped, status::running))
{
LOG_ERROR("Starting miner but it's already started");
return false;
}
if(!m_threads.empty())
{
LOG_ERROR("Unable to start miner because there are active mining threads");
return false;
}
m_mine_address = adr;
m_threads_total = static_cast<uint32_t>(threads_count);
m_starter_nonce = crypto::rand<uint32_t>();
request_block_template();//lets update block template
boost::interprocess::ipcdetail::atomic_write32(&m_stop, 0);
boost::interprocess::ipcdetail::atomic_write32(&m_thread_index, 0);
set_is_background_mining_enabled(do_background);
set_ignore_battery(ignore_battery);
m_threads.reserve(threads_count);
for(size_t i = 0; i != threads_count; i++)
while (m_threads.size() < threads_count)
{
m_threads.push_back(boost::thread(attrs, boost::bind(&miner::worker_thread, this)));
m_threads.emplace_back(attrs, boost::bind(&miner::worker_thread, this, m_threads.size()));
}
LOG_PRINT_L0("Mining has started with " << threads_count << " threads, good luck!" );
@@ -348,24 +342,16 @@ namespace cryptonote
}
}
//-----------------------------------------------------------------------------------------------------
void miner::send_stop_signal()
{
boost::interprocess::ipcdetail::atomic_write32(&m_stop, 1);
}
//-----------------------------------------------------------------------------------------------------
bool miner::stop()
{
MTRACE("Miner has received stop signal");
if (!is_mining())
if (!m_status.try_advance(status::running, status::stopping))
{
MDEBUG("Not mining - nothing to stop" );
MDEBUG("Not mining - nothing to stop");
return true;
}
send_stop_signal();
CRITICAL_REGION_LOCAL(m_threads_lock);
// In case background mining was active and the miner threads are waiting
// on the background miner to signal start.
m_is_background_mining_started_cond.notify_all();
@@ -380,6 +366,10 @@ namespace cryptonote
MINFO("Mining has been stopped, " << m_threads.size() << " finished" );
m_threads.clear();
// we are no longer running
m_status.recede(status::stopping, status::stopped);
return true;
}
//-----------------------------------------------------------------------------------------------------
@@ -413,39 +403,38 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------------
void miner::pause()
{
CRITICAL_REGION_LOCAL(m_miners_count_lock);
MDEBUG("miner::pause: " << m_pausers_count << " -> " << (m_pausers_count + 1));
++m_pausers_count;
if(m_pausers_count == 1 && is_mining())
auto pausers_count = m_pausers_count.fetch_add(1);
MDEBUG("miner::pause: " << pausers_count << " -> " << (pausers_count + 1));
if(pausers_count == 0 && is_mining())
MDEBUG("MINING PAUSED");
}
//-----------------------------------------------------------------------------------------------------
void miner::resume()
{
CRITICAL_REGION_LOCAL(m_miners_count_lock);
MDEBUG("miner::resume: " << m_pausers_count << " -> " << (m_pausers_count - 1));
--m_pausers_count;
if(m_pausers_count < 0)
auto pausers_count = m_pausers_count.fetch_sub(1);
MDEBUG("miner::resume: " << pausers_count << " -> " << (pausers_count - 1));
if(pausers_count <= 0)
{
m_pausers_count = 0;
m_pausers_count.fetch_add(1);
MERROR("Unexpected miner::resume() called");
}
if(!m_pausers_count && is_mining())
else if(pausers_count == 1 && is_mining())
{
MDEBUG("MINING RESUMED");
}
}
//-----------------------------------------------------------------------------------------------------
bool miner::worker_thread()
bool miner::worker_thread(uint32_t thread_index)
{
uint32_t th_local_index = boost::interprocess::ipcdetail::atomic_inc32(&m_thread_index);
MLOG_SET_THREAD_NAME(std::string("[miner ") + std::to_string(th_local_index) + "]");
MGINFO("Miner thread was started ["<< th_local_index << "]");
uint32_t nonce = m_starter_nonce + th_local_index;
MLOG_SET_THREAD_NAME(std::string("[miner ") + std::to_string(thread_index) + "]");
MGINFO("Miner thread was started ["<< thread_index << "]");
uint32_t nonce = m_starter_nonce + thread_index;
uint64_t height = 0;
difficulty_type local_diff = 0;
uint32_t local_template_ver = 0;
block b;
slow_hash_allocate_state();
while(!m_stop)
while(m_status.is(status::running))
{
if(m_pausers_count)//anti split workaround
{
@@ -455,15 +444,14 @@ namespace cryptonote
else if( m_is_background_mining_enabled )
{
misc_utils::sleep_no_w(m_miner_extra_sleep);
while( !m_is_background_mining_started )
while( !m_is_background_mining_started && m_status.is(status::running) )
{
MGINFO("background mining is enabled, but not started, waiting until start triggers");
boost::unique_lock<boost::mutex> started_lock( m_is_background_mining_started_mutex );
m_is_background_mining_started_cond.wait( started_lock );
if( m_stop ) break;
}
if( m_stop ) continue;
if( !m_status.is(status::running) ) continue;
}
if(local_template_ver != m_template_no)
@@ -474,7 +462,7 @@ namespace cryptonote
height = m_height;
CRITICAL_REGION_END();
local_template_ver = m_template_no;
nonce = m_starter_nonce + th_local_index;
nonce = m_starter_nonce + thread_index;
}
if(!local_template_ver)//no any set_block_template call
@@ -507,7 +495,7 @@ namespace cryptonote
++m_hashes;
}
slow_hash_free_state();
MGINFO("Miner thread stopped ["<< th_local_index << "]");
MGINFO("Miner thread stopped ["<< thread_index << "]");
return true;
}
//-----------------------------------------------------------------------------------------------------
@@ -578,7 +566,7 @@ namespace cryptonote
return true;
}
//-----------------------------------------------------------------------------------------------------
bool miner::background_worker_thread()
void miner::background_worker_thread()
{
uint64_t prev_total_time, current_total_time;
uint64_t prev_idle_time, current_idle_time;
@@ -588,10 +576,10 @@ namespace cryptonote
if(!get_system_times(prev_total_time, prev_idle_time))
{
LOG_ERROR("get_system_times call failed, background mining will NOT work!");
return false;
return;
}
while(!m_stop)
while(m_status.is(status::running))
{
try
@@ -729,8 +717,6 @@ namespace cryptonote
prev_idle_time = current_idle_time;
}
}
return true;
}
//-----------------------------------------------------------------------------------------------------
bool miner::get_system_times(uint64_t& total_time, uint64_t& idle_time)
Oops, something went wrong.

0 comments on commit 4428813

Please sign in to comment.