Merge "Calculate battery charge from energy and voltage"
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index a215592..fc47541 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -10204,6 +10204,12 @@
// Battery name, emitted only on multiple batteries.
optional string name = 5;
+
+ // Battery capacity in microwatt-hours(µWh).
+ optional int64 energy_counter_uwh = 6;
+
+ // Battery voltage in microvolts(µV).
+ optional int64 voltage_uv = 7;
}
// End of protos/perfetto/trace/power/battery_counters.proto
diff --git a/protos/perfetto/trace/power/battery_counters.proto b/protos/perfetto/trace/power/battery_counters.proto
index ab1aaa8..bb1a23c 100644
--- a/protos/perfetto/trace/power/battery_counters.proto
+++ b/protos/perfetto/trace/power/battery_counters.proto
@@ -35,4 +35,10 @@
// Battery name, emitted only on multiple batteries.
optional string name = 5;
+
+ // Battery capacity in microwatt-hours(µWh).
+ optional int64 energy_counter_uwh = 6;
+
+ // Battery voltage in microvolts(µV).
+ optional int64 voltage_uv = 7;
}
diff --git a/src/trace_processor/importers/proto/android_probes_parser.cc b/src/trace_processor/importers/proto/android_probes_parser.cc
index d4018e3..f85db0b 100644
--- a/src/trace_processor/importers/proto/android_probes_parser.cc
+++ b/src/trace_processor/importers/proto/android_probes_parser.cc
@@ -110,7 +110,18 @@
context_->track_tracker->InternGlobalCounterTrack(batt_charge_id);
context_->event_tracker->PushCounter(
ts, static_cast<double>(evt.charge_counter_uah()), track);
+ } else if (evt.has_energy_counter_uwh() && evt.has_voltage_uv()) {
+ // Calculate charge counter from energy counter and voltage.
+ TrackId track =
+ context_->track_tracker->InternGlobalCounterTrack(batt_charge_id);
+ auto energy = evt.energy_counter_uwh();
+ auto voltage = evt.voltage_uv();
+ if (voltage > 0) {
+ context_->event_tracker->PushCounter(
+ ts, static_cast<double>(energy * 1000000 / voltage), track);
+ }
}
+
if (evt.has_capacity_percent()) {
TrackId track =
context_->track_tracker->InternGlobalCounterTrack(batt_capacity_id);
diff --git a/src/traced/probes/power/linux_power_sysfs_data_source.cc b/src/traced/probes/power/linux_power_sysfs_data_source.cc
index b4bdec6..9d4365b 100644
--- a/src/traced/probes/power/linux_power_sysfs_data_source.cc
+++ b/src/traced/probes/power/linux_power_sysfs_data_source.cc
@@ -85,6 +85,21 @@
}
base::Optional<int64_t>
+LinuxPowerSysfsDataSource::BatteryInfo::GetEnergyCounterUah(
+ size_t battery_idx) {
+ PERFETTO_CHECK(battery_idx < sysfs_battery_subdirs_.size());
+ return ReadFileAsInt64(power_supply_dir_path_ + "/" +
+ sysfs_battery_subdirs_[battery_idx] + "/energy_now");
+}
+
+base::Optional<int64_t> LinuxPowerSysfsDataSource::BatteryInfo::GetVoltageUv(
+ size_t battery_idx) {
+ PERFETTO_CHECK(battery_idx < sysfs_battery_subdirs_.size());
+ return ReadFileAsInt64(power_supply_dir_path_ + "/" +
+ sysfs_battery_subdirs_[battery_idx] + "/voltage_now");
+}
+
+base::Optional<int64_t>
LinuxPowerSysfsDataSource::BatteryInfo::GetCapacityPercent(size_t battery_idx) {
PERFETTO_CHECK(battery_idx < sysfs_battery_subdirs_.size());
return ReadFileAsInt64(power_supply_dir_path_ + "/" +
@@ -174,6 +189,12 @@
value = battery_info_->GetAverageCurrentUa(battery_idx);
if (value)
counters_proto->set_current_ua(*value);
+ value = battery_info_->GetEnergyCounterUah(battery_idx);
+ if (value)
+ counters_proto->set_energy_counter_uwh(*value);
+ value = battery_info_->GetVoltageUv(battery_idx);
+ if (value)
+ counters_proto->set_voltage_uv(*value);
// On systems with multiple batteries, disambiguate with battery names.
if (battery_info_->num_batteries() > 1)
counters_proto->set_name(battery_info_->GetBatteryName(battery_idx));
diff --git a/src/traced/probes/power/linux_power_sysfs_data_source.h b/src/traced/probes/power/linux_power_sysfs_data_source.h
index d757b38..058ccd6 100644
--- a/src/traced/probes/power/linux_power_sysfs_data_source.h
+++ b/src/traced/probes/power/linux_power_sysfs_data_source.h
@@ -41,6 +41,12 @@
// The current coloumb counter value in µAh.
base::Optional<int64_t> GetChargeCounterUah(size_t battery_idx);
+ // The current energy counter in µWh.
+ base::Optional<int64_t> GetEnergyCounterUah(size_t battery_idx);
+
+ // The voltage in µV.
+ base::Optional<int64_t> GetVoltageUv(size_t battery_idx);
+
// The battery capacity in percent.
base::Optional<int64_t> GetCapacityPercent(size_t battery_idx);
diff --git a/src/traced/probes/power/linux_power_sysfs_data_source_unittest.cc b/src/traced/probes/power/linux_power_sysfs_data_source_unittest.cc
index ff98604..2c1c8aa 100644
--- a/src/traced/probes/power/linux_power_sysfs_data_source_unittest.cc
+++ b/src/traced/probes/power/linux_power_sysfs_data_source_unittest.cc
@@ -104,5 +104,41 @@
EXPECT_EQ(*battery_info_->GetChargeCounterUah(main_battery_idx), 3074000);
}
+TEST(LinuxPowerSysfsDataSourceTest, EnergyNow) {
+ base::TmpDirTree tmpdir;
+ std::unique_ptr<LinuxPowerSysfsDataSource::BatteryInfo> battery_info_;
+
+ tmpdir.AddDir("BAT0");
+ tmpdir.AddFile("BAT0/type", "Battery\n");
+ tmpdir.AddFile("BAT0/present", "1\n");
+ tmpdir.AddFile("BAT0/capacity", "95\n"); // 95 percent.
+ tmpdir.AddFile("BAT0/energy_now", "56680000\n"); // 56680000 µWh.
+
+ battery_info_.reset(
+ new LinuxPowerSysfsDataSource::BatteryInfo(tmpdir.path().c_str()));
+
+ EXPECT_EQ(battery_info_->num_batteries(), 1u);
+ EXPECT_EQ(*battery_info_->GetCapacityPercent(0), 95);
+ EXPECT_EQ(*battery_info_->GetEnergyCounterUah(0), 56680000);
+}
+
+TEST(LinuxPowerSysfsDataSourceTest, EnergyVoltageNow) {
+ base::TmpDirTree tmpdir;
+ std::unique_ptr<LinuxPowerSysfsDataSource::BatteryInfo> battery_info_;
+
+ tmpdir.AddDir("BAT0");
+ tmpdir.AddFile("BAT0/type", "Battery\n");
+ tmpdir.AddFile("BAT0/present", "1\n");
+ tmpdir.AddFile("BAT0/capacity", "95\n"); // 95 percent.
+ tmpdir.AddFile("BAT0/voltage_now", "17356000\n"); // Now at 17.356 µV.
+
+ battery_info_.reset(
+ new LinuxPowerSysfsDataSource::BatteryInfo(tmpdir.path().c_str()));
+
+ EXPECT_EQ(battery_info_->num_batteries(), 1u);
+ EXPECT_EQ(*battery_info_->GetCapacityPercent(0), 95);
+ EXPECT_EQ(*battery_info_->GetVoltageUv(0), 17356000);
+}
+
} // namespace
} // namespace perfetto
diff --git a/test/trace_processor/diff_tests/include_index.py b/test/trace_processor/diff_tests/include_index.py
index 09e084e..4367919 100644
--- a/test/trace_processor/diff_tests/include_index.py
+++ b/test/trace_processor/diff_tests/include_index.py
@@ -56,6 +56,7 @@
from diff_tests.performance.tests import Performance
from diff_tests.power.tests import Power
from diff_tests.power.tests_energy_breakdown import PowerEnergyBreakdown
+from diff_tests.power.tests_linux_sysfs_power import LinuxSysfsPower
from diff_tests.power.tests_power_rails import PowerPowerRails
from diff_tests.power.tests_voltage_and_scaling import PowerVoltageAndScaling
from diff_tests.process_tracking.tests import ProcessTracking
@@ -113,6 +114,7 @@
*GraphicsDrmRelatedFtraceEvents(index_path, 'graphics',
'GraphicsDrmRelatedFtraceEvents').fetch(),
*Ufs(index_path, 'ufs', 'Ufs').fetch(),
+ *LinuxSysfsPower(index_path, 'power', 'LinuxSysfsPower').fetch(),
*Memory(index_path, 'memory', 'Memory').fetch(),
*MemoryMetrics(index_path, 'memory', 'MemoryMetrics').fetch(),
*Network(index_path, 'network', 'Network').fetch(),
diff --git a/test/trace_processor/diff_tests/power/tests_linux_sysfs_power.py b/test/trace_processor/diff_tests/power/tests_linux_sysfs_power.py
new file mode 100644
index 0000000..fce058e
--- /dev/null
+++ b/test/trace_processor/diff_tests/power/tests_linux_sysfs_power.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python3
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License a
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from python.generators.diff_tests.testing import Path, DataPath, Metric
+from python.generators.diff_tests.testing import Csv, Json, TextProto
+from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import TestSuite
+
+
+class LinuxSysfsPower(TestSuite):
+
+ # Test basic battery counters.
+ def test_counters(self):
+ return DiffTestBlueprint(
+ trace=TextProto("""
+ packet {
+ timestamp: 3000000
+ battery {
+ charge_counter_uah: 3005000
+ capacity_percent: 100.000000
+ current_ua: 0
+ }
+ }
+ """),
+ query="""
+ SELECT * FROM (
+ (SELECT AVG(value) AS capacity_percent FROM counters
+ WHERE name='batt.capacity_pct'),
+ (SELECT AVG(value) AS charge_uah FROM counters
+ WHERE name='batt.charge_uah'),
+ (SELECT AVG(value) AS current_ua FROM counters
+ WHERE name='batt.current_ua')
+ );
+ """,
+ out=Csv("""
+ "capacity_percent","charge_uah","current_ua"
+ 100.000000,3005000.000000,0.000000
+ """))
+
+ # Test multiple batteries.
+ def test_multiple_batteries(self):
+ return DiffTestBlueprint(
+ trace=TextProto("""
+ packet {
+ timestamp: 3000000
+ battery {
+ charge_counter_uah: 3005000
+ capacity_percent: 100.000000
+ current_ua: 0
+ name: "BAT0"
+ }
+ }
+ packet {
+ timestamp: 3000000
+ battery {
+ capacity_percent: 90.000000
+ name: "BAT1"
+ }
+ }
+ """),
+ query="""
+ SELECT name, value FROM counters WHERE name like "batt.%" ORDER BY name
+ """,
+ out=Csv("""
+ "name","value"
+ "batt.BAT0.capacity_pct",100.000000
+ "batt.BAT0.charge_uah",3005000.000000
+ "batt.BAT0.current_ua",0.000000
+ "batt.BAT1.capacity_pct",90.000000
+ """))
+
+ # Test convertion to charge counter from energy and voltage.
+ def test_charge_from_energy_and_voltage(self):
+ return DiffTestBlueprint(
+ trace=TextProto("""
+ packet {
+ timestamp: 3000000
+ battery {
+ energy_counter_uwh: 56680000
+ voltage_uv: 17356000
+ }
+ }
+ packet {
+ timestamp: 4000000
+ battery {
+ energy_counter_uwh: 56600000
+ voltage_uv: 17356000
+ }
+ }
+ """),
+ query="""
+ SELECT value
+ FROM counters
+ WHERE name = "batt.charge_uah"
+ """,
+ out=Csv("""
+ "value"
+ 3265729.000000
+ 3261120.000000
+ """))
+
+ # Test convertion to charge counter from energy and voltage: bad voltage
+ # value.
+ def test_charge_from_energy_and_bad_voltage(self):
+ return DiffTestBlueprint(
+ trace=TextProto("""
+ packet {
+ timestamp: 3000000
+ battery {
+ energy_counter_uwh: 56680000
+ voltage_uv: 0
+ }
+ }
+ """),
+ query="""
+ SELECT value
+ FROM counters
+ WHERE name = "batt.charge_uah"
+ """,
+ out=Csv("""
+ "value"
+ """))