mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 05:37:54 +00:00
acpica: retrieve static battery info only once
On Fujitsu S936, evaluating the _BIF method on each battery-info update successively increased the RAM usage, while _BST (dynamic battery status) and _STA (generic status) did not show this behavior. Therefore this commit retrieves only dynamic information periodically (resp. on SCI IRQ). Now, acpica hast static RAM usage in idle state for 24+ hours. The root cause for the increased RAM usage is still shady. While it could just be normal that it grows until a certain yet unknown limit, there may also be memory leak in contrib code or some strange AML on the designated notebook. Issue #3454
This commit is contained in:
parent
a7835650e8
commit
ce149397ec
@ -11,35 +11,166 @@
|
|||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Battery : Acpica::Callback<Battery> {
|
class Battery : Acpica::Callback<Battery>
|
||||||
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Acpica::Reportstate * _report;
|
Acpica::Reportstate * _report;
|
||||||
ACPI_HANDLE _sb;
|
ACPI_HANDLE _sb;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ACPI spec - 10.2.2.1 _BIF (Battery Information)
|
||||||
|
* (alternatively 10.2.2.2 _BIX could be used)
|
||||||
|
*/
|
||||||
|
Acpica::Buffer<char [512]> _battery;
|
||||||
|
Genode::String<16> _battery_name;
|
||||||
|
|
||||||
|
void _init_static_info()
|
||||||
|
{
|
||||||
|
ACPI_STATUS res = AcpiEvaluateObjectTyped(_sb, ACPI_STRING("_BIF"),
|
||||||
|
nullptr, &_battery,
|
||||||
|
ACPI_TYPE_PACKAGE);
|
||||||
|
ACPI_OBJECT * obj = reinterpret_cast<ACPI_OBJECT *>(_battery.object);
|
||||||
|
if (ACPI_FAILURE(res) || !obj || obj->Package.Count != 13) {
|
||||||
|
Genode::error("failed - '", __func__, "' _BIF res=", Genode::Hex(res));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Acpica::Buffer<char [8]> battery_name;
|
||||||
|
res = AcpiGetName(_sb, ACPI_SINGLE_NAME, &battery_name);
|
||||||
|
if (ACPI_FAILURE(res)) {
|
||||||
|
_battery_name = Genode::String<16>("unknown");
|
||||||
|
} else {
|
||||||
|
_battery_name = Genode::String<16>(battery_name.object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _info(Genode::Xml_generator &xml)
|
||||||
|
{
|
||||||
|
xml.node("name", [&] { xml.append(_battery_name.string()); });
|
||||||
|
|
||||||
|
const char * node_name[] = {
|
||||||
|
"powerunit", "design_capacity", "last_full_capacity",
|
||||||
|
"technology", "voltage", "warning_capacity", "low_capacity",
|
||||||
|
"granularity1", "granularity2", "serial", "model", "type",
|
||||||
|
"oem"
|
||||||
|
};
|
||||||
|
|
||||||
|
ACPI_OBJECT * obj = reinterpret_cast<ACPI_OBJECT *>(_battery.object);
|
||||||
|
|
||||||
|
if (sizeof(node_name) / sizeof(node_name[0]) != obj->Package.Count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < 9; i++) {
|
||||||
|
ACPI_OBJECT * v = &obj->Package.Elements[i];
|
||||||
|
|
||||||
|
xml.node(node_name[i], [&] {
|
||||||
|
if (v->Type != ACPI_TYPE_INTEGER) {
|
||||||
|
xml.append("unknown");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
xml.attribute("value", v->Integer.Value);
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
xml.append(v->Integer.Value == 0 ? "mW/mWh" :
|
||||||
|
v->Integer.Value == 1 ? "mA/mAh" :
|
||||||
|
"unknown");
|
||||||
|
if (i == 3)
|
||||||
|
xml.append(v->Integer.Value == 0 ? "primary" :
|
||||||
|
v->Integer.Value == 1 ? "secondary" :
|
||||||
|
"unknown");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 9; i < obj->Package.Count; i++) {
|
||||||
|
ACPI_OBJECT * v = &obj->Package.Elements[i];
|
||||||
|
|
||||||
|
xml.node(node_name[i], [&] {
|
||||||
|
|
||||||
|
if (v->Type != ACPI_TYPE_STRING)
|
||||||
|
return;
|
||||||
|
|
||||||
|
xml.append(v->String.Pointer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _status(Genode::Xml_generator &xml)
|
||||||
|
{
|
||||||
|
/* 10.2.2.6 _BST (Battery Status) */
|
||||||
|
Acpica::Buffer<char [256]> dynamic;
|
||||||
|
ACPI_STATUS res = AcpiEvaluateObjectTyped(_sb, ACPI_STRING("_BST"),
|
||||||
|
nullptr, &dynamic,
|
||||||
|
ACPI_TYPE_PACKAGE);
|
||||||
|
ACPI_OBJECT * obj = reinterpret_cast<ACPI_OBJECT *>(dynamic.object);
|
||||||
|
if (ACPI_FAILURE(res) || !obj ||
|
||||||
|
obj->Package.Count != 4) {
|
||||||
|
Genode::error("failed - '", __func__, "' _BST res=", Genode::Hex(res));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Acpica::Buffer<ACPI_OBJECT> sta;
|
||||||
|
res = AcpiEvaluateObjectTyped(_sb, ACPI_STRING("_STA"), nullptr,
|
||||||
|
&sta, ACPI_TYPE_INTEGER);
|
||||||
|
if (ACPI_FAILURE(res)) {
|
||||||
|
xml.node("status", [&] { xml.append("unknown"); });
|
||||||
|
} else
|
||||||
|
xml.node("status", [&] {
|
||||||
|
xml.attribute("value", sta.object.Integer.Value);
|
||||||
|
/* see "6.3.7 _STA" for more human readable decoding */
|
||||||
|
if (!(sta.object.Integer.Value & ACPI_STA_BATTERY_PRESENT))
|
||||||
|
xml.append("battery not present");
|
||||||
|
});
|
||||||
|
|
||||||
|
const char * node_name[] = {
|
||||||
|
"state", "present_rate", "remaining_capacity",
|
||||||
|
"present_voltage"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (sizeof(node_name) / sizeof(node_name[0]) != obj->Package.Count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < obj->Package.Count; i++) {
|
||||||
|
ACPI_OBJECT * v = &obj->Package.Elements[i];
|
||||||
|
|
||||||
|
xml.node(node_name[i], [&] {
|
||||||
|
if (v->Type != ACPI_TYPE_INTEGER) {
|
||||||
|
xml.append("unknown");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
xml.attribute("value", v->Integer.Value);
|
||||||
|
|
||||||
|
if (i != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (v->Integer.Value & 0x1) xml.append("discharging");
|
||||||
|
if (v->Integer.Value & 0x2) xml.append("charging");
|
||||||
|
if (v->Integer.Value & 0x4) xml.append("critical low");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Battery(void * report, ACPI_HANDLE sb)
|
Battery(void * report, ACPI_HANDLE sb)
|
||||||
: _report(reinterpret_cast<Acpica::Reportstate *>(report)), _sb(sb)
|
: _report(reinterpret_cast<Acpica::Reportstate *>(report)), _sb(sb)
|
||||||
{
|
{
|
||||||
|
_init_static_info();
|
||||||
if (_report)
|
if (_report)
|
||||||
_report->add_notify(this);
|
_report->add_notify(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle(ACPI_HANDLE sb, UINT32 value)
|
|
||||||
{
|
|
||||||
if (_report)
|
|
||||||
_report->battery_event();
|
|
||||||
}
|
|
||||||
|
|
||||||
static ACPI_STATUS detect(ACPI_HANDLE sb, UINT32, void *m, void **)
|
static ACPI_STATUS detect(ACPI_HANDLE sb, UINT32, void *m, void **)
|
||||||
{
|
{
|
||||||
Acpica::Main * main = reinterpret_cast<Acpica::Main *>(m);
|
Acpica::Main * main = reinterpret_cast<Acpica::Main *>(m);
|
||||||
Battery * dev_obj = new (main->heap) Battery(main->report, sb);
|
Battery * dev_obj = new (main->heap) Battery(main->report, sb);
|
||||||
|
|
||||||
ACPI_STATUS res = AcpiInstallNotifyHandler (sb, ACPI_DEVICE_NOTIFY,
|
ACPI_STATUS res =
|
||||||
handler, dev_obj);
|
AcpiInstallNotifyHandler(sb, ACPI_DEVICE_NOTIFY,
|
||||||
|
Acpica::Callback<Battery>::handler,
|
||||||
|
dev_obj);
|
||||||
if (ACPI_FAILURE(res)) {
|
if (ACPI_FAILURE(res)) {
|
||||||
Genode::error("failed - '", __func__, "' "
|
Genode::error("failed - '", __func__, "' "
|
||||||
"res=", Genode::Hex(res));
|
"res=", Genode::Hex(res));
|
||||||
@ -48,7 +179,7 @@ class Battery : Acpica::Callback<Battery> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Acpica::Buffer<char [8]> battery_name;
|
Acpica::Buffer<char [8]> battery_name;
|
||||||
AcpiGetName (sb, ACPI_SINGLE_NAME, &battery_name);
|
res = AcpiGetName (sb, ACPI_SINGLE_NAME, &battery_name);
|
||||||
if (ACPI_FAILURE(res)) {
|
if (ACPI_FAILURE(res)) {
|
||||||
Genode::error("failed - '", __func__, "' battery name "
|
Genode::error("failed - '", __func__, "' battery name "
|
||||||
"res=", Genode::Hex(res));
|
"res=", Genode::Hex(res));
|
||||||
@ -106,130 +237,19 @@ class Battery : Acpica::Callback<Battery> {
|
|||||||
return AE_OK;
|
return AE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Acpica::Callback<> interface
|
||||||
|
*/
|
||||||
|
|
||||||
|
void handle(ACPI_HANDLE sb, UINT32 value)
|
||||||
|
{
|
||||||
|
if (_report)
|
||||||
|
_report->battery_event();
|
||||||
|
}
|
||||||
|
|
||||||
void generate(Genode::Xml_generator &xml)
|
void generate(Genode::Xml_generator &xml)
|
||||||
{
|
{
|
||||||
info(xml);
|
_info(xml);
|
||||||
status(xml);
|
_status(xml);
|
||||||
}
|
|
||||||
|
|
||||||
void info(Genode::Xml_generator &xml)
|
|
||||||
{
|
|
||||||
/* ACPI spec - 10.2.2.1 _BIF (Battery Information) */
|
|
||||||
Acpica::Buffer<char [512]> battery;
|
|
||||||
ACPI_STATUS res = AcpiEvaluateObjectTyped(_sb, ACPI_STRING("_BIF"),
|
|
||||||
nullptr, &battery,
|
|
||||||
ACPI_TYPE_PACKAGE);
|
|
||||||
ACPI_OBJECT * obj = reinterpret_cast<ACPI_OBJECT *>(battery.object);
|
|
||||||
if (ACPI_FAILURE(res) || !obj || obj->Package.Count != 13) {
|
|
||||||
Genode::error("failed - '", __func__, "' _BIF res=", Genode::Hex(res));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Acpica::Buffer<char [8]> battery_name;
|
|
||||||
AcpiGetName (_sb, ACPI_SINGLE_NAME, &battery_name);
|
|
||||||
if (ACPI_FAILURE(res))
|
|
||||||
xml.node("name", [&] { xml.append("unknown"); });
|
|
||||||
else
|
|
||||||
xml.node("name", [&] { xml.append(battery_name.object); });
|
|
||||||
|
|
||||||
const char * node_name[] = {
|
|
||||||
"powerunit", "design_capacity", "last_full_capacity",
|
|
||||||
"technology", "voltage", "warning_capacity", "low_capacity",
|
|
||||||
"granularity1", "granularity2", "serial", "model", "type",
|
|
||||||
"oem"
|
|
||||||
};
|
|
||||||
|
|
||||||
if (sizeof(node_name) / sizeof(node_name[0]) != obj->Package.Count)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < 9; i++) {
|
|
||||||
ACPI_OBJECT * v = &obj->Package.Elements[i];
|
|
||||||
|
|
||||||
xml.node(node_name[i], [&] {
|
|
||||||
if (v->Type != ACPI_TYPE_INTEGER) {
|
|
||||||
xml.append("unknown");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
xml.attribute("value", v->Integer.Value);
|
|
||||||
|
|
||||||
if (i == 0)
|
|
||||||
xml.append(v->Integer.Value == 0 ? "mW/mWh" :
|
|
||||||
v->Integer.Value == 1 ? "mA/mAh" :
|
|
||||||
"unknown");
|
|
||||||
if (i == 3)
|
|
||||||
xml.append(v->Integer.Value == 0 ? "primary" :
|
|
||||||
v->Integer.Value == 1 ? "secondary" :
|
|
||||||
"unknown");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned i = 9; i < obj->Package.Count; i++) {
|
|
||||||
ACPI_OBJECT * v = &obj->Package.Elements[i];
|
|
||||||
|
|
||||||
xml.node(node_name[i], [&] {
|
|
||||||
|
|
||||||
if (v->Type != ACPI_TYPE_STRING)
|
|
||||||
return;
|
|
||||||
|
|
||||||
xml.append(v->String.Pointer);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void status(Genode::Xml_generator &xml)
|
|
||||||
{
|
|
||||||
/* 10.2.2.6 _BST (Battery Status) */
|
|
||||||
Acpica::Buffer<char [256]> dynamic;
|
|
||||||
ACPI_STATUS res = AcpiEvaluateObjectTyped(_sb, ACPI_STRING("_BST"),
|
|
||||||
nullptr, &dynamic,
|
|
||||||
ACPI_TYPE_PACKAGE);
|
|
||||||
ACPI_OBJECT * obj = reinterpret_cast<ACPI_OBJECT *>(dynamic.object);
|
|
||||||
if (ACPI_FAILURE(res) || !obj ||
|
|
||||||
obj->Package.Count != 4) {
|
|
||||||
Genode::error("failed - '", __func__, "' _BST res=", Genode::Hex(res));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Acpica::Buffer<ACPI_OBJECT> sta;
|
|
||||||
res = AcpiEvaluateObjectTyped(_sb, ACPI_STRING("_STA"), nullptr,
|
|
||||||
&sta, ACPI_TYPE_INTEGER);
|
|
||||||
if (ACPI_FAILURE(res)) {
|
|
||||||
xml.node("status", [&] { xml.append("unknown"); });
|
|
||||||
} else
|
|
||||||
xml.node("status", [&] {
|
|
||||||
xml.attribute("value", sta.object.Integer.Value);
|
|
||||||
/* see "6.3.7 _STA" for more human readable decoding */
|
|
||||||
if (!(sta.object.Integer.Value & ACPI_STA_BATTERY_PRESENT))
|
|
||||||
xml.append("battery not present");
|
|
||||||
});
|
|
||||||
|
|
||||||
const char * node_name[] = {
|
|
||||||
"state", "present_rate", "remaining_capacity",
|
|
||||||
"present_voltage"
|
|
||||||
};
|
|
||||||
|
|
||||||
if (sizeof(node_name) / sizeof(node_name[0]) != obj->Package.Count)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < obj->Package.Count; i++) {
|
|
||||||
ACPI_OBJECT * v = &obj->Package.Elements[i];
|
|
||||||
|
|
||||||
xml.node(node_name[i], [&] {
|
|
||||||
if (v->Type != ACPI_TYPE_INTEGER) {
|
|
||||||
xml.append("unknown");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
xml.attribute("value", v->Integer.Value);
|
|
||||||
|
|
||||||
if (i != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (v->Integer.Value & 0x1) xml.append("discharging");
|
|
||||||
if (v->Integer.Value & 0x2) xml.append("charging");
|
|
||||||
if (v->Integer.Value & 0x4) xml.append("critical low");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user