diff options
author | Yan Wang <yawanng@google.com> | 2019-07-02 15:46:34 -0700 |
---|---|---|
committer | Yan Wang <yawanng@google.com> | 2019-07-11 11:40:04 -0700 |
commit | 7af0155c4177cc29b1417b0ccac3622babb6274b (patch) | |
tree | 2eda56aaa47bd4fafc13fbf81689af5f78637fa7 /startop/scripts/app_startup/lib/args_utils.py | |
parent | 3fb2816c59b8c99d1be7ba0f96560e4262dda8a1 (diff) |
startop: Rewrite app startup runner to use new python run_app_with_prefetch.
Test: pytest app_startup_runner_test.py
Test: pytest lib/args_utils_test.py
Test: pytest lib/data_frame_test.py
Test: ./app_startup_runner.py --package com.google.android.music --readahead fadvise --readahead cold --inodes textcache --output output.txt -d -lc 3
Change-Id: Ide9abe4ff3d7179e6830a7866b0eb90cc67d8e40
Bug: 137216480
Diffstat (limited to 'startop/scripts/app_startup/lib/args_utils.py')
-rw-r--r-- | startop/scripts/app_startup/lib/args_utils.py | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/startop/scripts/app_startup/lib/args_utils.py b/startop/scripts/app_startup/lib/args_utils.py new file mode 100644 index 000000000000..080f3b53157b --- /dev/null +++ b/startop/scripts/app_startup/lib/args_utils.py @@ -0,0 +1,77 @@ +import itertools +import os +import sys +from typing import Any, Callable, Dict, Iterable, List, NamedTuple, Tuple, \ + TypeVar, Optional + +# local import +sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname( + os.path.abspath(__file__))))) +import lib.print_utils as print_utils + +T = TypeVar('T') +NamedTupleMeta = Callable[ + ..., T] # approximation of a (S : NamedTuple<T> where S() == T) metatype. +FilterFuncType = Callable[[NamedTuple], bool] + +def dict_lookup_any_key(dictionary: dict, *keys: List[Any]): + for k in keys: + if k in dictionary: + return dictionary[k] + + + print_utils.debug_print("None of the keys {} were in the dictionary".format( + keys)) + return [None] + +def generate_run_combinations(named_tuple: NamedTupleMeta[T], + opts_dict: Dict[str, List[Optional[object]]], + loop_count: int = 1) -> Iterable[T]: + """ + Create all possible combinations given the values in opts_dict[named_tuple._fields]. + + :type T: type annotation for the named_tuple type. + :param named_tuple: named tuple type, whose fields are used to make combinations for + :param opts_dict: dictionary of keys to value list. keys correspond to the named_tuple fields. + :param loop_count: number of repetitions. + :return: an iterable over named_tuple instances. + """ + combinations_list = [] + for k in named_tuple._fields: + # the key can be either singular or plural , e.g. 'package' or 'packages' + val = dict_lookup_any_key(opts_dict, k, k + "s") + + # treat {'x': None} key value pairs as if it was [None] + # otherwise itertools.product throws an exception about not being able to iterate None. + combinations_list.append(val or [None]) + + print_utils.debug_print("opts_dict: ", opts_dict) + print_utils.debug_print_nd("named_tuple: ", named_tuple) + print_utils.debug_print("combinations_list: ", combinations_list) + + for i in range(loop_count): + for combo in itertools.product(*combinations_list): + yield named_tuple(*combo) + +def filter_run_combinations(named_tuple: NamedTuple, + filters: List[FilterFuncType]) -> bool: + for filter in filters: + if filter(named_tuple): + return False + return True + +def generate_group_run_combinations(run_combinations: Iterable[NamedTuple], + dst_nt: NamedTupleMeta[T]) \ + -> Iterable[Tuple[T, Iterable[NamedTuple]]]: + def group_by_keys(src_nt): + src_d = src_nt._asdict() + # now remove the keys that aren't legal in dst. + for illegal_key in set(src_d.keys()) - set(dst_nt._fields): + if illegal_key in src_d: + del src_d[illegal_key] + + return dst_nt(**src_d) + + for args_list_it in itertools.groupby(run_combinations, group_by_keys): + (group_key_value, args_it) = args_list_it + yield (group_key_value, args_it) |