Bug#680401: powerstat-16-17-delta
Attached is the delta between powerstat 0.01.16 and 0.01.17
diff -Nru powerstat-0.01.16/debian/changelog powerstat-0.01.17/debian/changelog
--- powerstat-0.01.16/debian/changelog 2012-06-20 15:56:47.000000000 +0100
+++ powerstat-0.01.17/debian/changelog 2012-07-03 11:49:02.000000000 +0100
@@ -1,3 +1,10 @@
+powerstat (0.01.17-1) unstable; urgency=low
+
+ * Update version
+ * Add support for /sys/class/power_supply (Closes: #679593)
+
+ -- Colin King <colin.king@canonical.com> Tue, 3 Jul 2012 11:48:44 +0100
+
powerstat (0.01.16-1) unstable; urgency=low
* Initial Debian release (Closes: #678273)
diff -Nru powerstat-0.01.16/Makefile powerstat-0.01.17/Makefile
--- powerstat-0.01.16/Makefile 2012-06-20 15:48:34.000000000 +0100
+++ powerstat-0.01.17/Makefile 2012-07-03 11:49:49.000000000 +0100
@@ -1,6 +1,6 @@
CFLAGS += -Wall
-VERSION=0.01.16
+VERSION=0.01.17
BINDIR=/usr/bin
MANDIR=/usr/share/man/man8
diff -Nru powerstat-0.01.16/powerstat.c powerstat-0.01.17/powerstat.c
--- powerstat-0.01.16/powerstat.c 2012-06-20 15:48:34.000000000 +0100
+++ powerstat-0.01.17/powerstat.c 2012-07-03 11:49:49.000000000 +0100
@@ -21,6 +21,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdarg.h>
+#include <stdint.h>
#include <string.h>
#include <unistd.h>
@@ -36,6 +37,7 @@
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <sys/socket.h>
#include <linux/connector.h>
@@ -79,6 +81,16 @@
OPTS_REDO_NETLINK_BUSY | \
OPTS_ROOT_PRIV)
+#define SYS_CLASS_POWER_SUPPLY "/sys/class/power_supply"
+#define PROC_ACPI_BATTERY "/proc/acpi/battery"
+
+#define SYS_FIELD_VOLTAGE "POWER_SUPPLY_VOLTAGE_NOW="
+#define SYS_FIELD_WATTS_RATE "POWER_SUPPLY_POWER_NOW="
+#define SYS_FIELD_WATTS_LEFT "POWER_SUPPLY_ENERGY_NOW="
+#define SYS_FIELD_AMPS_RATE "POWER_SUPPLY_CURRENT_NOW="
+#define SYS_FIELD_AMPS_LEFT "POWER_SUPPLY_CHARGE_NOW="
+#define SYS_FIELD_STATUS_DISCHARGING "POWER_SUPPLY_STATUS=Discharging"
+
/* Measurement entry */
typedef struct {
double value;
@@ -118,6 +130,25 @@
static int opts; /* opt arg opt flags */
static volatile int stop_recv; /* sighandler stop flag */
+
+char *file_get(const char *file)
+{
+ FILE *fp;
+ char buffer[4096];
+
+ if ((fp = fopen(file, "r")) == NULL)
+ return NULL;
+
+ if (fgets(buffer, sizeof(buffer), fp) == NULL) {
+ fclose(fp);
+ return NULL;
+ }
+
+ fclose(fp);
+
+ return strdup(buffer);
+}
+
/*
* tty_height()
* try and find height of tty
@@ -311,8 +342,10 @@
{
int i;
- for (i=0; i<MAX_VALUES; i++)
+ for (i=0; i<MAX_VALUES; i++) {
stats->value[i] = 0.0;
+ stats->inaccurate[i] = false;
+ }
}
/*
@@ -530,7 +563,7 @@
max->inaccurate[j] = true;
min->inaccurate[j] = true;
stddev->inaccurate[j] = true;
-
+
average->value[j] = 0.0;
max->value[j] = 0.0;
min->value[j] = 0.0;
@@ -539,11 +572,176 @@
}
}
+
+
/*
- * power_rate_get()
- * get power discharge rate from battery
+ * power_rate_get_sys_fs()
+ * get power discharge rate from battery via /sys interface
*/
-static int power_rate_get(double *rate, bool *discharging, bool *inaccurate)
+static int power_rate_get_sys_fs(double *rate, bool *discharging, bool *inaccurate)
+{
+ DIR *dir;
+ struct dirent *dirent;
+ time_t time_now, dt;
+
+ static measurement_t measurements[MAX_MEASUREMENTS];
+ static int index = 0;
+ int i, j;
+ double total_watts = 0.0;
+ double total_capacity = 0.0;
+ double dw;
+
+ *rate = 0.0;
+ *discharging = false;
+ *inaccurate = true;
+
+ if ((dir = opendir(SYS_CLASS_POWER_SUPPLY)) == NULL) {
+ fprintf(stderr, "Machine does not have %s, cannot run the test.\n", SYS_CLASS_POWER_SUPPLY);
+ return -1;
+ }
+
+ do {
+ dirent = readdir(dir);
+ if (dirent && strlen(dirent->d_name) > 2) {
+ char path[PATH_MAX];
+ char *data;
+ int val;
+ FILE *fp;
+
+ double voltage = 0.0;
+
+ double amps_rate = 0.0;
+ double amps_left = 0.0;
+
+ double watts_rate = 0.0;
+ double watts_left = 0.0;
+
+ /* Check that type field matches the expected type */
+ snprintf(path, sizeof(path), "%s/%s/type", SYS_CLASS_POWER_SUPPLY, dirent->d_name);
+ if ((data = file_get(path)) != NULL) {
+ bool mismatch = (strstr(data, "Battery") == NULL);
+ free(data);
+ if (mismatch)
+ continue; /* type don't match, skip this entry */
+ } else
+ continue; /* can't check type, skip this entry */
+
+ snprintf(path, sizeof(path), "%s/%s/uevent", SYS_CLASS_POWER_SUPPLY, dirent->d_name);
+ if ((fp = fopen(path, "r")) == NULL) {
+ fprintf(stderr, "Battery %s present but under supported - no state present.", dirent->d_name);
+ return -1;
+ } else {
+ char buffer[4096];
+ while (fgets(buffer, sizeof(buffer)-1, fp) != NULL) {
+ if (strstr(buffer, SYS_FIELD_STATUS_DISCHARGING))
+ *discharging = true;
+
+ if (strstr(buffer, SYS_FIELD_AMPS_LEFT) &&
+ strlen(buffer) > sizeof(SYS_FIELD_AMPS_LEFT) - 1) {
+ sscanf(buffer + sizeof(SYS_FIELD_AMPS_LEFT) - 1, "%d", &val);
+ amps_left = (double)val / 1000000.0;
+ }
+
+ if (strstr(buffer, SYS_FIELD_WATTS_LEFT) &&
+ strlen(buffer) > sizeof(SYS_FIELD_WATTS_LEFT) - 1) {
+ sscanf(buffer + sizeof(SYS_FIELD_WATTS_LEFT) - 1, "%d", &val);
+ watts_left = (double)val / 1000000.0;
+ }
+
+ if (strstr(buffer, SYS_FIELD_AMPS_RATE) &&
+ strlen(buffer) > sizeof(SYS_FIELD_AMPS_RATE) - 1) {
+ sscanf(buffer + sizeof(SYS_FIELD_AMPS_RATE) - 1, "%d", &val);
+ amps_rate = (double)val / 1000000.0;
+ }
+
+ if (strstr(buffer, SYS_FIELD_WATTS_RATE) &&
+ strlen(buffer) > sizeof(SYS_FIELD_WATTS_RATE) - 1) {
+ sscanf(buffer + sizeof(SYS_FIELD_WATTS_RATE) - 1, "%d", &val);
+ watts_rate = (double)val / 1000000.0;
+ }
+
+ if (strstr(buffer, SYS_FIELD_VOLTAGE) &&
+ strlen(buffer) > sizeof(SYS_FIELD_VOLTAGE) - 1) {
+ sscanf(buffer + sizeof(SYS_FIELD_VOLTAGE) - 1, "%d", &val);
+ voltage = (double)val / 1000000.0;
+ }
+ }
+ total_watts += watts_rate + voltage * amps_rate;
+ total_capacity += watts_left + voltage * amps_left;
+ fclose(fp);
+ }
+ }
+ } while (dirent);
+
+ closedir(dir);
+
+ if (! *discharging) {
+ printf("Machine is indicating it is not discharging and hence "
+ "we cannot measure power usage.\n");
+ return -1;
+ }
+
+ /*
+ * If the battery is helpful it supplies the rate already, in which case
+ * we know the results from the battery are as good as we can and we don't
+ * have to figure out anything from capacity change over time.
+ */
+ if (total_watts > RATE_ZERO_LIMIT) {
+ *rate = total_watts;
+ *inaccurate = (total_watts < 0.0);
+ return 0;
+ }
+
+ /*
+ * Battery is less helpful, we need to figure the power rate by looking
+ * back in time, measuring capacity drop and figuring out the rate from
+ * this. We keep track of the rate over a sliding window of ROLLING_AVERAGE
+ * seconds.
+ */
+ time_now = time(NULL);
+
+ measurements[index].value = total_capacity;
+ measurements[index].when = time_now;
+ index = (index + 1) % MAX_MEASUREMENTS;
+
+ /*
+ * Scan back in time for a sample that's > ROLLING_AVERAGE seconds away
+ * and calculate power consumption based on this value and interval
+ */
+ for (j = index, i = 0; i < MAX_MEASUREMENTS; i++) {
+ j--;
+ if (j<0)
+ j+= MAX_MEASUREMENTS;
+
+ if (measurements[j].when) {
+ dw = measurements[j].value - total_capacity;
+ dt = time_now - measurements[j].when;
+ *rate = 3600.0 * dw / dt;
+
+ if (time_now - measurements[j].when > ROLLING_AVERAGE) {
+ *inaccurate = false;
+ break;
+ }
+ }
+ }
+
+ /*
+ * We either have found a good measurement, or an estimate at this point, but
+ * is it valid?
+ */
+ if (*rate < 0.0) {
+ *rate = 0.0;
+ *inaccurate = true;
+ }
+
+ return 0;
+}
+
+/*
+ * power_rate_get_proc_acpi()
+ * get power discharge rate from battery via /proc/acpi interface
+ */
+static int power_rate_get_proc_acpi(double *rate, bool *discharging, bool *inaccurate)
{
DIR *dir;
FILE *file;
@@ -562,8 +760,8 @@
*discharging = false;
*inaccurate = true;
- if ((dir = opendir("/proc/acpi/battery")) == NULL) {
- printf("Machine does not have a battery, cannot run the test.\n");
+ if ((dir = opendir(PROC_ACPI_BATTERY)) == NULL) {
+ fprintf(stderr, "Machine does not have %s, cannot run the test.\n", PROC_ACPI_BATTERY);
return -1;
}
@@ -643,7 +841,7 @@
closedir(dir);
if (! *discharging) {
- printf("Machine is NOT running on battery and hence "
+ printf("Machine is indicating it is not discharging and hence "
"we cannot measure power usage.\n");
return -1;
}
@@ -703,6 +901,21 @@
return 0;
}
+static int power_rate_get(double *rate, bool *discharging, bool *inaccurate)
+{
+ struct stat buf;
+
+ if ((stat(SYS_CLASS_POWER_SUPPLY, &buf) != -1) &&
+ S_ISDIR(buf.st_mode))
+ return power_rate_get_sys_fs(rate, discharging, inaccurate);
+
+ if ((stat(PROC_ACPI_BATTERY, &buf) != -1) &&
+ S_ISDIR(buf.st_mode))
+ return power_rate_get_proc_acpi(rate, discharging, inaccurate);
+
+ return -1;
+}
+
/*
* proc_info_hash()
* hash on PID
@@ -865,6 +1078,11 @@
}
stats_clear_all(stats, max_readings);
+ stats_clear(&average);
+ stats_clear(&stddev);
+ stats_clear(&min);
+ stats_clear(&max);
+
stats_headings();
row++;
@@ -882,7 +1100,7 @@
usec = ((t1.tv_sec + sample_delay - t2.tv_sec) * 1000000) + (t1.tv_usec - t2.tv_usec);
tv.tv_sec = usec / 1000000;
tv.tv_usec = usec % 1000000;
-
+
if (opts & OPTS_USE_NETLINK) {
fd_set readfds;
FD_ZERO(&readfds);
@@ -891,7 +1109,7 @@
} else {
ret = select(0, NULL, NULL, NULL, &tv);
}
-
+
if (ret < 0) {
if (errno == EINTR)
break;
@@ -966,11 +1184,11 @@
return -1;
}
}
-
+
for (nlmsghdr = (struct nlmsghdr *)buf; NLMSG_OK (nlmsghdr, len); nlmsghdr = NLMSG_NEXT (nlmsghdr, len)) {
struct cn_msg *cn_msg;
struct proc_event *proc_ev;
-
+
if ((nlmsghdr->nlmsg_type == NLMSG_ERROR) ||
(nlmsghdr->nlmsg_type == NLMSG_NOOP))
continue;
@@ -1152,7 +1370,7 @@
max_readings = run_duration / sample_delay;
}
- if (geteuid() == 0)
+ if (geteuid() == 0)
opts |= OPTS_ROOT_PRIV;
else if (opts & OPTS_USE_NETLINK) {
fprintf(stderr, "%s needs to be run with root privilege when using -p, -r, -s options\n", argv[0]);
@@ -1173,7 +1391,7 @@
printf("Waiting %d seconds before starting (gathering samples) \r", start_delay - i);
fflush(stdout);
if (power_rate_get(&dummy_rate, &discharging, &dummy_inaccurate) < 0)
- exit(ret);
+ exit(ret);
if (sleep(1) || stop_recv)
exit(ret);
if (!discharging)
Reply to: