From ce149397ecd40ca95a99d837f431a4d06199b4ba Mon Sep 17 00:00:00 2001 From: Christian Helmuth Date: Thu, 18 Jul 2019 14:29:18 +0200 Subject: [PATCH] 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 --- repos/libports/src/app/acpica/sb.h | 288 +++++++++++++++-------------- 1 file changed, 154 insertions(+), 134 deletions(-) diff --git a/repos/libports/src/app/acpica/sb.h b/repos/libports/src/app/acpica/sb.h index f48fab1e82..b9e8e25a20 100644 --- a/repos/libports/src/app/acpica/sb.h +++ b/repos/libports/src/app/acpica/sb.h @@ -11,35 +11,166 @@ * under the terms of the GNU Affero General Public License version 3. */ -class Battery : Acpica::Callback { - +class Battery : Acpica::Callback +{ private: Acpica::Reportstate * _report; ACPI_HANDLE _sb; + /* + * ACPI spec - 10.2.2.1 _BIF (Battery Information) + * (alternatively 10.2.2.2 _BIX could be used) + */ + Acpica::Buffer _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(_battery.object); + if (ACPI_FAILURE(res) || !obj || obj->Package.Count != 13) { + Genode::error("failed - '", __func__, "' _BIF res=", Genode::Hex(res)); + return; + } + + Acpica::Buffer 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(_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 dynamic; + ACPI_STATUS res = AcpiEvaluateObjectTyped(_sb, ACPI_STRING("_BST"), + nullptr, &dynamic, + ACPI_TYPE_PACKAGE); + ACPI_OBJECT * obj = reinterpret_cast(dynamic.object); + if (ACPI_FAILURE(res) || !obj || + obj->Package.Count != 4) { + Genode::error("failed - '", __func__, "' _BST res=", Genode::Hex(res)); + return; + } + + Acpica::Buffer 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: Battery(void * report, ACPI_HANDLE sb) : _report(reinterpret_cast(report)), _sb(sb) { + _init_static_info(); if (_report) _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 **) { Acpica::Main * main = reinterpret_cast(m); Battery * dev_obj = new (main->heap) Battery(main->report, sb); - ACPI_STATUS res = AcpiInstallNotifyHandler (sb, ACPI_DEVICE_NOTIFY, - handler, dev_obj); + ACPI_STATUS res = + AcpiInstallNotifyHandler(sb, ACPI_DEVICE_NOTIFY, + Acpica::Callback::handler, + dev_obj); if (ACPI_FAILURE(res)) { Genode::error("failed - '", __func__, "' " "res=", Genode::Hex(res)); @@ -48,7 +179,7 @@ class Battery : Acpica::Callback { } Acpica::Buffer battery_name; - AcpiGetName (sb, ACPI_SINGLE_NAME, &battery_name); + res = AcpiGetName (sb, ACPI_SINGLE_NAME, &battery_name); if (ACPI_FAILURE(res)) { Genode::error("failed - '", __func__, "' battery name " "res=", Genode::Hex(res)); @@ -106,130 +237,19 @@ class Battery : Acpica::Callback { return AE_OK; } + /* + * Acpica::Callback<> interface + */ + + void handle(ACPI_HANDLE sb, UINT32 value) + { + if (_report) + _report->battery_event(); + } + void generate(Genode::Xml_generator &xml) { - info(xml); - status(xml); - } - - void info(Genode::Xml_generator &xml) - { - /* ACPI spec - 10.2.2.1 _BIF (Battery Information) */ - Acpica::Buffer battery; - ACPI_STATUS res = AcpiEvaluateObjectTyped(_sb, ACPI_STRING("_BIF"), - nullptr, &battery, - ACPI_TYPE_PACKAGE); - ACPI_OBJECT * obj = reinterpret_cast(battery.object); - if (ACPI_FAILURE(res) || !obj || obj->Package.Count != 13) { - Genode::error("failed - '", __func__, "' _BIF res=", Genode::Hex(res)); - return; - } - - Acpica::Buffer 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 dynamic; - ACPI_STATUS res = AcpiEvaluateObjectTyped(_sb, ACPI_STRING("_BST"), - nullptr, &dynamic, - ACPI_TYPE_PACKAGE); - ACPI_OBJECT * obj = reinterpret_cast(dynamic.object); - if (ACPI_FAILURE(res) || !obj || - obj->Package.Count != 4) { - Genode::error("failed - '", __func__, "' _BST res=", Genode::Hex(res)); - return; - } - - Acpica::Buffer 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"); - }); - } + _info(xml); + _status(xml); } };