Profiling Laptop Power Dynamics: A Pure Linux sysfs Approach
Modern laptops present a complex power delivery layout. When running on battery, energy measurement is straightforward. However, when connected to AC power, internal battery gauges obscure system-level draw.
Over a nearly two-hour workload session, I profiled my laptop’s power draw using pure Linux Kernel interfaces—without external hardware tools like USB-C power meters—to separate battery charging overhead from active system consumption.
1. System Telemetry Architecture
The Linux Kernel exposes power telemetry through two primary interfaces under /sys:
sysfsACPI Power Supply Subsystem (/sys/class/power_supply/BAT*/)voltage_now¤t_now: Instantaneous terminal parameters (\(\mu\text{V}\), \(\mu\text{A}\)).status: Power state transition matrix (Discharging,Charging,Full).-
power_now: Direct power draw (\(\mu\text{W}\)) provided by the Smart Battery System (SBS) Embedded Controller (EC). - Running Average Power Limit / RAPL (
/sys/class/powercap/intel-rapl/) energy_uj: Cumulative energy counter (\(\mu\text{J}\)) consumed by the CPU package.
flowchart TB
adapter["<b>AC Adapter</b><br/>DC Input"]
subgraph power_paths ["POWER DISTRIBUTION"]
direction LR
components["<b>System Components</b><br/>CPU, GPU, RAM"]
charger["<b>Battery Controller</b><br/>Charger IC"]
end
integration["<b>Energy Integration</b><br/>sysfs BAT0 / Internal RAPL"]
adapter --> components
adapter --> charger
components -- "Internal RAPL + Base Estimate" --> integration
charger -- "sysfs BAT0" --> integration
2. Mathematical Modeling & Integration
Power varies dynamically across system states, requiring numerical integration over time intervals \(\Delta t\):
\[E_{\text{total}} = \sum_{i=1}^{N} \frac{P(t_i) \cdot \Delta t_i}{3600} \quad [\text{Wh}]\]State Machine Logic
- Discharging Phase (\(P_{\text{sys}} = P_{\text{bat}}\)): The system power is directly measured from the battery terminal discharge rate:
- Charging Phase (\(P_{\text{bat}} = P_{\text{charge}}\)): The battery gauge only sees current entering the chemical cells. System component power \(P_{\text{sys}}\) is modeled by differentiating the RAPL energy counter over time plus baseline platform power \(P_{\text{base}}\) (~5 W for display, NVMe, and memory):
3. Data Collection Pipeline
A custom Bash daemon was executed to sample telemetry at \(1\text{ Hz}\) into a structured time-series CSV:
#!/usr/bin/env bash
# High-frequency power state sampler
BAT="/sys/class/power_supply/BAT0"
RAPL="/sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj"
echo "timestamp,status,capacity_pct,voltage_v,current_a,battery_power_w,cpu_energy_uj"
while true; do
TS=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
STATUS=$(cat "$BAT/status")
CAP=$(cat "$BAT/capacity")
V=$(awk "BEGIN {print $(cat $BAT/voltage_now) / 1e6}")
I=$(awk "BEGIN {print $(cat $BAT/current_now) / 1e6}")
P=$(awk "BEGIN {print $V * $I}")
CPU=$(cat "$RAPL" 2>/dev/null || echo 0)
echo "$TS,$STATUS,$CAP,$V,$I,$P,$CPU"
sleep 1
done
4. Analytical Results
Processing the dataset via Python (pandas / numpy) over a 1.81-hour test run yielded the following energy distribution:
| Metric / Phase | Duration | Energy Transferred | Avg Power Draw |
|---|---|---|---|
| Discharging Mode | 0.81 h (48.6 min) | \(12.54\text{ Wh}\) | ~15.5 W |
| Active Charging Mode | 1.00 h (60.0 min) | \(24.60\text{ Wh}\) (To Battery) | ~24.6 W |
| System Active Overhead | 1.81 h (108.6 min) | \(27.99\text{ Wh}\) (Components) | ~15.4 W |
| Total Internal Consumption | 1.81 h | 52.59 Wh | ~29.0 W |
5. Thermal & Efficiency Losses (AC-to-DC Conversion)
The internal telemetry accounts for energy delivered after onboard regulation. To estimate total power pulled from the AC mains grid, we must factor in hardware conversion efficiencies:
\[\text{Efficiency Coefficients:} \quad \eta_{\text{adapter}} \approx 0.89, \quad \eta_{\text{charger\_ic}} \approx 0.92\] \[E_{\text{wall}} = \frac{E_{\text{sys}}}{\eta_{\text{adapter}}} + \frac{E_{\text{charge}}}{\eta_{\text{adapter}} \cdot \eta_{\text{charger\_ic}}}\]Applying these coefficients to our recorded 52.59 Wh internal load yields an estimated ~59.8 Wh (~0.06 kWh) total draw at the mains wall outlet.