Breaking Eggs And Making Omelettes

Topics On Multimedia Technology and Reverse Engineering


Archives:

Monster Battery Power Revisited

May 27th, 2010 by Multimedia Mike

So I have this new fat netbook battery and I performed an experiment to determine how long it really lasts. In my last post on the matter, it was suggested that I should rely on the information that gnome-power-manager is giving me. However, I have rarely seen GPM report more than about 2 hours of charge; even on a full battery, it only reports 3h25m when I profiled it as lasting over 5 hours in my typical use. So I started digging to understand how GPM gets its numbers and determine if, perhaps, it’s not getting accurate data from the system.

I started poking around /proc for the data I wanted. You can learn a lot in /proc as long as you know the right question to ask. I had to remember what the power subsystem is called — ACPI — and this led me to /proc/acpi/battery/BAT0/state which has data such as:

present:                 yes
capacity state:          ok
charging state:          charged
present rate:            unknown
remaining capacity:      100 mAh
present voltage:         8326 mV

“Remaining capacity” rated in mAh is a little odd; I would later determine that this should actually be expressed as a percentage (i.e., 100% charge at the time of this reading). Examining the GPM source code, it seems to determine as a function of the current CPU load (queried via /proc/stat) and the battery state queried via a facility called devicekit. I couldn’t immediately find any source code to the latter but I was able to install a utility called ‘devkit-power’. Mostly, it appears to rehash data already found in the above /proc file.

Curiously, the file /proc/acpi/battery/BAT0/info, which displays essential information about the battery, reports the design capacity of my battery as only 4400 mAh which is true for the original battery; the new monster battery is supposed to be 10400 mAh. I can imagine that all of these data points could be conspiring to under-report my remaining battery life.

Science project: Repeat the previous power-related science project but also parse and track the remaining capacity and present voltage fields from the battery state proc file.

Let’s skip straight to the results (which are consistent with my last set of results in terms of longevity):



So there is definitely something strange going on with the reporting– the 4400 mAh battery reports discharge at a linear rate while the 10400 mAh battery reports precipitous dropoff after 60%.

Another curious item is that my script broke at first when there was 20% power remaining which, as you can imagine, is a really annoying time to discover such a bug. At that point, the “time to empty” reported by devkit-power jumped from 0 seconds to 20 hours (the first state change observed for that field).

Here’s my script, this time elevated from Bash script to Python. It requires xdotool and devkit-power to be installed (both should be available in the package manager for a distro).

  1. #!/usr/bin/python
  2.  
  3. import commands
  4. import random
  5. import sys
  6. import time
  7.  
  8. XDOTOOL = "/usr/bin/xdotool"
  9. BATTERY_STATE = "/proc/acpi/battery/BAT0/state"
  10. DEVKIT_POWER = "/usr/bin/devkit-power -i /org/freedesktop/DeviceKit/Power/devices/battery_BAT0"
  11.  
  12. print "count, unixtime, proc_remaining_capacity, proc_present_voltage, devkit_percentage, devkit_voltage"
  13.  
  14. count = 0
  15. while 1:
  16.     commands.getstatusoutput("%s mousemove %d %d" % (XDOTOOL, random.randrange(0,800), random.randrange(0, 480)))
  17.     battery_state = open(BATTERY_STATE).read().splitlines()
  18.     for line in battery_state:
  19.         if line.startswith("remaining capacity:"):
  20.             proc_remaining_capacity = int(line.lstrip("remaining capacity: ").rstrip("mAh"))
  21.         elif line.startswith("present voltage:"):
  22.             proc_present_voltage = int(line.lstrip("present voltage: ").rstrip("mV"))
  23.     devkit_state = commands.getoutput(DEVKIT_POWER).splitlines()
  24.     for line in devkit_state:
  25.         line = line.strip()
  26.         if line.startswith("percentage:"):
  27.             devkit_percentage = int(line.lstrip("percentage:").rstrip('\%'))
  28.         elif line.startswith("voltage:"):
  29.             devkit_voltage = float(line.lstrip("voltage:").rstrip('V')) * 1000
  30.     print "%d, %d, %d, %d, %d, %d" % (count, time.time(), proc_remaining_capacity, proc_present_voltage, devkit_percentage, devkit_voltage)
  31.     sys.stdout.flush()
  32.     time.sleep(60)
  33.     count += 1

Posted in Python, Science Projects | 1 Comment »

One Response

  1. Owen S Says:

    The dropoff looks right to me if your system is not configured for the battery. A battery’s remaining capacity is calculated by measuring and interpreting its terminal voltage; I’d expect this is being done by the motherboard’s ACPI AML code. Lithium-Ion batteries tend to have exponential power dropoffs – that is, they may only drop by .3v or so for 80% of their cycle, then they’ll plumet as the remaining 20% is removed, down to whatever limiter they have built in (Over discharging can cause them to explode). That, in combination with the monitoring for the wrong capacity, could easily conspire to cause this kind of effect.