Path: blob/master/AndroidRunner/Plugins/android/Android.py
907 views
import csv1import os2import os.path as op3import threading4import time5import timeit6from collections import OrderedDict7from functools import reduce89from AndroidRunner import util10from AndroidRunner import Tests11from AndroidRunner.Plugins.Profiler import Profiler121314class Android(Profiler):15def __init__(self, config, paths):16super(Android, self).__init__(config, paths)17self.output_dir = ''18self.paths = paths19self.profile = False20available_data_points = ['cpu', 'mem']21self.interval = float(Tests.is_integer(22config.get('sample_interval', 0))23) / 100024self.data_points = config['data_points']25invalid_data_points = [26dp for dp in config['data_points'] if dp not in set(available_data_points)]27if invalid_data_points:28self.logger.warning(29'Invalid data points in config: {}'.format(invalid_data_points))30self.data_points = [dp for dp in config['data_points']31if dp in set(available_data_points)]32self.data = [['datetime'] + self.data_points]33self.lock = threading.Lock()3435@staticmethod36def get_cpu_usage(device):37"""Get CPU usage in percentage"""38# return device.shell('dumpsys cpuinfo | grep TOTAL | cut -d" " -f1').strip()[:-1]39shell_result = device.shell('dumpsys cpuinfo | grep TOTAL')40shell_splitted = shell_result.split('%')[0]41if '.-' in shell_splitted:42shell_splitted = shell_splitted.replace('.-', '.')43return shell_splitted44# return device.shell('dumpsys cpuinfo | grep TOTAL').split('%')[0]4546@staticmethod47def get_mem_usage(device, app):48"""Get memory usage in KB for app, if app is None system usage is used"""49if not app:50# return device.shell('dumpsys meminfo | grep Used | cut -d" " -f5').strip()[1:-1]51# return device.shell('dumpsys meminfo | grep Used').split()[2].strip()[1:-1].replace(",", ".")52# https://stackoverflow.com/questions/23175809/str-translate-gives-typeerror-translate-takes-one-argument-2-given-worked-i53return device.shell('dumpsys meminfo | grep Used').translate(str.maketrans('', '', '(kB,K')).split()[2]54else:55result = device.shell(56'dumpsys meminfo {} | grep TOTAL'.format(app))57if result == '':58result = device.shell('dumpsys meminfo {}'.format(app))59if 'No process found' in result:60raise Exception('Android Profiler: {}'.format(result))61return ' '.join(result.strip().split()).split()[1]6263def start_profiling(self, device, **kwargs):64self.profile = True65self.data = [['datetime'] + self.data_points]66app = kwargs.get('app', None)67self.get_data(device, app)6869def get_data(self, device, app):70"""Runs the profiling methods every self.interval seconds in a separate thread"""71self.lock.acquire()72if not self.profile:73self.lock.release()74return75start = timeit.default_timer()76device_time = device.shell('date -u')77row = [device_time]78if 'cpu' in self.data_points:79row.append(self.get_cpu_usage(device))80if 'mem' in self.data_points:81row.append(self.get_mem_usage(device, app))82self.data.append(row)83end = timeit.default_timer()84# timer results could be negative85interval = max(float(0), self.interval - max(0, int(end - start)))86self.lock.release()87threading.Timer(interval, self.get_data, args=(device, app)).start()8889def stop_profiling(self, device, **kwargs):90self.lock.acquire()91self.profile = False92self.lock.release()9394def collect_results(self, device):95filename = '{}_{}.csv'.format(96device.id, time.strftime('%Y.%m.%d_%H%M%S'))97with open(op.join(self.output_dir, filename), 'w+') as f:98writer = csv.writer(f)99for row in self.data:100writer.writerow(row)101102def set_output(self, output_dir):103self.output_dir = output_dir104105def dependencies(self):106return []107108def load(self, device):109return110111def unload(self, device):112return113114def aggregate_subject(self):115filename = os.path.join(self.output_dir, 'Aggregated.csv')116subject_rows = list()117subject_rows.append(self.aggregate_android_subject(self.output_dir))118119util.write_to_file(filename, subject_rows)120121def aggregate_end(self, data_dir, output_file):122rows = self.aggregate_final(data_dir)123124util.write_to_file(output_file, rows)125126@staticmethod127def aggregate_android_subject(logs_dir):128def add_row(accum, new):129row = {k: v + float(new[k]) for k, v in list(accum.items())130if k not in ['Component', 'count']}131count = accum['count'] + 1132return dict(row, **{'count': count})133134runs = []135for run_file in [f for f in os.listdir(logs_dir) if os.path.isfile(os.path.join(logs_dir, f))]:136with open(os.path.join(logs_dir, run_file), 'r') as run:137reader = csv.DictReader(run)138init = dict(139{fn: 0 for fn in reader.fieldnames if fn != 'datetime'}, **{'count': 0})140run_total = reduce(add_row, reader, init)141runs.append(142{k: v / run_total['count'] for k, v in list(run_total.items()) if k != 'count'})143runs_total = reduce(144lambda x, y: {k: v + y[k] for k, v in list(x.items())}, runs)145return OrderedDict(146sorted(list({'android_' + k: v / len(runs) for k, v in list(runs_total.items())}.items()), key=lambda x: x[0]))147148def aggregate_final(self, data_dir):149rows = []150for device in util.list_subdir(data_dir):151row = OrderedDict({'device': device})152device_dir = os.path.join(data_dir, device)153for subject in util.list_subdir(device_dir):154row.update({'subject': subject})155subject_dir = os.path.join(device_dir, subject)156if os.path.isdir(os.path.join(subject_dir, 'android')):157row.update(self.aggregate_android_final(158os.path.join(subject_dir, 'android')))159rows.append(row.copy())160else:161for browser in util.list_subdir(subject_dir):162row.update({'browser': browser})163browser_dir = os.path.join(subject_dir, browser)164if os.path.isdir(os.path.join(browser_dir, 'android')):165row.update(self.aggregate_android_final(166os.path.join(browser_dir, 'android')))167rows.append(row.copy())168return rows169170@staticmethod171def aggregate_android_final(logs_dir):172for aggregated_file in [f for f in os.listdir(logs_dir) if os.path.isfile(os.path.join(logs_dir, f))]:173if aggregated_file == "Aggregated.csv":174with open(os.path.join(logs_dir, aggregated_file), 'r') as aggregated:175reader = csv.DictReader(aggregated)176row_dict = OrderedDict()177for row in reader:178for f in reader.fieldnames:179row_dict.update({f: row[f]})180return OrderedDict(row_dict)181182