From 345ed4823c686edda33e224316c5ade8a5b838ae Mon Sep 17 00:00:00 2001 From: Dion Ahmetaj Date: Sat, 14 Jan 2017 22:20:54 -0500 Subject: [PATCH 1/9] Background/smart mining. If a users' computer is plugged into a power source, and CPU has been idle for some time, then begin mining to some threshold (don't destroy the users' CPU). This patch only supports windows and linux (I've only tested on Win64 and Ubuntu). The variables currently default to pretty conservative values (i.e. 20% CPU mining threshold). --- src/cryptonote_basic/miner.cpp | 400 +++++++++++++++++++++++- src/cryptonote_basic/miner.h | 53 +++- src/daemon/command_parser_executor.cpp | 13 +- src/daemon/command_server.cpp | 2 +- src/daemon/rpc_command_executor.cpp | 3 +- src/daemon/rpc_command_executor.h | 2 +- src/rpc/core_rpc_server.cpp | 2 +- src/rpc/core_rpc_server_commands_defs.h | 2 + 8 files changed, 459 insertions(+), 18 deletions(-) diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 88c631f80..2b70df643 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -60,6 +60,10 @@ namespace cryptonote const command_line::arg_descriptor arg_extra_messages = {"extra-messages-file", "Specify file for extra messages to include into coinbase transactions", "", true}; const command_line::arg_descriptor arg_start_mining = {"start-mining", "Specify wallet address to mining for", "", true}; const command_line::arg_descriptor arg_mining_threads = {"mining-threads", "Specify mining threads count", 0, true}; + const command_line::arg_descriptor arg_bg_mining_enable = {"bg-mining-enable", "enable/disable background mining", true, true}; + const command_line::arg_descriptor 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}; + const command_line::arg_descriptor arg_bg_mining_idle_threshold_percentage = {"bg-mining-idle-threshold", "Specify minimum avg idle percentage over lookback interval", miner::BACKGROUND_MINING_DEFAULT_IDLE_THRESHOLD_PERCENTAGE, true}; + const command_line::arg_descriptor arg_bg_mining_miner_target_percentage = {"bg-mining-miner-target", "Specificy maximum percentage cpu use by miner(s)", miner::BACKGROUND_MINING_DEFAULT_MINING_TARGET_PERCENTAGE, true}; } @@ -77,7 +81,12 @@ namespace cryptonote m_hashes(0), m_do_print_hashrate(false), m_do_mining(false), - m_current_hash_rate(0) + m_current_hash_rate(0), + m_is_background_mining_enabled(false), + m_min_idle_seconds(BACKGROUND_MINING_DEFAULT_MIN_IDLE_INTERVAL_IN_SECONDS), + m_idle_threshold(BACKGROUND_MINING_DEFAULT_IDLE_THRESHOLD_PERCENTAGE), + m_mining_target(BACKGROUND_MINING_DEFAULT_MINING_TARGET_PERCENTAGE), + m_miner_extra_sleep(BACKGROUND_MINING_DEFAULT_MINER_EXTRA_SLEEP_MILLIS) { } @@ -137,7 +146,7 @@ namespace cryptonote merge_hr(); return true; }); - + return true; } //----------------------------------------------------------------------------------------------------- @@ -171,6 +180,10 @@ 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_bg_mining_enable); + command_line::add_arg(desc, arg_bg_mining_min_idle_interval_seconds); + command_line::add_arg(desc, arg_bg_mining_idle_threshold_percentage); + command_line::add_arg(desc, arg_bg_mining_miner_target_percentage); } //----------------------------------------------------------------------------------------------------- bool miner::init(const boost::program_options::variables_map& vm, bool testnet) @@ -213,6 +226,17 @@ namespace cryptonote } } + // Background mining parameters + // Let init set all parameters even if background mining is not enabled, they can start later with params set + if(command_line::has_arg(vm, arg_bg_mining_enable)) + set_is_background_mining_enabled( command_line::get_arg(vm, arg_bg_mining_enable) ); + if(command_line::has_arg(vm, arg_bg_mining_min_idle_interval_seconds)) + set_min_idle_seconds( command_line::get_arg(vm, arg_bg_mining_min_idle_interval_seconds) ); + if(command_line::has_arg(vm, arg_bg_mining_idle_threshold_percentage)) + set_idle_threshold( command_line::get_arg(vm, arg_bg_mining_idle_threshold_percentage) ); + 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) ); + return true; } //----------------------------------------------------------------------------------------------------- @@ -230,7 +254,7 @@ namespace cryptonote return m_threads_total; } //----------------------------------------------------------------------------------------------------- - bool miner::start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs) + bool miner::start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs, bool do_background) { m_mine_address = adr; m_threads_total = static_cast(threads_count); @@ -260,6 +284,14 @@ namespace cryptonote } LOG_PRINT_L0("Mining has started with " << threads_count << " threads, good luck!" ); + + set_is_background_mining_enabled(do_background); + if( get_is_background_mining_enabled() ) + { + m_background_mining_thread = boost::thread(attrs, boost::bind(&miner::background_worker_thread, this)); + LOG_PRINT_L0("Background mining controller thread started" ); + } + return true; } //----------------------------------------------------------------------------------------------------- @@ -291,10 +323,19 @@ namespace cryptonote 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(); + for(boost::thread& th: m_threads) th.join(); - MINFO("Mining has been stopped, " << m_threads.size() << " finished" ); + // The background mining thread could be sleeping for a long time, so we + // interrupt it just in case + m_background_mining_thread.interrupt(); + m_background_mining_thread.join(); + + LOG_PRINT_L0("Mining has been stopped, " << m_threads.size() << " finished" ); m_threads.clear(); return true; } @@ -321,7 +362,7 @@ namespace cryptonote boost::thread::attributes attrs; attrs.set_stack_size(THREAD_STACK_SIZE); - start(m_mine_address, m_threads_total, attrs); + start(m_mine_address, m_threads_total, attrs, get_is_background_mining_enabled()); } } //----------------------------------------------------------------------------------------------------- @@ -364,6 +405,19 @@ namespace cryptonote misc_utils::sleep_no_w(100); continue; } + else if( m_is_background_mining_enabled ) + { + misc_utils::sleep_no_w(m_miner_extra_sleep); + while( !m_is_background_mining_started ) + { + MGINFO("background mining is enabled, but not started, waiting until start triggers"); + boost::unique_lock 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(local_template_ver != m_template_no) { @@ -410,5 +464,339 @@ namespace cryptonote return true; } //----------------------------------------------------------------------------------------------------- -} + bool miner::get_is_background_mining_enabled() const + { + return m_is_background_mining_enabled; + } + //----------------------------------------------------------------------------------------------------- + /** + * This has differing behaviour depending on if mining has been started/etc. + * Note: add documentation + */ + bool miner::set_is_background_mining_enabled(bool is_background_mining_enabled) + { + m_is_background_mining_enabled = is_background_mining_enabled; + // Extra logic will be required if we make this function public in the future + // and allow toggling smart mining without start/stop + //m_is_background_mining_enabled_cond.notify_one(); + return true; + } + //----------------------------------------------------------------------------------------------------- + uint64_t miner::get_min_idle_seconds() const + { + return m_min_idle_seconds; + } + //----------------------------------------------------------------------------------------------------- + bool miner::set_min_idle_seconds(uint64_t min_idle_seconds) + { + if(min_idle_seconds > BACKGROUND_MINING_MAX_MIN_IDLE_INTERVAL_IN_SECONDS) return false; + if(min_idle_seconds < BACKGROUND_MINING_MIN_MIN_IDLE_INTERVAL_IN_SECONDS) return false; + m_min_idle_seconds = min_idle_seconds; + return true; + } + //----------------------------------------------------------------------------------------------------- + uint8_t miner::get_idle_threshold() const + { + return m_idle_threshold; + } + //----------------------------------------------------------------------------------------------------- + bool miner::set_idle_threshold(uint8_t idle_threshold) + { + if(idle_threshold > BACKGROUND_MINING_MAX_IDLE_THRESHOLD_PERCENTAGE) return false; + if(idle_threshold < BACKGROUND_MINING_MIN_IDLE_THRESHOLD_PERCENTAGE) return false; + m_idle_threshold = idle_threshold; + return true; + } + //----------------------------------------------------------------------------------------------------- + uint8_t miner::get_mining_target() const + { + return m_mining_target; + } + //----------------------------------------------------------------------------------------------------- + bool miner::set_mining_target(uint8_t mining_target) + { + if(mining_target > BACKGROUND_MINING_MAX_MINING_TARGET_PERCENTAGE) return false; + if(mining_target < BACKGROUND_MINING_MIN_MINING_TARGET_PERCENTAGE) return false; + m_mining_target = mining_target; + return true; + } + //----------------------------------------------------------------------------------------------------- + bool miner::background_worker_thread() + { + uint64_t prev_total_time, current_total_time; + uint64_t prev_idle_time, current_idle_time; + uint64_t previous_process_time = 0, current_process_time = 0; + if(!get_system_times(prev_total_time, prev_idle_time)) + { + LOG_ERROR(__func__ << " : get_system_times call failed, background mining will NOT work!"); + return false; + } + + while(!m_stop) + { + + try + { + // Commenting out the below since we're going with privatizing the bg mining enabled + // function, but I'll leave the code/comments here for anyone that wants to modify the + // patch in the future + // ------------------------------------------------------------------------------------- + // All of this might be overkill if we just enforced some simple requirements + // about changing this variable before/after the miner starts, but I envision + // in the future a checkbox that you can tick on/off for background mining after + // you've clicked "start mining". There's still an issue here where if background + // mining is disabled when start is called, this thread is never created, and so + // enabling after does nothing, something I have to fix in the future. However, + // this should take care of the case where mining is started with bg-enabled, + // and then the user decides to un-check background mining, and just do + // regular full-speed mining. I might just be over-doing it and thinking up + // non-existant use-cases, so if the concensus is to simplify, we can remove all this fluff. + /* + while( !m_is_background_mining_enabled ) + { + MGINFO(__func__ << " : background mining is disabled, waiting until enabled!"); + boost::unique_lock enabled_lock( m_is_background_mining_enabled_mutex ); + m_is_background_mining_enabled_cond.wait( enabled_lock ); + } + */ + + // If we're already mining, then sleep for the miner monitor interval. + // If we're NOT mining, then sleep for the idle monitor interval + boost::this_thread::sleep_for( + m_is_background_mining_started ? + boost::chrono::seconds( BACKGROUND_MINING_MINER_MONITOR_INVERVAL_IN_SECONDS ) : + boost::chrono::seconds( get_min_idle_seconds() ) ); + } + catch(boost::thread_interrupted) + { + MGINFO(__func__ << " : background miner thread interrupted "); + continue; // if interrupted because stop called, loop should end .. + } + + if( m_is_background_mining_started ) + { + // figure out if we need to stop, and monitor mining usage + + // previous is uninitialized + if(previous_process_time == 0) + { + // get some starting data .. + if(!get_system_times(prev_total_time, prev_idle_time)) + LOG_ERROR(__func__ << " : get_system_times call failed"); + + if(!get_process_time(previous_process_time)) + LOG_ERROR(__func__ << " : get_process_time call failed!"); + + continue; + } + + // If we get here, then previous values are initialized. + // Let's get some current data for comparison. + + if(!get_system_times(current_total_time, current_idle_time)) + { + LOG_ERROR(__func__ << " : get_system_times call failed"); + continue; + } + + if(!get_process_time(current_process_time)) + { + LOG_ERROR(__func__ << " : get_process_time call failed!"); + continue; + } + + uint64_t total_diff = (current_total_time - prev_total_time); + uint64_t idle_diff = (current_idle_time - prev_idle_time); + uint64_t process_diff = (current_process_time - previous_process_time); + uint8_t idle_percentage = get_percent_of_total(idle_diff, total_diff); + uint8_t process_percentage = get_percent_of_total(process_diff, total_diff); + bool on_ac_power = ac_line_status(); + MGINFO(__func__ << " : idle percentage is " << unsigned(idle_percentage) << "\%, miner percentage is " << unsigned(process_percentage) << "\%, ac power : " << on_ac_power); + if( idle_percentage + process_percentage < get_idle_threshold() || !ac_line_status() ) + { + MGINFO(__func__ << " : cpu is " << unsigned(idle_percentage) << "% idle, idle threshold is " << unsigned(get_idle_threshold()) << "\%, ac power : " << on_ac_power << ", background mining stopping, thanks for your contribution!"); + m_is_background_mining_started = false; + + // reset process times + previous_process_time = 0; + current_process_time = 0; + } + else + { + previous_process_time = current_process_time; + + // adjust the miner extra sleep variable + int64_t miner_extra_sleep_change = (-1 * (get_mining_target() - process_percentage) ); + int64_t new_miner_extra_sleep = m_miner_extra_sleep + miner_extra_sleep_change; + // if you start the miner with few threads on a multicore system, this could + // fall below zero because all the time functions aggregate across all processors. + // I'm just hard limiting to 5 millis min sleep here, other options? + m_miner_extra_sleep = std::max( new_miner_extra_sleep , (int64_t)5 ); + MGINFO(__func__ << " : m_miner_extra_sleep " << m_miner_extra_sleep); + } + + prev_total_time = current_total_time; + prev_idle_time = current_idle_time; + } + else + { + // figure out if we need to start + + if(!get_system_times(current_total_time, current_idle_time)) + { + LOG_ERROR(__func__ << " : get_system_times call failed"); + continue; + } + + uint64_t total_diff = (current_total_time - prev_total_time); + uint64_t idle_diff = (current_idle_time - prev_idle_time); + uint8_t idle_percentage = get_percent_of_total(idle_diff, total_diff); + bool on_ac_power = ac_line_status(); + MGINFO(__func__ << " : idle percentage is " << unsigned(idle_percentage)); + if( idle_percentage >= get_idle_threshold() && on_ac_power ) + { + MGINFO(__func__ << " : cpu is " << unsigned(idle_percentage) << "% idle, idle threshold is " << unsigned(get_idle_threshold()) << "\%, ac power : " << on_ac_power << ", background mining started, good luck!"); + m_is_background_mining_started = true; + m_is_background_mining_started_cond.notify_all(); + } + + prev_total_time = current_total_time; + prev_idle_time = current_idle_time; + } + } + + return true; + } + //----------------------------------------------------------------------------------------------------- + bool miner::get_system_times(uint64_t& total_time, uint64_t& idle_time) + { + #ifdef _WIN32 + + FILETIME idleTime; + FILETIME kernelTime; + FILETIME userTime; + if ( GetSystemTimes( &idleTime, &kernelTime, &userTime ) != -1 ) + { + total_time = + ( (((uint64_t)(kernelTime.dwHighDateTime)) << 32) | ((uint64_t)kernelTime.dwLowDateTime) ) + + ( (((uint64_t)(userTime.dwHighDateTime)) << 32) | ((uint64_t)userTime.dwLowDateTime) ); + + idle_time = ( (((uint64_t)(idleTime.dwHighDateTime)) << 32) | ((uint64_t)idleTime.dwLowDateTime) ); + + return true; + } + + #elif defined(__linux__) + + const std::string STR_CPU("cpu"); + const std::size_t STR_CPU_LEN = STR_CPU.size(); + const std::string STAT_FILE_PATH = "/proc/stat"; + + if( !epee::file_io_utils::is_file_exist(STAT_FILE_PATH) ) + { + LOG_ERROR(__func__ << " : '" << STAT_FILE_PATH << "' file does not exist"); + return false; + } + + std::ifstream stat_file_stream(STAT_FILE_PATH); + if( stat_file_stream.fail() ) + { + LOG_ERROR(__func__ << " : failed to open '" << STAT_FILE_PATH << "'"); + return false; + } + + std::string line; + std::getline(stat_file_stream, line); + std::istringstream stat_file_iss(line); + stat_file_iss.ignore(65536, ' '); // skip cpu label ... + uint64_t utime, ntime, stime, itime; + if( !(stat_file_iss >> utime && stat_file_iss >> ntime && stat_file_iss >> stime && stat_file_iss >> itime) ) + { + LOG_ERROR(__func__ << " : failed to read '" << STAT_FILE_PATH << "'"); + return false; + } + + idle_time = itime; + total_time = utime + ntime + stime + itime; + + return true; + + #endif + + return false; // unsupported systemm.. + } + //----------------------------------------------------------------------------------------------------- + bool miner::get_process_time(uint64_t& total_time) + { + #ifdef _WIN32 + + FILETIME createTime; + FILETIME exitTime; + FILETIME kernelTime; + FILETIME userTime; + if ( GetProcessTimes( GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime ) != -1 ) + { + total_time = + ( (((uint64_t)(kernelTime.dwHighDateTime)) << 32) | ((uint64_t)kernelTime.dwLowDateTime) ) + + ( (((uint64_t)(userTime.dwHighDateTime)) << 32) | ((uint64_t)userTime.dwLowDateTime) ); + + return true; + } + + #elif defined(__linux__) && defined(_SC_CLK_TCK) + + struct tms tms; + if ( times(&tms) != (clock_t)-1 ) + { + total_time = tms.tms_utime + tms.tms_stime; + return true; + } + + #endif + + return false; // unsupported system.. + } + //----------------------------------------------------------------------------------------------------- + uint8_t miner::get_percent_of_total(uint64_t other, uint64_t total) + { + return (uint8_t)( ceil( (other * 1.f / total * 1.f) * 100) ); + } + //----------------------------------------------------------------------------------------------------- + bool miner::ac_line_status() + { + #ifdef _WIN32 + + SYSTEM_POWER_STATUS power_status; + if ( GetSystemPowerStatus( &power_status ) != 0 ) + { + return power_status.ACLineStatus == 1; + } + + #elif defined(__linux__) + + // i've only tested on UBUNTU, these paths might be different on other systems + // need to figure out a way to make this more flexible + const std::string POWER_SUPPLY_STATUS_PATH = "/sys/class/power_supply/ACAD/online"; + + if( !epee::file_io_utils::is_file_exist(POWER_SUPPLY_STATUS_PATH) ) + { + LOG_ERROR(__func__ << " : '" << POWER_SUPPLY_STATUS_PATH << "' file does not exist, can't determine if on AC power"); + return false; + } + + std::ifstream power_stream(POWER_SUPPLY_STATUS_PATH); + if( power_stream.fail() ) + { + LOG_ERROR(__func__ << " : failed to open '" << POWER_SUPPLY_STATUS_PATH << "'"); + return false; + } + + return power_stream.get() == '1'; + + #endif + + LOG_ERROR(__func__ << " : couldn't query power status"); + return false; // shouldn't get here unless no support for querying battery status + } +} diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h index f24f6e960..ea669f7ea 100644 --- a/src/cryptonote_basic/miner.h +++ b/src/cryptonote_basic/miner.h @@ -35,7 +35,14 @@ #include "cryptonote_basic.h" #include "difficulty.h" #include "math_helper.h" - +#ifdef _WIN32 +#include +#elif __linux__ +#include +#include +#include +#include +#endif namespace cryptonote { @@ -60,7 +67,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); bool on_block_chain_update(); - bool start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs); + bool start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs, bool do_background = false); uint64_t get_speed() const; uint32_t get_threads_count() const; void send_stop_signal(); @@ -74,6 +81,26 @@ namespace cryptonote void pause(); void resume(); void do_print_hashrate(bool do_hr); + bool get_is_background_mining_enabled() const; + uint64_t get_min_idle_seconds() const; + bool set_min_idle_seconds(uint64_t min_idle_seconds); + uint8_t get_idle_threshold() const; + bool set_idle_threshold(uint8_t idle_threshold); + uint8_t get_mining_target() const; + bool set_mining_target(uint8_t mining_target); + + static constexpr uint8_t BACKGROUND_MINING_DEFAULT_IDLE_THRESHOLD_PERCENTAGE = 90; + static constexpr uint8_t BACKGROUND_MINING_MIN_IDLE_THRESHOLD_PERCENTAGE = 50; + static constexpr uint8_t BACKGROUND_MINING_MAX_IDLE_THRESHOLD_PERCENTAGE = 99; + static constexpr uint16_t BACKGROUND_MINING_DEFAULT_MIN_IDLE_INTERVAL_IN_SECONDS = 10; + static constexpr uint16_t BACKGROUND_MINING_MIN_MIN_IDLE_INTERVAL_IN_SECONDS = 10; + static constexpr uint16_t BACKGROUND_MINING_MAX_MIN_IDLE_INTERVAL_IN_SECONDS = 3600; + static constexpr uint8_t BACKGROUND_MINING_DEFAULT_MINING_TARGET_PERCENTAGE = 20; + static constexpr uint8_t BACKGROUND_MINING_MIN_MINING_TARGET_PERCENTAGE = 5; + static constexpr uint8_t BACKGROUND_MINING_MAX_MINING_TARGET_PERCENTAGE = 50; + static constexpr uint8_t BACKGROUND_MINING_MINER_MONITOR_INVERVAL_IN_SECONDS = 10; + static constexpr uint64_t BACKGROUND_MINING_DEFAULT_MINER_EXTRA_SLEEP_MILLIS = 400; // ramp up + static constexpr uint64_t BACKGROUND_MINING_MIN_MINER_EXTRA_SLEEP_MILLIS = 5; private: bool worker_thread(); @@ -119,8 +146,24 @@ namespace cryptonote bool m_do_print_hashrate; bool m_do_mining; + // background mining stuffs .. + + bool set_is_background_mining_enabled(bool is_background_mining_enabled); + bool background_worker_thread(); + std::atomic m_is_background_mining_enabled; + boost::mutex m_is_background_mining_enabled_mutex; + boost::condition_variable m_is_background_mining_enabled_cond; + std::atomic m_is_background_mining_started; + boost::mutex m_is_background_mining_started_mutex; + boost::condition_variable m_is_background_mining_started_cond; + boost::thread m_background_mining_thread; + uint64_t m_min_idle_seconds; + uint8_t m_idle_threshold; + uint8_t m_mining_target; + std::atomic m_miner_extra_sleep; + static bool get_system_times(uint64_t& total_time, uint64_t& idle_time); + static bool get_process_time(uint64_t& total_time); + static uint8_t get_percent_of_total(uint64_t some_time, uint64_t total_time); + static bool ac_line_status(); // true = plugged in, else nope }; } - - - diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index fd73654ac..8ed529737 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -271,17 +271,24 @@ bool t_command_parser_executor::start_mining(const std::vector& arg if(testnet) std::cout << "Mining to a testnet address, make sure this is intentional!" << std::endl; uint64_t threads_count = 1; - if(args.size() > 2) + bool do_background_mining = false; + if(args.size() > 3) { return false; } - else if(args.size() == 2) + + if(args.size() == 3) + { + do_background_mining = args[2] == "true"; + } + + if(args.size() >= 2) { bool ok = epee::string_tools::get_xtype_from_string(threads_count, args[1]); threads_count = (ok && 0 < threads_count) ? threads_count : 1; } - m_executor.start_mining(adr, threads_count, testnet); + m_executor.start_mining(adr, threads_count, testnet, do_background_mining); return true; } diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index 34868b576..4133b90d9 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -96,7 +96,7 @@ t_command_server::t_command_server( m_command_lookup.set_handler( "start_mining" , std::bind(&t_command_parser_executor::start_mining, &m_parser, p::_1) - , "Start mining for specified address, start_mining [], default 1 thread" + , "Start mining for specified address, start_mining [] [do_background_mining], default 1 thread, no background mining" ); m_command_lookup.set_handler( "stop_mining" diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 469f83014..ae5c2d31d 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -929,11 +929,12 @@ bool t_rpc_command_executor::print_transaction_pool_stats() { return true; } -bool t_rpc_command_executor::start_mining(cryptonote::account_public_address address, uint64_t num_threads, bool testnet) { +bool t_rpc_command_executor::start_mining(cryptonote::account_public_address address, uint64_t num_threads, bool testnet, bool do_background_mining = false) { cryptonote::COMMAND_RPC_START_MINING::request req; cryptonote::COMMAND_RPC_START_MINING::response res; req.miner_address = cryptonote::get_account_address_as_str(testnet, address); req.threads_count = num_threads; + req.do_background_mining = do_background_mining; std::string fail_message = "Mining did not start"; diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h index 4691844fa..5b7b76448 100644 --- a/src/daemon/rpc_command_executor.h +++ b/src/daemon/rpc_command_executor.h @@ -106,7 +106,7 @@ public: bool print_transaction_pool_stats(); - bool start_mining(cryptonote::account_public_address address, uint64_t num_threads, bool testnet); + bool start_mining(cryptonote::account_public_address address, uint64_t num_threads, bool testnet, bool do_background_mining); bool stop_mining(); diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 5442b6ac4..608f1e531 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -635,7 +635,7 @@ namespace cryptonote boost::thread::attributes attrs; attrs.set_stack_size(THREAD_STACK_SIZE); - if(!m_core.get_miner().start(adr, static_cast(req.threads_count), attrs)) + if(!m_core.get_miner().start(adr, static_cast(req.threads_count), attrs, req.do_background_mining)) { res.status = "Failed, mining not started"; LOG_PRINT_L0(res.status); diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 83ef2ebd4..a26350ba9 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -500,10 +500,12 @@ namespace cryptonote { std::string miner_address; uint64_t threads_count; + bool do_background_mining; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(miner_address) KV_SERIALIZE(threads_count) + KV_SERIALIZE(do_background_mining) END_KV_SERIALIZE_MAP() }; From 21a1e0252f3dd08ff7d067c9e7f2b9454c615d27 Mon Sep 17 00:00:00 2001 From: Dion Ahmetaj Date: Thu, 2 Feb 2017 12:24:42 -0500 Subject: [PATCH 2/9] Set background mining started bool to false on bg thread start. If mining::stop then mining::start, idle logic is re-run instead of starting immediately (if it was running before stop). --- src/cryptonote_basic/miner.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 2b70df643..d424dd5e7 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -526,6 +526,7 @@ namespace cryptonote uint64_t prev_total_time, current_total_time; uint64_t prev_idle_time, current_idle_time; uint64_t previous_process_time = 0, current_process_time = 0; + m_is_background_mining_enabled = false; if(!get_system_times(prev_total_time, prev_idle_time)) { From 2937fdbbbf9219d345ff561a4ecfe25dbdddd247 Mon Sep 17 00:00:00 2001 From: Dion Ahmetaj Date: Thu, 2 Feb 2017 12:30:33 -0500 Subject: [PATCH 3/9] Moved setting of previous process times to block where background mining is started, and added an explicit sleep in that block to wait for some mining to occur. --- src/cryptonote_basic/miner.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index d424dd5e7..9ae56be38 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -578,19 +578,6 @@ namespace cryptonote if( m_is_background_mining_started ) { // figure out if we need to stop, and monitor mining usage - - // previous is uninitialized - if(previous_process_time == 0) - { - // get some starting data .. - if(!get_system_times(prev_total_time, prev_idle_time)) - LOG_ERROR(__func__ << " : get_system_times call failed"); - - if(!get_process_time(previous_process_time)) - LOG_ERROR(__func__ << " : get_process_time call failed!"); - - continue; - } // If we get here, then previous values are initialized. // Let's get some current data for comparison. @@ -659,7 +646,17 @@ namespace cryptonote { MGINFO(__func__ << " : cpu is " << unsigned(idle_percentage) << "% idle, idle threshold is " << unsigned(get_idle_threshold()) << "\%, ac power : " << on_ac_power << ", background mining started, good luck!"); m_is_background_mining_started = true; - m_is_background_mining_started_cond.notify_all(); + m_is_background_mining_started_cond.notify_all(); + + // Wait for a little mining to happen .. + boost::this_thread::sleep_for(boost::chrono::seconds( 1 )); + + // Starting data ... + if(!get_process_time(previous_process_time)) + { + m_is_background_mining_started = false; + LOG_ERROR(__func__ << " : get_process_time call failed!"); + } } prev_total_time = current_total_time; From 0b1045ed7d4a8116489996de49eb0940eee03015 Mon Sep 17 00:00:00 2001 From: Dion Ahmetaj Date: Thu, 2 Feb 2017 12:33:34 -0500 Subject: [PATCH 4/9] Moved around checking of AC power in order to bail quicker to sleep if not plugged in. --- src/cryptonote_basic/miner.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 9ae56be38..08877c260 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -574,7 +574,9 @@ namespace cryptonote MGINFO(__func__ << " : background miner thread interrupted "); continue; // if interrupted because stop called, loop should end .. } - + + bool on_ac_power = ac_line_status(); + if( m_is_background_mining_started ) { // figure out if we need to stop, and monitor mining usage @@ -599,9 +601,9 @@ namespace cryptonote uint64_t process_diff = (current_process_time - previous_process_time); uint8_t idle_percentage = get_percent_of_total(idle_diff, total_diff); uint8_t process_percentage = get_percent_of_total(process_diff, total_diff); - bool on_ac_power = ac_line_status(); + MGINFO(__func__ << " : idle percentage is " << unsigned(idle_percentage) << "\%, miner percentage is " << unsigned(process_percentage) << "\%, ac power : " << on_ac_power); - if( idle_percentage + process_percentage < get_idle_threshold() || !ac_line_status() ) + if( idle_percentage + process_percentage < get_idle_threshold() || !on_ac_power ) { MGINFO(__func__ << " : cpu is " << unsigned(idle_percentage) << "% idle, idle threshold is " << unsigned(get_idle_threshold()) << "\%, ac power : " << on_ac_power << ", background mining stopping, thanks for your contribution!"); m_is_background_mining_started = false; @@ -627,7 +629,7 @@ namespace cryptonote prev_total_time = current_total_time; prev_idle_time = current_idle_time; } - else + else if( on_ac_power ) { // figure out if we need to start From 68652cd94d0cf3a94e36fbd631db83c201dc5908 Mon Sep 17 00:00:00 2001 From: Dion Ahmetaj Date: Thu, 2 Feb 2017 12:34:51 -0500 Subject: [PATCH 5/9] Added some //TODO comments pertaining to returning enums instead of bools in order to be better able to handle failure states. --- src/cryptonote_basic/miner.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 08877c260..e654ac185 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -798,5 +798,10 @@ namespace cryptonote LOG_ERROR(__func__ << " : couldn't query power status"); return false; // shouldn't get here unless no support for querying battery status + // TODO: return enum with ability to signify failure in querying for power status + // and change bg-mining logic so that it stops. As @vtnerd states, with the current + // setup "If someone enabled background mining on a system that fails to grab ac + // status, it will just continually check with little hope of ever being resolved + // automagically". This is also the case for time/idle stats functions. } } From d2c7d0f6b0d0cef224f6a2390fa33c3018847a44 Mon Sep 17 00:00:00 2001 From: Dion Ahmetaj Date: Sat, 4 Feb 2017 13:21:13 -0500 Subject: [PATCH 6/9] Cleaned up some logging. Thanks to moneromooo for help. --- src/cryptonote_basic/miner.cpp | 40 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index e654ac185..92be4dfec 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -335,7 +335,7 @@ namespace cryptonote m_background_mining_thread.interrupt(); m_background_mining_thread.join(); - LOG_PRINT_L0("Mining has been stopped, " << m_threads.size() << " finished" ); + MINFO("Mining has been stopped, " << m_threads.size() << " finished" ); m_threads.clear(); return true; } @@ -530,7 +530,7 @@ namespace cryptonote if(!get_system_times(prev_total_time, prev_idle_time)) { - LOG_ERROR(__func__ << " : get_system_times call failed, background mining will NOT work!"); + LOG_ERROR("get_system_times call failed, background mining will NOT work!"); return false; } @@ -556,7 +556,7 @@ namespace cryptonote /* while( !m_is_background_mining_enabled ) { - MGINFO(__func__ << " : background mining is disabled, waiting until enabled!"); + MGINFO("background mining is disabled, waiting until enabled!"); boost::unique_lock enabled_lock( m_is_background_mining_enabled_mutex ); m_is_background_mining_enabled_cond.wait( enabled_lock ); } @@ -569,9 +569,9 @@ namespace cryptonote boost::chrono::seconds( BACKGROUND_MINING_MINER_MONITOR_INVERVAL_IN_SECONDS ) : boost::chrono::seconds( get_min_idle_seconds() ) ); } - catch(boost::thread_interrupted) + catch(const boost::thread_interrupted&) { - MGINFO(__func__ << " : background miner thread interrupted "); + MDEBUG("background miner thread interrupted "); continue; // if interrupted because stop called, loop should end .. } @@ -586,13 +586,13 @@ namespace cryptonote if(!get_system_times(current_total_time, current_idle_time)) { - LOG_ERROR(__func__ << " : get_system_times call failed"); + MERROR("get_system_times call failed"); continue; } if(!get_process_time(current_process_time)) { - LOG_ERROR(__func__ << " : get_process_time call failed!"); + MERROR("get_process_time call failed!"); continue; } @@ -602,10 +602,10 @@ namespace cryptonote uint8_t idle_percentage = get_percent_of_total(idle_diff, total_diff); uint8_t process_percentage = get_percent_of_total(process_diff, total_diff); - MGINFO(__func__ << " : idle percentage is " << unsigned(idle_percentage) << "\%, miner percentage is " << unsigned(process_percentage) << "\%, ac power : " << on_ac_power); + MGINFO("idle percentage is " << unsigned(idle_percentage) << "\%, miner percentage is " << unsigned(process_percentage) << "\%, ac power : " << on_ac_power); if( idle_percentage + process_percentage < get_idle_threshold() || !on_ac_power ) { - MGINFO(__func__ << " : cpu is " << unsigned(idle_percentage) << "% idle, idle threshold is " << unsigned(get_idle_threshold()) << "\%, ac power : " << on_ac_power << ", background mining stopping, thanks for your contribution!"); + MGINFO("cpu is " << unsigned(idle_percentage) << "% idle, idle threshold is " << unsigned(get_idle_threshold()) << "\%, ac power : " << on_ac_power << ", background mining stopping, thanks for your contribution!"); m_is_background_mining_started = false; // reset process times @@ -623,7 +623,7 @@ namespace cryptonote // fall below zero because all the time functions aggregate across all processors. // I'm just hard limiting to 5 millis min sleep here, other options? m_miner_extra_sleep = std::max( new_miner_extra_sleep , (int64_t)5 ); - MGINFO(__func__ << " : m_miner_extra_sleep " << m_miner_extra_sleep); + MDEBUG("m_miner_extra_sleep " << m_miner_extra_sleep); } prev_total_time = current_total_time; @@ -635,7 +635,7 @@ namespace cryptonote if(!get_system_times(current_total_time, current_idle_time)) { - LOG_ERROR(__func__ << " : get_system_times call failed"); + MERROR("get_system_times call failed"); continue; } @@ -643,10 +643,10 @@ namespace cryptonote uint64_t idle_diff = (current_idle_time - prev_idle_time); uint8_t idle_percentage = get_percent_of_total(idle_diff, total_diff); bool on_ac_power = ac_line_status(); - MGINFO(__func__ << " : idle percentage is " << unsigned(idle_percentage)); + MGINFO("idle percentage is " << unsigned(idle_percentage)); if( idle_percentage >= get_idle_threshold() && on_ac_power ) { - MGINFO(__func__ << " : cpu is " << unsigned(idle_percentage) << "% idle, idle threshold is " << unsigned(get_idle_threshold()) << "\%, ac power : " << on_ac_power << ", background mining started, good luck!"); + MGINFO("cpu is " << unsigned(idle_percentage) << "% idle, idle threshold is " << unsigned(get_idle_threshold()) << "\%, ac power : " << on_ac_power << ", background mining started, good luck!"); m_is_background_mining_started = true; m_is_background_mining_started_cond.notify_all(); @@ -657,7 +657,7 @@ namespace cryptonote if(!get_process_time(previous_process_time)) { m_is_background_mining_started = false; - LOG_ERROR(__func__ << " : get_process_time call failed!"); + MERROR("get_process_time call failed!"); } } @@ -695,14 +695,14 @@ namespace cryptonote if( !epee::file_io_utils::is_file_exist(STAT_FILE_PATH) ) { - LOG_ERROR(__func__ << " : '" << STAT_FILE_PATH << "' file does not exist"); + LOG_ERROR("'" << STAT_FILE_PATH << "' file does not exist"); return false; } std::ifstream stat_file_stream(STAT_FILE_PATH); if( stat_file_stream.fail() ) { - LOG_ERROR(__func__ << " : failed to open '" << STAT_FILE_PATH << "'"); + LOG_ERROR("failed to open '" << STAT_FILE_PATH << "'"); return false; } @@ -713,7 +713,7 @@ namespace cryptonote uint64_t utime, ntime, stime, itime; if( !(stat_file_iss >> utime && stat_file_iss >> ntime && stat_file_iss >> stime && stat_file_iss >> itime) ) { - LOG_ERROR(__func__ << " : failed to read '" << STAT_FILE_PATH << "'"); + LOG_ERROR("failed to read '" << STAT_FILE_PATH << "'"); return false; } @@ -781,14 +781,14 @@ namespace cryptonote if( !epee::file_io_utils::is_file_exist(POWER_SUPPLY_STATUS_PATH) ) { - LOG_ERROR(__func__ << " : '" << POWER_SUPPLY_STATUS_PATH << "' file does not exist, can't determine if on AC power"); + LOG_ERROR("'" << POWER_SUPPLY_STATUS_PATH << "' file does not exist, can't determine if on AC power"); return false; } std::ifstream power_stream(POWER_SUPPLY_STATUS_PATH); if( power_stream.fail() ) { - LOG_ERROR(__func__ << " : failed to open '" << POWER_SUPPLY_STATUS_PATH << "'"); + LOG_ERROR("failed to open '" << POWER_SUPPLY_STATUS_PATH << "'"); return false; } @@ -796,7 +796,7 @@ namespace cryptonote #endif - LOG_ERROR(__func__ << " : couldn't query power status"); + LOG_ERROR("couldn't query power status"); return false; // shouldn't get here unless no support for querying battery status // TODO: return enum with ability to signify failure in querying for power status // and change bg-mining logic so that it stops. As @vtnerd states, with the current From 23c73269caec8638eab8ae8107f91aa06c0f3431 Mon Sep 17 00:00:00 2001 From: Dion Ahmetaj Date: Sun, 5 Feb 2017 09:10:03 -0500 Subject: [PATCH 7/9] Use defined directive to silence pre-proc warnings. --- src/cryptonote_basic/miner.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h index ea669f7ea..dae8b4b63 100644 --- a/src/cryptonote_basic/miner.h +++ b/src/cryptonote_basic/miner.h @@ -37,7 +37,7 @@ #include "math_helper.h" #ifdef _WIN32 #include -#elif __linux__ +#elif defined(__linux__) #include #include #include From e4dfd2fb6345c1d212ca3706254faa988948beb3 Mon Sep 17 00:00:00 2001 From: Dion Ahmetaj Date: Tue, 7 Feb 2017 10:55:49 -0500 Subject: [PATCH 8/9] Changed ac_line_status to on_battery_power. --- src/cryptonote_basic/miner.cpp | 10 +++++----- src/cryptonote_basic/miner.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 92be4dfec..145cb185f 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -575,7 +575,7 @@ namespace cryptonote continue; // if interrupted because stop called, loop should end .. } - bool on_ac_power = ac_line_status(); + bool on_ac_power = !on_battery_power(); if( m_is_background_mining_started ) { @@ -642,7 +642,7 @@ namespace cryptonote uint64_t total_diff = (current_total_time - prev_total_time); uint64_t idle_diff = (current_idle_time - prev_idle_time); uint8_t idle_percentage = get_percent_of_total(idle_diff, total_diff); - bool on_ac_power = ac_line_status(); + MGINFO("idle percentage is " << unsigned(idle_percentage)); if( idle_percentage >= get_idle_threshold() && on_ac_power ) { @@ -763,14 +763,14 @@ namespace cryptonote return (uint8_t)( ceil( (other * 1.f / total * 1.f) * 100) ); } //----------------------------------------------------------------------------------------------------- - bool miner::ac_line_status() + bool miner::on_battery_power() { #ifdef _WIN32 SYSTEM_POWER_STATUS power_status; if ( GetSystemPowerStatus( &power_status ) != 0 ) { - return power_status.ACLineStatus == 1; + return power_status.ACLineStatus != 1; } #elif defined(__linux__) @@ -792,7 +792,7 @@ namespace cryptonote return false; } - return power_stream.get() == '1'; + return power_stream.get() != '1'; #endif diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h index dae8b4b63..7c81f1be0 100644 --- a/src/cryptonote_basic/miner.h +++ b/src/cryptonote_basic/miner.h @@ -164,6 +164,6 @@ namespace cryptonote static bool get_system_times(uint64_t& total_time, uint64_t& idle_time); static bool get_process_time(uint64_t& total_time); static uint8_t get_percent_of_total(uint64_t some_time, uint64_t total_time); - static bool ac_line_status(); // true = plugged in, else nope + static bool on_battery_power(); }; } From ad95e65028302c151546e49698284fdf48727c6d Mon Sep 17 00:00:00 2001 From: Dion Ahmetaj Date: Wed, 8 Feb 2017 16:17:50 -0500 Subject: [PATCH 9/9] Added a note about smart mining to status command. Fixed up a bug where I was resetting bg mining enabled instead of started. Upped the miner threshold. Also moved setting of enabled on start above miner thread creation since starting with true, then stopping, then starting with false resulted in race condition. --- src/cryptonote_basic/miner.cpp | 6 +++--- src/cryptonote_basic/miner.h | 2 +- src/daemon/rpc_command_executor.cpp | 2 +- src/rpc/core_rpc_server.cpp | 1 + src/rpc/core_rpc_server_commands_defs.h | 2 ++ 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 145cb185f..117c81878 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -277,7 +277,8 @@ namespace cryptonote boost::interprocess::ipcdetail::atomic_write32(&m_stop, 0); boost::interprocess::ipcdetail::atomic_write32(&m_thread_index, 0); - + set_is_background_mining_enabled(do_background); + for(size_t i = 0; i != threads_count; i++) { m_threads.push_back(boost::thread(attrs, boost::bind(&miner::worker_thread, this))); @@ -285,7 +286,6 @@ namespace cryptonote LOG_PRINT_L0("Mining has started with " << threads_count << " threads, good luck!" ); - set_is_background_mining_enabled(do_background); if( get_is_background_mining_enabled() ) { m_background_mining_thread = boost::thread(attrs, boost::bind(&miner::background_worker_thread, this)); @@ -526,7 +526,7 @@ namespace cryptonote uint64_t prev_total_time, current_total_time; uint64_t prev_idle_time, current_idle_time; uint64_t previous_process_time = 0, current_process_time = 0; - m_is_background_mining_enabled = false; + m_is_background_mining_started = false; if(!get_system_times(prev_total_time, prev_idle_time)) { diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h index 7c81f1be0..a66083ead 100644 --- a/src/cryptonote_basic/miner.h +++ b/src/cryptonote_basic/miner.h @@ -95,7 +95,7 @@ namespace cryptonote static constexpr uint16_t BACKGROUND_MINING_DEFAULT_MIN_IDLE_INTERVAL_IN_SECONDS = 10; static constexpr uint16_t BACKGROUND_MINING_MIN_MIN_IDLE_INTERVAL_IN_SECONDS = 10; static constexpr uint16_t BACKGROUND_MINING_MAX_MIN_IDLE_INTERVAL_IN_SECONDS = 3600; - static constexpr uint8_t BACKGROUND_MINING_DEFAULT_MINING_TARGET_PERCENTAGE = 20; + static constexpr uint8_t BACKGROUND_MINING_DEFAULT_MINING_TARGET_PERCENTAGE = 40; static constexpr uint8_t BACKGROUND_MINING_MIN_MINING_TARGET_PERCENTAGE = 5; static constexpr uint8_t BACKGROUND_MINING_MAX_MINING_TARGET_PERCENTAGE = 50; static constexpr uint8_t BACKGROUND_MINING_MINER_MONITOR_INVERVAL_IN_SECONDS = 10; diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index ae5c2d31d..00b349b15 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -377,7 +377,7 @@ bool t_rpc_command_executor::show_status() { % (unsigned long long)(ires.target_height >= ires.height ? ires.target_height : ires.height) % get_sync_percentage(ires) % (ires.testnet ? "testnet" : "mainnet") - % (mining_busy ? "syncing" : mres.active ? "mining at " + get_mining_speed(mres.speed) : "not mining") + % (mining_busy ? "syncing" : mres.active ? ( ( mres.is_background_mining_enabled ? "smart " : "" ) + std::string("mining at ") + get_mining_speed(mres.speed) ) : "not mining") % get_mining_speed(ires.difficulty / ires.target) % (unsigned)hfres.version % get_fork_extra_info(hfres.earliest_height, ires.height, ires.target) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 608f1e531..1caf737ca 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -663,6 +663,7 @@ namespace cryptonote const miner& lMiner = m_core.get_miner(); res.active = lMiner.is_mining(); + res.is_background_mining_enabled = lMiner.get_is_background_mining_enabled(); if ( lMiner.is_mining() ) { res.speed = lMiner.get_speed(); diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index a26350ba9..3ab1ea175 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -610,6 +610,7 @@ namespace cryptonote uint64_t speed; uint32_t threads_count; std::string address; + bool is_background_mining_enabled; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(status) @@ -617,6 +618,7 @@ namespace cryptonote KV_SERIALIZE(speed) KV_SERIALIZE(threads_count) KV_SERIALIZE(address) + KV_SERIALIZE(is_background_mining_enabled) END_KV_SERIALIZE_MAP() }; };