Merge pull request #1737

69ab14d9 More robust battery status handling. (Dion Ahmetaj)
This commit is contained in:
Riccardo Spagni 2017-02-21 11:16:08 +02:00
commit d2059dfab2
No known key found for this signature in database
GPG key ID: 55432DF31CCD4FCD
8 changed files with 81 additions and 29 deletions

View file

@ -41,6 +41,7 @@
#include "common/command_line.h"
#include "string_coding.h"
#include "storages/portable_storage_template_helper.h"
#include "boost/logic/tribool.hpp"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "miner"
@ -61,6 +62,7 @@ namespace cryptonote
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_bg_mining_enable = {"bg-mining-enable", "enable/disable 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};
const command_line::arg_descriptor<uint8_t> 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<uint8_t> 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};
@ -181,6 +183,7 @@ namespace cryptonote
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_ignore_battery);
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);
@ -230,6 +233,8 @@ namespace cryptonote
// 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_ignore_battery))
set_ignore_battery( command_line::get_arg(vm, arg_bg_mining_ignore_battery) );
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))
@ -254,7 +259,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 do_background)
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);
@ -278,6 +283,7 @@ 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);
set_ignore_battery(ignore_battery);
for(size_t i = 0; i != threads_count; i++)
{
@ -469,6 +475,11 @@ namespace cryptonote
return m_is_background_mining_enabled;
}
//-----------------------------------------------------------------------------------------------------
bool miner::get_ignore_battery() const
{
return m_ignore_battery;
}
//-----------------------------------------------------------------------------------------------------
/**
* This has differing behaviour depending on if mining has been started/etc.
* Note: add documentation
@ -482,6 +493,11 @@ namespace cryptonote
return true;
}
//-----------------------------------------------------------------------------------------------------
void miner::set_ignore_battery(bool ignore_battery)
{
m_ignore_battery = ignore_battery;
}
//-----------------------------------------------------------------------------------------------------
uint64_t miner::get_min_idle_seconds() const
{
return m_min_idle_seconds;
@ -575,7 +591,21 @@ namespace cryptonote
continue; // if interrupted because stop called, loop should end ..
}
bool on_ac_power = !on_battery_power();
boost::tribool battery_powered(on_battery_power());
bool on_ac_power = false;
if(indeterminate( battery_powered ))
{
// name could be better, only ignores battery requirement if we failed
// to get the status of the system
if( m_ignore_battery )
{
on_ac_power = true;
}
}
else
{
on_ac_power = !battery_powered;
}
if( m_is_background_mining_started )
{
@ -763,45 +793,54 @@ namespace cryptonote
return (uint8_t)( ceil( (other * 1.f / total * 1.f) * 100) );
}
//-----------------------------------------------------------------------------------------------------
bool miner::on_battery_power()
boost::logic::tribool miner::on_battery_power()
{
#ifdef _WIN32
SYSTEM_POWER_STATUS power_status;
if ( GetSystemPowerStatus( &power_status ) != 0 )
{
return power_status.ACLineStatus != 1;
return boost::logic::tribool(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) )
std::string power_supply_path = "";
const std::string POWER_SUPPLY_STATUS_PATHS[] =
{
LOG_ERROR("'" << POWER_SUPPLY_STATUS_PATH << "' file does not exist, can't determine if on AC power");
return false;
"/sys/class/power_supply/ACAD/online",
"/sys/class/power_supply/AC/online"
};
for(const std::string& path : POWER_SUPPLY_STATUS_PATHS)
{
if( epee::file_io_utils::is_file_exist(path) )
{
power_supply_path = path;
break;
}
}
std::ifstream power_stream(POWER_SUPPLY_STATUS_PATH);
if( power_supply_path.empty() )
{
LOG_ERROR("Couldn't find battery/power status file, can't determine if plugged in!");
return boost::logic::tribool(boost::logic::indeterminate);;
}
std::ifstream power_stream(power_supply_path);
if( power_stream.fail() )
{
LOG_ERROR("failed to open '" << POWER_SUPPLY_STATUS_PATH << "'");
return false;
LOG_ERROR("failed to open '" << power_supply_path << "'");
return boost::logic::tribool(boost::logic::indeterminate);;
}
return power_stream.get() != '1';
return boost::logic::tribool( (power_stream.get() != '1') );
#endif
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
// 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.
return boost::logic::tribool(boost::logic::indeterminate);
}
}

View file

@ -31,6 +31,7 @@
#pragma once
#include <boost/program_options.hpp>
#include <boost/logic/tribool_fwd.hpp>
#include <atomic>
#include "cryptonote_basic.h"
#include "difficulty.h"
@ -67,7 +68,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 do_background = false);
bool start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs, bool do_background = false, bool ignore_battery = false);
uint64_t get_speed() const;
uint32_t get_threads_count() const;
void send_stop_signal();
@ -82,6 +83,7 @@ namespace cryptonote
void resume();
void do_print_hashrate(bool do_hr);
bool get_is_background_mining_enabled() const;
bool get_ignore_battery() const;
uint64_t get_min_idle_seconds() const;
bool set_min_idle_seconds(uint64_t min_idle_seconds);
uint8_t get_idle_threshold() const;
@ -149,8 +151,10 @@ namespace cryptonote
// background mining stuffs ..
bool set_is_background_mining_enabled(bool is_background_mining_enabled);
void set_ignore_battery(bool ignore_battery);
bool background_worker_thread();
std::atomic<bool> m_is_background_mining_enabled;
bool m_ignore_battery;
boost::mutex m_is_background_mining_enabled_mutex;
boost::condition_variable m_is_background_mining_enabled_cond;
std::atomic<bool> m_is_background_mining_started;
@ -164,6 +168,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 on_battery_power();
static boost::logic::tribool on_battery_power();
};
}

View file

@ -272,12 +272,18 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg
std::cout << "Mining to a testnet address, make sure this is intentional!" << std::endl;
uint64_t threads_count = 1;
bool do_background_mining = false;
if(args.size() > 3)
bool ignore_battery = false;
if(args.size() > 4)
{
return false;
}
if(args.size() == 3)
if(args.size() == 4)
{
ignore_battery = args[3] == "true";
}
if(args.size() >= 3)
{
do_background_mining = args[2] == "true";
}
@ -288,7 +294,7 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg
threads_count = (ok && 0 < threads_count) ? threads_count : 1;
}
m_executor.start_mining(adr, threads_count, testnet, do_background_mining);
m_executor.start_mining(adr, threads_count, testnet, do_background_mining, ignore_battery);
return true;
}

View file

@ -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 <addr> [<threads>] [do_background_mining], default 1 thread, no background mining"
, "Start mining for specified address, start_mining <addr> [<threads>] [do_background_mining] [ignore_battery], default 1 thread, no background mining"
);
m_command_lookup.set_handler(
"stop_mining"

View file

@ -929,12 +929,13 @@ 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 do_background_mining = false) {
bool t_rpc_command_executor::start_mining(cryptonote::account_public_address address, uint64_t num_threads, bool testnet, bool do_background_mining, bool ignore_battery) {
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;
req.ignore_battery = ignore_battery;
std::string fail_message = "Mining did not start";

View file

@ -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 do_background_mining);
bool start_mining(cryptonote::account_public_address address, uint64_t num_threads, bool testnet, bool do_background_mining = false, bool ignore_battery = false);
bool stop_mining();

View file

@ -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<size_t>(req.threads_count), attrs, req.do_background_mining))
if(!m_core.get_miner().start(adr, static_cast<size_t>(req.threads_count), attrs, req.do_background_mining, req.ignore_battery))
{
res.status = "Failed, mining not started";
LOG_PRINT_L0(res.status);

View file

@ -501,11 +501,13 @@ namespace cryptonote
std::string miner_address;
uint64_t threads_count;
bool do_background_mining;
bool ignore_battery;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(miner_address)
KV_SERIALIZE(threads_count)
KV_SERIALIZE(do_background_mining)
KV_SERIALIZE(ignore_battery)
END_KV_SERIALIZE_MAP()
};