generic-poky/meta/lib/oeqa/buildperf/base.py

123 lines
4.0 KiB
Python
Raw Normal View History

# Copyright (c) 2016, Intel Corporation.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms and conditions of the GNU General Public License,
# version 2, as published by the Free Software Foundation.
#
# This program is distributed in the hope it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
"""Build performance test base classes and functionality"""
import logging
import os
import shutil
import time
from datetime import datetime
from oeqa.utils.commands import runCmd, get_bb_vars
# Get logger for this module
log = logging.getLogger('build-perf')
class KernelDropCaches(object):
"""Container of the functions for dropping kernel caches"""
sudo_passwd = None
@classmethod
def check(cls):
"""Check permssions for dropping kernel caches"""
from getpass import getpass
from locale import getdefaultlocale
cmd = ['sudo', '-k', '-n', 'tee', '/proc/sys/vm/drop_caches']
ret = runCmd(cmd, ignore_status=True, data=b'0')
if ret.output.startswith('sudo:'):
pass_str = getpass(
"\nThe script requires sudo access to drop caches between "
"builds (echo 3 > /proc/sys/vm/drop_caches).\n"
"Please enter your sudo password: ")
cls.sudo_passwd = bytes(pass_str, getdefaultlocale()[1])
@classmethod
def drop(cls):
"""Drop kernel caches"""
cmd = ['sudo', '-k']
if cls.sudo_passwd:
cmd.append('-S')
input_data = cls.sudo_passwd + b'\n'
else:
cmd.append('-n')
input_data = b''
cmd += ['tee', '/proc/sys/vm/drop_caches']
input_data += b'3'
runCmd(cmd, data=input_data)
class BuildPerfTest(object):
"""Base class for build performance tests"""
name = None
description = None
def __init__(self, out_dir):
self.out_dir = out_dir
self.results = {'name':self.name,
'description': self.description,
'status': 'NOTRUN',
'start_time': None,
'elapsed_time': None,
'measurements': []}
if not os.path.exists(self.out_dir):
os.makedirs(self.out_dir)
if not self.name:
self.name = self.__class__.__name__
self.bb_vars = get_bb_vars()
def run(self):
"""Run test"""
self.results['status'] = 'FAILED'
self.results['start_time'] = datetime.now()
self._run()
self.results['elapsed_time'] = (datetime.now() -
self.results['start_time'])
# Test is regarded as completed if it doesn't raise an exception
self.results['status'] = 'COMPLETED'
def _run(self):
"""Actual test payload"""
raise NotImplementedError
@staticmethod
def force_rm(path):
"""Equivalent of 'rm -rf'"""
if os.path.isfile(path) or os.path.islink(path):
os.unlink(path)
elif os.path.isdir(path):
shutil.rmtree(path)
def rm_tmp(self):
"""Cleanup temporary/intermediate files and directories"""
log.debug("Removing temporary and cache files")
for name in ['bitbake.lock', 'conf/sanity_info',
self.bb_vars['TMPDIR']]:
self.force_rm(name)
def rm_sstate(self):
"""Remove sstate directory"""
log.debug("Removing sstate-cache")
self.force_rm(self.bb_vars['SSTATE_DIR'])
def rm_cache(self):
"""Drop bitbake caches"""
self.force_rm(self.bb_vars['PERSISTENT_DIR'])
@staticmethod
def sync():
"""Sync and drop kernel caches"""
log.debug("Syncing and dropping kernel caches""")
KernelDropCaches.drop()
os.sync()
# Wait a bit for all the dirty blocks to be written onto disk
time.sleep(3)