blob: 43267eec3a66bd7dae75f12060b8a0d073fa186b [file] [log] [blame]
# Copyright 2018 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
import numpy
import os
from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib.cros import tpm_utils
from autotest_lib.server import test, autotest
CLIENT_TEST_NAME = 'platform_InitLoginPerf'
STAGE_OOBE = 0
STAGE_REGULAR = 1
STAGE_NAME = ['oobe', 'regular']
BENCHMARKS = {
'initial_login': {'stage': STAGE_OOBE,
'name': 'login-duration',
'display': '1stLogin',
'units': 'seconds',
'upload': True},
'regular_login': {'stage': STAGE_REGULAR,
'name': 'login-duration',
'display': 'RegLogin',
'units': 'seconds',
'upload': True},
'prepare_attestation': {'stage': STAGE_OOBE,
'name': 'attestation-duration',
'display': 'PrepAttn',
'units': 'seconds',
'upload': True},
'take_ownership': {'stage': STAGE_OOBE,
'name': 'ownership-duration',
'display': 'TakeOwnp',
'units': 'seconds',
'upload': True},
}
class platform_InitLoginPerfServer(test.test):
"""Test to exercise and gather perf data for initialization and login."""
version = 1
def initialize(self):
"""Run before the first iteration."""
self.perf_results = {}
for bmname in BENCHMARKS:
self.perf_results[bmname] = []
def stage_args(self, stage):
"""Build arguments for the client-side test.
@param stage Stage of the test to get arguments for.
@return Dictionary of arguments.
"""
if stage == 0:
return {'perform_init': True,
'pre_init_delay': self.pre_init_delay}
else:
return {'perform_init': False}
def run_stage(self, stage):
"""Run the client-side test.
@param stage: Stage of the test to run.
"""
full_stage = 'iteration.%s/%s' % (self.iteration, STAGE_NAME[stage])
logging.info('Run stage %s', full_stage)
self.client_at.run_test(test_name=self.client_test,
results_dir=full_stage,
check_client_result=True,
**self.stage_args(stage))
client_keyval = os.path.join(self.outputdir, full_stage,
self.client_test, 'results', 'keyval')
self.client_results[stage] = utils.read_keyval(client_keyval,
type_tag='perf')
def save_perf_data(self):
"""Extract perf data from client-side test results."""
for bmname, bm in BENCHMARKS.iteritems():
try:
self.perf_results[bmname].append(
self.client_results[bm['stage']][bm['name']])
except:
logging.warning('Failed to extract %s from client results',
bmname)
self.perf_results[bmname].append(None)
pass
def output_benchmark(self, bmname):
"""Output a benchmark.
@param bmname: Name of the benchmark.
"""
bm = BENCHMARKS[bmname]
values = self.perf_results[bmname]
if not bm.get('upload', True):
return
self.output_perf_value(
description=bmname,
value=[x for x in values if x is not None],
units=bm.get('units', 'seconds'),
higher_is_better=False,
graph=self.graph_name)
def display_perf_headers(self):
"""Add headers for the results table to the info log."""
hdr = "# "
for bm in BENCHMARKS.itervalues():
hdr += bm['display'] + ' '
logging.info('# Results for delay = %.2f sec', self.pre_init_delay)
logging.info(hdr)
def display_perf_line(self, n):
"""Add one iteration results line to the info log.
@param n: Number of the iteration.
"""
line = "# "
for bmname in BENCHMARKS:
value = self.perf_results[bmname][n]
if value is None:
line += ' None '
else:
line += '%8.2f ' % value
logging.info(line)
def display_perf_stats(self, name, func):
""" Add results statistics line to the info log.
@param name: Name of the statistic.
@param func: Function to reduce the list of results.
"""
line = "# "
for bmname in BENCHMARKS:
line += '%8.2f ' % func(self.perf_results[bmname])
logging.info('# %s:', name)
logging.info(line)
def process_perf_data(self):
"""Process performance data from all iterations."""
logging.info('Process perf data')
logging.debug('Results: %s', self.perf_results)
if self.upload_perf:
for bmname in BENCHMARKS:
self.output_benchmark(bmname)
logging.info('##############################################')
self.display_perf_headers()
for iter in range(self.iteration - 1):
self.display_perf_line(iter)
self.display_perf_stats('Average', numpy.mean)
self.display_perf_stats('Min', min)
self.display_perf_stats('Max', max)
self.display_perf_stats('StdDev', lambda x: numpy.std(x, ddof=1))
logging.info('##############################################')
def run_once(self, host, pre_init_delay=0,
upload_perf=False, graph_name=None):
"""Run a single iteration.
@param pre_init_delay: Delay before initialization during first boot.
@param upload_perf: Do we need to upload the results?
@param graph_name: Graph name to use when uploading the results.
"""
if self.iteration is None:
self.iteration = 1
logging.info('Start iteration %s', self.iteration)
self.client = host
self.pre_init_delay = pre_init_delay
self.upload_perf = upload_perf
self.graph_name = graph_name
self.client_results = {}
self.client_test = CLIENT_TEST_NAME
self.client_at = autotest.Autotest(self.client)
logging.info('Clear the owner before the test')
tpm_utils.ClearTPMOwnerRequest(self.client, wait_for_ready=False)
self.run_stage(STAGE_OOBE)
self.client.reboot()
self.run_stage(STAGE_REGULAR)
self.save_perf_data()
def postprocess(self):
"""Run after all iterations in case of success."""
self.process_perf_data()
def cleanup(self):
"""Run at the end regardless of success."""
logging.info('Cleanup')
tpm_utils.ClearTPMOwnerRequest(self.client, wait_for_ready=False)