More robust battery status handling.

Added an extra path to check for linux power supply status.
Added ignore battery option. If set to true, then when we can't figure out
the power status, we'll assume the system is plugged in.
This commit is contained in:
Dion Ahmetaj 2017-02-15 14:00:01 -05:00
parent 3f171b931f
commit 69ab14d91e
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()
};