Run miner threads at priority `SCHED_IDLE` (see `sched(7)`)

This way miners can fully utilize all spare CPU power without affecting
    performance of the rest of the system.
This commit is contained in:
Petr 2023-07-01 21:34:08 +02:00
parent 0a1eaf26f9
commit 2cc49b3877
3 changed files with 123 additions and 4 deletions

View File

@ -83,6 +83,7 @@ using namespace epee;
#include "miner.h"
#include "crypto/hash.h"
#include "thread.h"
extern "C" void slow_hash_allocate_state();
@ -95,6 +96,7 @@ namespace cryptonote
const command_line::arg_descriptor<std::string> arg_extra_messages = {"extra-messages-file", "Specify file for extra messages to include into coinbase transactions", "", true};
const command_line::arg_descriptor<std::string> arg_start_mining = {"start-mining", "Specify wallet address to mining for", "", true};
const command_line::arg_descriptor<uint32_t> arg_mining_threads = {"mining-threads", "Specify mining threads count", 0, true};
const command_line::arg_descriptor<bool> arg_mining_threads_idle = {"mining-threads-idle", "Run mining threads at the idle/lowest possible system priority. This is an alternative to the background mining feature.", false, true};
const command_line::arg_descriptor<bool> arg_bg_mining_enable = {"bg-mining-enable", "enable background mining", true, true};
const command_line::arg_descriptor<bool> arg_bg_mining_ignore_battery = {"bg-mining-ignore-battery", "if true, assumes plugged in when unable to query system power status", false, true};
const command_line::arg_descriptor<uint64_t> arg_bg_mining_min_idle_interval_seconds = {"bg-mining-min-idle-interval", "Specify min lookback interval in seconds for determining idle state", miner::BACKGROUND_MINING_DEFAULT_MIN_IDLE_INTERVAL_IN_SECONDS, true};
@ -120,6 +122,7 @@ namespace cryptonote
m_total_hashes(0),
m_do_print_hashrate(false),
m_do_mining(false),
m_threads_idle(false),
m_current_hash_rate(0),
m_is_background_mining_enabled(false),
m_min_idle_seconds(BACKGROUND_MINING_DEFAULT_MIN_IDLE_INTERVAL_IN_SECONDS),
@ -287,6 +290,7 @@ namespace cryptonote
command_line::add_arg(desc, arg_extra_messages);
command_line::add_arg(desc, arg_start_mining);
command_line::add_arg(desc, arg_mining_threads);
command_line::add_arg(desc, arg_mining_threads_idle);
command_line::add_arg(desc, arg_bg_mining_enable);
command_line::add_arg(desc, arg_bg_mining_ignore_battery);
command_line::add_arg(desc, arg_bg_mining_min_idle_interval_seconds);
@ -350,6 +354,11 @@ namespace cryptonote
if(command_line::has_arg(vm, arg_bg_mining_miner_target_percentage))
set_mining_target( command_line::get_arg(vm, arg_bg_mining_miner_target_percentage) );
if(command_line::has_arg(vm, arg_mining_threads_idle))
{
m_threads_idle = command_line::get_arg(vm, arg_mining_threads_idle);
}
return true;
}
//-----------------------------------------------------------------------------------------------------
@ -367,7 +376,7 @@ namespace cryptonote
return m_threads_total;
}
//-----------------------------------------------------------------------------------------------------
bool miner::start(const account_public_address& adr, size_t threads_count, bool do_background, bool ignore_battery)
bool miner::start(const account_public_address& adr, size_t threads_count, bool threads_idle, bool do_background, bool ignore_battery)
{
m_block_reward = 0;
m_mine_address = adr;
@ -401,7 +410,13 @@ namespace cryptonote
for(size_t i = 0; i != m_threads_total; i++)
{
m_threads.push_back(boost::thread(m_attrs, boost::bind(&miner::worker_thread, this)));
if (threads_idle) {
m_threads.push_back(create_background_thread(m_attrs, boost::bind(
&miner::worker_thread, this)));
} else {
m_threads.push_back(boost::thread(m_attrs, boost::bind(
&miner::worker_thread, this)));
}
}
if (threads_count == 0)
@ -411,6 +426,9 @@ namespace cryptonote
if( get_is_background_mining_enabled() )
{
if (threads_idle) {
MERROR("Feature --mining-threads-idle is an alternative to background mining and doesn't make sense to be used together.");
}
m_background_mining_thread = boost::thread(m_attrs, boost::bind(&miner::background_worker_thread, this));
LOG_PRINT_L0("Background mining controller thread started" );
}
@ -493,7 +511,7 @@ namespace cryptonote
{
if(m_do_mining)
{
start(m_mine_address, m_threads_total, get_is_background_mining_enabled(), get_ignore_battery());
start(m_mine_address, m_threads_total, m_threads_idle, get_is_background_mining_enabled(), get_ignore_battery());
}
}
//-----------------------------------------------------------------------------------------------------

View File

@ -66,7 +66,7 @@ namespace cryptonote
static void init_options(boost::program_options::options_description& desc);
bool set_block_template(const block& bl, const difficulty_type& diffic, uint64_t height, uint64_t block_reward);
bool on_block_chain_update();
bool start(const account_public_address& adr, size_t threads_count, bool do_background = false, bool ignore_battery = false);
bool start(const account_public_address& adr, size_t threads_count, bool threads_idle, bool do_background = false, bool ignore_battery = false);
uint64_t get_speed() const;
uint32_t get_threads_count() const;
void send_stop_signal();
@ -150,6 +150,7 @@ namespace cryptonote
std::list<uint64_t> m_last_hash_rates;
bool m_do_print_hashrate;
bool m_do_mining;
bool m_threads_idle;
std::vector<std::pair<uint64_t, uint64_t>> m_threads_autodetect;
boost::thread::attributes m_attrs;

View File

@ -0,0 +1,100 @@
// Copyright (c) 2014-2022, 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.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
#include <utility>
#include <boost/thread/thread.hpp>
#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#include <sched.h>
#endif // _WIN32
namespace cryptonote
{
// Creates and returns a thread running at an idle priority (if possible).
template<typename Callable>
boost::thread create_background_thread(boost::thread::attributes& attrs, Callable func);
#ifdef _WIN32
template<typename Callable>
boost::thread create_background_thread(boost::thread::attributes& attrs, Callable func) {
return boost::thread(attrs, [func = std::move(func)]() mutable {
auto handle = GetCurrentThread();
if (!SetThreadPriority(handle, THREAD_MODE_BACKGROUND_BEGIN)) {
if (!SetThreadPriority(handle, THREAD_PRIORITY_LOWEST)) {
MWARNING("Can't set a background thread priority: "
<< std::error_code(GetLastError(), std::system_category()));
}
}
std::move(func)();
});
}
#else
template<typename Callable>
boost::thread create_background_thread(boost::thread::attributes& attrs, Callable func) {
auto thread = boost::thread(attrs, std::move(func));
auto handle = thread.native_handle();
int policy;
struct sched_param param;
int error;
if ((error = pthread_getschedparam(handle, &policy, &param)) != 0) {
MWARNING("Can't set a background thread priority: pthread_getschedparam "
"failed: " << std::strerror(error));
return thread;
}
#ifdef SCHED_IDLE
policy = SCHED_IDLE;
// In particular MacOS doesn't support `SCHED_IDLE`. In the future we might
// consider using https://developer.apple.com/documentation/dispatch
// instead.
#else
#warning SCHED_IDLE policy not available, falling back to minimum priority
param.sched_priority = sched_get_priority_min(policy);
#endif
if ((error = pthread_setschedparam(handle, policy, &param)) != 0) {
MWARNING("Can't set a background thread priority: pthread_setschedparam "
"to SCHED_IDLE failed: " << std::strerror(error));
}
return thread;
}
#endif
} // namespace cryptonote