autotest: Log battery info for analysis
BUG=b:163572001
TEST=run local repair
Change-Id: I351010bd51b3e1d53dba8e22787605b0eefe26a7
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/autotest/+/2434491
Tested-by: Otabek Kasimov <otabek@google.com>
Reviewed-by: Garry Wang <xianuowang@chromium.org>
Commit-Queue: Otabek Kasimov <otabek@google.com>
diff --git a/server/hosts/cros_repair.py b/server/hosts/cros_repair.py
index 372d0bd..e649a68 100644
--- a/server/hosts/cros_repair.py
+++ b/server/hosts/cros_repair.py
@@ -10,6 +10,7 @@
import json
import logging
import time
+import math
import common
from autotest_lib.client.common_lib import error
@@ -100,6 +101,9 @@
# Battery discharging state in power_supply_info file.
BATTERY_DISCHARGING = 'Discharging'
+ # Power controller can discharge battery any time till 90% for any model.
+ # Setting level to 85% in case we have wearout of it.
+ BATTERY_DISCHARGE_MIN = 85
@timeout_util.TimeoutDecorator(cros_constants.VERIFY_TIMEOUT_SEC)
def verify(self, host):
@@ -129,7 +133,21 @@
def _validate_battery(self, host, info):
try:
charging_state = info['Battery']['state']
- if charging_state == self.BATTERY_DISCHARGING:
+ battery_level = float(info['Battery']['percentage'])
+
+ # Collect info to determine which battery level is better to call
+ # as MIN_BATTERY_LEVEL for DUTs in the lab.
+ battery_level_by_10 = int(math.floor(battery_level / 10.0)) * 10
+ metrics_data = {
+ 'model': host.host_info_store.get().model,
+ 'level': battery_level_by_10,
+ 'mode': charging_state
+ }
+ metrics.Counter('chromeos/autotest/battery/state').increment(
+ fields=metrics_data)
+
+ if (charging_state == self.BATTERY_DISCHARGING
+ and battery_level < self.BATTERY_DISCHARGE_MIN):
logging.debug('Try to fix discharging state of the battery. '
'Possible that a test left wrong state.')
# Here is the chance that battery is discharging because
@@ -137,19 +155,20 @@
# We are going to try to fix it by set charging to normal.
host.run('ectool chargecontrol normal', ignore_status=True)
# wait to change state.
- time.sleep(5)
+ time.sleep(10)
info = self._load_info(host)
charging_state = info['Battery']['state']
fixed = charging_state != self.BATTERY_DISCHARGING
# TODO (@otabek) remove metrics after research
- metrics_data = {'host': host.hostname,
- 'model': host.host_info_store.get().model,
- 'fixed': fixed}
+ logging.debug('Fixed battery discharge mode.')
+ metrics_data = {
+ 'model': host.host_info_store.get().model,
+ 'fixed': fixed
+ }
metrics.Counter(
'chromeos/autotest/repair/chargecontrol_fixed'
).increment(fields=metrics_data)
- battery_level = float(info['Battery']['percentage'])
if (battery_level < MIN_BATTERY_LEVEL and
charging_state == self.BATTERY_DISCHARGING):
# TODO(@xianuowang) remove metrics here once we have device
diff --git a/server/hosts/servo_repair.py b/server/hosts/servo_repair.py
index 1de4b4c..cb794a6 100644
--- a/server/hosts/servo_repair.py
+++ b/server/hosts/servo_repair.py
@@ -10,6 +10,7 @@
import sys
import functools
import logging
+import math
import time
import common
@@ -583,6 +584,63 @@
return 'pwr_button control is normal'
+class _BatteryVerifier(hosts.Verifier):
+ """Collect battery info for analysis."""
+
+ @ignore_exception_for_non_cros_host
+ @timeout_util.TimeoutDecorator(cros_constants.VERIFY_TIMEOUT_SEC)
+ def verify(self, host):
+ try:
+ servo = host.get_servo()
+ charging = False
+ if servo.has_control('battery_is_charging'):
+ charging = servo.get('battery_is_charging')
+ level = -1
+ if servo.has_control('battery_charge_percent'):
+ level = servo.get('battery_charge_percent')
+ design_mah = servo.get('battery_full_design_mah')
+ charge_mah = servo.get('battery_full_charge_mah')
+ logging.info('Charging: %s', charging)
+ logging.info('Percentage: %s', level)
+ logging.info('Full charge max: %s', charge_mah)
+ logging.info('Full design max: %s', design_mah)
+ # based on analysis of ratio we can find out what is
+ # the level when we can say that battery is dead
+ ratio = int(math.floor(charge_mah / design_mah * 100.0))
+ logging.info('Ratio: %s', ratio)
+ data = {
+ 'board': host.servo_board or 'unknown',
+ 'model': host.servo_model or 'unknown',
+ 'ratio': ratio
+ }
+ metrics.Counter('chromeos/autotest/battery/ratio').increment(
+ fields=data)
+ except Exception as e:
+ # Keeping it with info level because we do not expect it.
+ logging.info('(Not critical) %s', e)
+
+ def _is_applicable(self, host):
+ if not host.is_ec_supported():
+ logging.info('The board not support EC')
+ return False
+ dut_info = host.get_dut_host_info()
+ if dut_info:
+ host_info = host.get_dut_host_info()
+ if host_info.get_label_value('power') != 'battery':
+ logging.info('The board does not have battery')
+ return False
+ servo = host.get_servo()
+ if (not servo.has_control('battery_full_design_mah')
+ or not servo.has_control('battery_full_charge_mah')):
+ logging.info('The board is not supported battery controls...')
+ return False
+ return True
+
+ @property
+ def description(self):
+ return 'Logs battery levels'
+
+
class _LidVerifier(hosts.Verifier):
"""
Verifier to check sanity of the `lid_open` signal.
@@ -832,6 +890,7 @@
(_ServodControlVerifier, 'servod_control', ['servod_connection']),
(_DUTConnectionVerifier, 'dut_connected', ['servod_connection']),
(_PowerButtonVerifier, 'pwr_button', ['dut_connected']),
+ (_BatteryVerifier, 'battery', ['dut_connected']),
(_LidVerifier, 'lid_open', ['dut_connected']),
(_EcBoardVerifier, 'ec_board', ['dut_connected']),
(_CCDTestlabVerifier, 'ccd_testlab', ['dut_connected']),