From 746cf8980b204d7aa60d567a6223e0a5409f44f6 Mon Sep 17 00:00:00 2001 From: Sonali Srivastava Date: Wed, 27 Jul 2022 11:53:21 +0530 Subject: sleep: support multiple battery instead of only BAT0 --- src/sleep/sleep.c | 64 ++++++++++++++++++++++--------------------------------- 1 file changed, 25 insertions(+), 39 deletions(-) (limited to 'src/sleep') diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index ff6c71d61b..14191cfc61 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -263,6 +263,7 @@ static int execute( } static int execute_s2h(const SleepConfig *sleep_config) { + _cleanup_hashmap_free_ Hashmap *last_capacity = NULL, *current_capacity = NULL; int r; assert(sleep_config); @@ -270,42 +271,29 @@ static int execute_s2h(const SleepConfig *sleep_config) { while (battery_is_low() == 0) { _cleanup_close_ int tfd = -1; struct itimerspec ts = {}; - usec_t suspend_interval = sleep_config->hibernate_delay_sec, before_timestamp = 0, after_timestamp = 0; + usec_t suspend_interval = sleep_config->hibernate_delay_sec, before_timestamp = 0, after_timestamp = 0, total_suspend_interval; bool woken_by_timer; - int last_capacity = 0, current_capacity = 0, previous_discharge_rate, estimated_discharge_rate = 0; tfd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK|TFD_CLOEXEC); if (tfd < 0) return log_error_errno(errno, "Error creating timerfd: %m"); /* Store current battery capacity and current time before suspension */ - r = read_battery_capacity_percentage(); - if (r >= 0) { - last_capacity = r; - log_debug("Current battery charge percentage: %d%%", last_capacity); + r = fetch_batteries_capacity_by_name(&last_capacity); + if (r >= 0) before_timestamp = now(CLOCK_BOOTTIME); - } else if (r == -ENOENT) + else if (r == -ENOENT) /* In case of no battery, system suspend interval will be set to HibernateDelaySec=. */ log_debug_errno(r, "Suspend Interval value set to %s: %m", FORMAT_TIMESPAN(suspend_interval, USEC_PER_SEC)); else return log_error_errno(r, "Error fetching battery capacity percentage: %m"); - r = get_battery_discharge_rate(); + r = get_total_suspend_interval(last_capacity, &total_suspend_interval); if (r < 0) - log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to get discharge rate, ignoring: %m"); - else if (last_capacity * 2 <= r) { - /* System should hibernate in case discharge rate is higher than double of battery current capacity - * why double : Because while calculating suspend interval, we have taken a buffer of 30 minute and - * discharge_rate is calculated on per 60 minute basis which is double. Also suspend_interval > 0 */ - log_debug("Current battery percentage capacity too low to suspend, so invoking hibernation"); - break; - } else { - previous_discharge_rate = r; - assert(previous_discharge_rate != 0); - suspend_interval = usec_sub_unsigned(last_capacity * USEC_PER_HOUR / previous_discharge_rate, 30 * USEC_PER_MINUTE); - /* The previous discharge rate is stored in per hour basis so converted to minutes. - * Subtracted 30 minutes from the result to keep a buffer of 30 minutes before battery gets critical */ - } + log_debug_errno(r, "Failed to estimate suspend interval using previous discharge rate, ignoring: %m"); + else + suspend_interval = total_suspend_interval; + log_debug("Set timerfd wake alarm for %s", FORMAT_TIMESPAN(suspend_interval, USEC_PER_SEC)); /* Wake alarm for system with or without battery to hibernate or estimate discharge rate whichever is applicable */ timespec_store(&ts.it_value, suspend_interval); @@ -323,28 +311,26 @@ static int execute_s2h(const SleepConfig *sleep_config) { /* Store fd_wait status */ woken_by_timer = FLAGS_SET(r, POLLIN); - r = read_battery_capacity_percentage(); - if (r >= 0) { - current_capacity = r; - log_debug("Current battery charge percentage after wakeup: %d%%", current_capacity); - } else if (r == -ENOENT) { - /* In case of no battery, system will be hibernated after 1st cycle of suspend */ + r = fetch_batteries_capacity_by_name(¤t_capacity); + if (r < 0) { + /* In case of no battery or error while getting charge level, no need to measure + * discharge rate. Instead system should wakeup if it is manual wakeup or + * hibernate if this is a timer wakeup. */ log_debug_errno(r, "Battery capacity percentage unavailable, cannot estimate discharge rate: %m"); + if (!woken_by_timer) + return 0; break; - } else - return log_error_errno(r, "Error fetching battery capacity percentage: %m"); + } - if (current_capacity >= last_capacity) - log_debug("Battery was not discharged during suspension"); - else { - after_timestamp = now(CLOCK_BOOTTIME); - log_debug("Attempting to estimate battery discharge rate after wakeup from %s sleep", FORMAT_TIMESPAN(after_timestamp - before_timestamp, USEC_PER_HOUR)); + after_timestamp = now(CLOCK_BOOTTIME); + log_debug("Attempting to estimate battery discharge rate after wakeup from %s sleep", FORMAT_TIMESPAN(after_timestamp - before_timestamp, USEC_PER_HOUR)); - estimated_discharge_rate = (last_capacity - current_capacity) * USEC_PER_HOUR / (after_timestamp - before_timestamp); - r = put_battery_discharge_rate(estimated_discharge_rate); + if (after_timestamp != before_timestamp) { + r = estimate_battery_discharge_rate_per_hour(last_capacity, current_capacity, before_timestamp, after_timestamp); if (r < 0) - log_warning_errno(r, "Failed to update battery discharge rate, ignoring: %m"); - } + log_warning_errno(r, "Failed to estimate and update battery discharge rate, ignoring: %m"); + } else + log_debug("System woke up too early to estimate discharge rate"); if (!woken_by_timer) /* Return as manual wakeup done. This also will return in case battery was charged during suspension */ -- cgit v1.2.3