Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Retrieve battery charge information on PCP
Assisted-by: CodeRabbit
Assisted-by: GPT 5.4
Assisted-by: Raptor mini
Co-authored-by: Nathan Scott <nathans@redhat.com>
  • Loading branch information
BenBE and natoscott committed Oct 3, 2026
commit e68417daeba5b2bf6f0e604315e86e7f2084ed3d
2 changes: 2 additions & 0 deletions pcp/Metric.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ typedef enum Metric_ {
PCP_MEM_ZSWAPPED, /* mem.util.zswapped */
PCP_VFS_FILES_COUNT, /* vfs.files.count */
PCP_VFS_FILES_MAX, /* vfs.files.max */
PCP_DENKI_ENERGY_NOW, /* denki.bat.energy_now */
PCP_DENKI_ENERGY_FULL, /* denki.bat.capacity */

PCP_PROC_PID, /* proc.psinfo.pid */
PCP_PROC_PPID, /* proc.psinfo.ppid */
Expand Down
43 changes: 37 additions & 6 deletions pcp/Platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ static const char* Platform_metricNames[] = {
[PCP_MEM_ZSWAPPED] = "mem.util.zswapped",
[PCP_VFS_FILES_COUNT] = "vfs.files.count",
[PCP_VFS_FILES_MAX] = "vfs.files.max",
[PCP_DENKI_ENERGY_NOW] = "denki.bat.energy_now",
[PCP_DENKI_ENERGY_FULL] = "denki.bat.capacity",

[PCP_PROC_PID] = "proc.psinfo.pid",
[PCP_PROC_PPID] = "proc.psinfo.ppid",
Expand Down Expand Up @@ -864,12 +866,41 @@ void Platform_getFileDescriptors(double* used, double* max) {
}

void Platform_getBattery(BatteryInfo* info) {
*info = (BatteryInfo) {
.ac = AC_ERROR,
.percent = NAN,
.energyCurr = NAN,
.energyFull = NAN,
};
info->ac = AC_ERROR;
info->percent = NAN;
info->energyCurr = NAN;
info->energyFull = NAN;

int energyCount = 0;
if (Metric_desc(PCP_DENKI_ENERGY_NOW) != NULL) {
energyCount = Metric_instanceCount(PCP_DENKI_ENERGY_NOW);
}

if (energyCount < 1) {
info->ac = AC_PRESENT;
return;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
}

if (energyCount > 0) {
pmAtomValue* batteryEnergyCurr = xCalloc(energyCount, sizeof(pmAtomValue));
pmAtomValue* batteryEnergyFull = xCalloc(energyCount, sizeof(pmAtomValue));
if (Metric_values(PCP_DENKI_ENERGY_NOW, batteryEnergyCurr, energyCount, PM_TYPE_DOUBLE) &&
Metric_values(PCP_DENKI_ENERGY_FULL, batteryEnergyFull, energyCount, PM_TYPE_DOUBLE)) {
info->energyCurr = 0.0;
info->energyFull = 0.0;
for (int i = 0; i < energyCount; i++) {
double full = isNonnegative(batteryEnergyFull[i].d) ? batteryEnergyFull[i].d : 0.0;
info->energyCurr += CLAMP(batteryEnergyCurr[i].d, 0.0, full);
info->energyFull += full;
}

if (info->energyFull > 0) {
info->percent = CLAMP((info->energyCurr / info->energyFull) * 100.0, 0.0, 100.0);
}
}
free(batteryEnergyCurr);
free(batteryEnergyFull);
Comment on lines +891 to +909

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant files and nearby context.
for f in pcp/Metric.h pcp/Platform.c; do
  echo "===== $f ====="
  wc -l "$f"
done

echo "===== pcp/Metric.h (around lines 100-120) ====="
sed -n '100,120p' pcp/Metric.h

echo "===== pcp/Platform.c (around mappings near lines 230-245) ====="
sed -n '230,245p' pcp/Platform.c

echo "===== pcp/Platform.c (around battery aggregation near lines 880-920) ====="
sed -n '880,920p' pcp/Platform.c

# Search for denki references and any documentation/comments about capacity semantics.
echo "===== grep denki ====="
rg -n "denki\.bat\.(power_now|energy_now|energy_full|capacity)|pmda-denki|fillstate|percent" -S .

Repository: htop-dev/htop

Length of output: 41367


🌐 Web query:

pmda-denki denki.bat.capacity fillstate percent energy_now documentation

💡 Result:

pmda-denki is a Performance Metrics Domain Agent (PMDA) for the Performance Co-Pilot (PCP) suite, designed to collect and expose electrical power consumption and battery metrics on Linux systems [1][2]. Regarding the specific battery metrics mentioned, the following details are documented: denki.bat.capacity This metric reports the battery charge level as a percentage [3]. denki.bat.energy_now This metric shows the current battery charge [3]. It is often used to represent the raw energy level (frequently in Watt-hours) read from the system filesystem [4]. Related Metrics While you mentioned "fillstate," the official documentation and handbook identify the following core metrics for battery management: - denki.bat.power_now: Represents the current consumption or charge rate of the battery, typically updated by firmware [3][4]. - denki.bat.energy_now_rate: This is a computed metric calculated by pmda-denki itself, representing the rate of charging or discharging in 60-second intervals [3][4]. pmda-denki is generally installed and managed via the PCP infrastructure (e.g., using the Install/Remove scripts located in $PCP_PMDAS_DIR/denki) [1][2]. It is designed to work with system-provided power data, such as Intel's RAPL (Running Average Power Limit) interface for CPU power and standard battery sysfs interfaces for battery data [1][5]. For further details, the authoritative documentation can be found in the pmda-denki handbook [3][6].

Citations:


denki.bat.capacity is a percentage, not an energy-capacity metric

pcp/Metric.h and pcp/Platform.c map PCP_DENKI_ENERGY_FULL to denki.bat.capacity, then pcp/Platform.c#L891-L909 treats it as Wh and derives energyFull/percent from mixed units. Rework this to use a real full-capacity metric, or leave energyFull/ETA unset when only fill-state is available.

📍 Affects 2 files
  • pcp/Platform.c#L891-L909 (this comment)
  • pcp/Metric.h#L110-L112
  • pcp/Platform.c#L237-L239

}
}

const char* Platform_getFailedState(void) {
Expand Down