Path: blob/master/tests/unit/fixtures/Android1.py
908 views
import csv1import os2import os.path as op3import threading4import time5import timeit6from collections import OrderedDict78from .Profiler import Profiler9from functools import reduce101112class ConfigError(Exception):13pass141516class Android1(Profiler):17def __init__(self, config, paths):18super(Android1, self).__init__(config, paths)19self.output_dir = ''20self.paths = paths21self.profile = False22available_data_points = ['cpu', 'mem']23self.interval = float(self.is_integer(config.get('sample_interval', 0))) / 100024self.data_points = config['data_points']25invalid_data_points = [dp for dp in config['data_points'] if dp not in set(available_data_points)]26if invalid_data_points:27self.logger.warning('Invalid data points in config: {}'.format(invalid_data_points))28self.data_points = [dp for dp in config['data_points'] if dp in set(available_data_points)]29self.data = [['datetime'] + self.data_points]3031@staticmethod32def get_cpu_usage(device):33"""Get CPU usage in percentage"""34# return device.shell('dumpsys cpuinfo | grep TOTAL | cut -d" " -f1').strip()[:-1]35shell_result = device.shell('dumpsys cpuinfo | grep TOTAL')36shell_splitted = shell_result.split('%')[0]37if '-' in shell_splitted:38print(shell_result)39print(shell_splitted)40return shell_splitted41# return device.shell('dumpsys cpuinfo | grep TOTAL').split('%')[0]4243@staticmethod44def get_mem_usage(device, app):45"""Get memory usage in KB for app, if app is None system usage is used"""46if not app:47# return device.shell('dumpsys meminfo | grep Used | cut -d" " -f5').strip()[1:-1]48# return device.shell('dumpsys meminfo | grep Used').split()[2].strip()[1:-1].replace(",", ".")49return device.shell('dumpsys meminfo | grep Used').translate(None, '(kB,K').split()[2]50else:51result = device.shell('dumpsys meminfo {} | grep TOTAL'.format(app))52if 'No process found' in result:53raise Exception('Android Profiler: {}'.format(result))54return ' '.join(result.strip().split()).split()[1]5556def start_profiling(self, device, **kwargs):57self.profile = True58app = kwargs.get('app', None)59self.get_data(device, app)6061def get_data(self, device, app):62"""Runs the profiling methods every self.interval seconds in a separate thread"""63start = timeit.default_timer()64device_time = device.shell('date -u')65row = [device_time]66if 'cpu' in self.data_points:67row.append(self.get_cpu_usage(device))68if 'mem' in self.data_points:69row.append(self.get_mem_usage(device, app))70self.data.append(row)71end = timeit.default_timer()72# timer results could be negative73interval = max(float(0), self.interval - max(0, int(end - start)))74if self.profile:75threading.Timer(interval, self.get_data, args=(device, app)).start()7677def stop_profiling(self, device, **kwargs):78self.profile = False7980def collect_results(self, device, path=None):81filename = '{}_{}.csv'.format(device.id, time.strftime('%Y.%m.%d_%H%M%S'))82with open(op.join(self.output_dir, filename), 'w+') as f:83writer = csv.writer(f)84for row in self.data:85writer.writerow(row)8687def set_output(self, output_dir):88self.output_dir = output_dir8990def dependencies(self):91return ['android1.test.dependency']9293def load(self, device):94return9596def unload(self, device):97return9899def aggregate_subject(self):100filename = os.path.join(self.output_dir, 'Aggregated.csv')101subject_rows = list()102subject_rows.append(self.aggregate_android_subject(self.output_dir))103self.write_to_file(filename, subject_rows)104105def aggregate_end(self, data_dir, output_file):106rows = self.aggregate_final(data_dir)107self.write_to_file(output_file, rows)108109@staticmethod110def aggregate_android_subject(logs_dir):111def add_row(accum, new):112row = {k: v + float(new[k]) for k, v in list(accum.items()) if k not in ['Component', 'count']}113count = accum['count'] + 1114return dict(row, **{'count': count})115116runs = []117for run_file in [f for f in os.listdir(logs_dir) if os.path.isfile(os.path.join(logs_dir, f))]:118with open(os.path.join(logs_dir, run_file), 'rb') as run:119reader = csv.DictReader(run)120init = dict({fn: 0 for fn in reader.fieldnames if fn != 'datetime'}, **{'count': 0})121run_total = reduce(add_row, reader, init)122runs.append({k: v / run_total['count'] for k, v in list(run_total.items()) if k != 'count'})123runs_total = reduce(lambda x, y: {k: v + y[k] for k, v in list(x.items())}, runs)124return OrderedDict(125sorted(list({'android_' + k: v / len(runs) for k, v in list(runs_total.items())}.items()), key=lambda x: x[0]))126127def aggregate_final(self, data_dir):128rows = []129for device in self.list_subdir(data_dir):130row = OrderedDict({'device': device})131device_dir = os.path.join(data_dir, device)132for subject in self.list_subdir(device_dir):133row.update({'subject': subject})134subject_dir = os.path.join(device_dir, subject)135if os.path.isdir(os.path.join(subject_dir, 'android')):136row.update(self.aggregate_android_final(os.path.join(subject_dir, 'android')))137rows.append(row.copy())138else:139for browser in self.list_subdir(subject_dir):140row.update({'browser': browser})141browser_dir = os.path.join(subject_dir, browser)142if os.path.isdir(os.path.join(browser_dir, 'android')):143row.update(self.aggregate_android_final(os.path.join(browser_dir, 'android')))144rows.append(row.copy())145return rows146147@staticmethod148def aggregate_android_final(logs_dir):149for aggregated_file in [f for f in os.listdir(logs_dir) if os.path.isfile(os.path.join(logs_dir, f))]:150if aggregated_file == "Aggregated.csv":151with open(os.path.join(logs_dir, aggregated_file), 'rb') as aggregated:152reader = csv.DictReader(aggregated)153row_dict = OrderedDict()154for row in reader:155for f in reader.fieldnames:156row_dict.update({f: row[f]})157return OrderedDict(row_dict)158159@staticmethod160def list_subdir(a_dir):161"""List immediate subdirectories of a_dir"""162# https://stackoverflow.com/a/800201163return [name for name in os.listdir(a_dir)164if os.path.isdir(os.path.join(a_dir, name))]165166@staticmethod167def write_to_file(filename, rows):168with open(filename, 'w') as f:169writer = csv.DictWriter(f, list(rows[0].keys()))170writer.writeheader()171writer.writerows(rows)172173@staticmethod174def is_integer(number, minimum=0):175if not isinstance(number, int):176raise ConfigError('%s is not an integer' % number)177if number < minimum:178raise ConfigError('%s should be equal or larger than %i' % (number, minimum))179return number180181182