diff --git a/libs/utils/conf.py b/libs/utils/conf.py index dc19b2d92dcb43ec3e572b4873489d02b5ad19f2..feb4140ab3c7d0b5555df0b94d8b2f70763850b3 100644 --- a/libs/utils/conf.py +++ b/libs/utils/conf.py @@ -51,20 +51,38 @@ class LisaLogging(object): logging.info(' %s', filepath) class JsonConf(object): + """ + Class for parsing a JSON superset with comments. + + Simply strips comments and then uses the standard JSON parser. + + :param filename: Path to file to parse + :type filename: str + """ def __init__(self, filename): self.filename = filename self.json = None def load(self): - """ Parse a JSON file - First remove comments and then use the json module package - Comments look like : - // ... - or - /* - ... - */ + """ + Parse a JSON file + + First remove comments and then use the json module package + Comments look like : + + :: + + // ... + + or + + :: + + /* + ... + */ + """ # Setup logging @@ -100,6 +118,9 @@ class JsonConf(object): return self.json def show(self): + """ + Pretty-print content of parsed JSON + """ print json.dumps(self.json, indent=4) # Regular expression for comments diff --git a/libs/utils/env.py b/libs/utils/env.py index bed90ee7db99558208091a6b76162684209cf932..41eb51d1cbeab198891879598f5555eb6d9eaa79 100644 --- a/libs/utils/env.py +++ b/libs/utils/env.py @@ -54,39 +54,105 @@ class ShareState(object): self.__dict__ = self.__shared_state class TestEnv(ShareState): + """ + Represents the environment configuring LISA, the target, and the test setup + + The test environment is defined by: + + - a target configuration (target_conf) defining which HW platform we + want to use to run the experiments + - a test configuration (test_conf) defining which SW setups we need on + that HW target + - a folder to collect the experiments results, which can be specified + using the test_conf::results_dir option and is by default wiped from + all the previous contents (if wipe=True) + + :param target_conf: + Configuration defining the target to run experiments on. May be + + - A dict defining the values directly + - A path to a JSON file containing the configuration + - ``None``, in which case $LISA_HOME/target.config is used. + + You need to provide the information needed to connect to the + target. For SSH targets that means "host", "username" and + either "password" or "keyfile". All other fields are optional if + the relevant features aren't needed. Has the following keys: + + **host** + Target IP or MAC address for SSH access + **username** + For SSH access + **keyfile** + Path to SSH key (alternative to password) + **password** + SSH password (alternative to keyfile) + **device** + Target Android device ID if using ADB + **port** + Port for Android connection default port is 5555 + **ANDROID_HOME** + Path to Android SDK. Defaults to ``$ANDROID_HOME`` from the + environment. + **rtapp-calib** + Calibration values for RT-App. If unspecified, LISA will + calibrate RT-App on the target. A message will be logged with + a value that can be copied here to avoid having to re-run + calibration on subsequent tests. + **tftp** + Directory path containing kernels and DTB images for the + target. LISA does *not* manage this TFTP server, it must be + provided externally. Optional. + + :param test_conf: Configuration of software for target experiments. Takes + the same form as target_conf. Fields are: + + **modules** + Devlib modules to be enabled. Default is [] + **exclude_modules** + Devlib modules to be disabled. Default is []. + **tools** + List of tools (available under ./tools/$ARCH/) to install on + the target. Names, not paths (e.g. ['ftrace']). Default is []. + **ping_time**, **reboot_time** + Override parameters to :meth:`reboot` method + **__features__** + List of test environment features to enable. Options are: + + "no-kernel" + do not deploy kernel/dtb images + "no-reboot" + do not force reboot the target at each configuration change + "debug" + enable debugging messages + + **ftrace** + Configuration for ftrace. Dictionary with keys: + + events + events to enable. + functions + functions to enable in the function tracer. Optional. + buffsize + Size of buffer. Default is 10240. + + **results_dir** + location of results of the experiments + + :param wipe: set true to cleanup all previous content from the output + folder + :type wipe: bool + + :param force_new: Create a new TestEnv object even if there is one available + for this session. By default, TestEnv only creates one + object per session, use this to override this behaviour. + :type force_new: bool + """ _initialized = False def __init__(self, target_conf=None, test_conf=None, wipe=True, force_new=False): - """ - Initialize the LISA test environment. - - The test environment is defined by: - - a target configuration (target_conf) defining which HW platform we - want to use to run the experiments - - a test configuration (test_conf) defining which SW setups we need on - that HW target - - a folder to collect the experiments results, which can be specified - using the test_conf::results_dir option and is by default wiped from - all the previous contents (if wipe=True) - - :param target_conf: the HW target we want to use - :type target_conf: dict - - :param test_conf: the SW setup of the HW target in use - :type test_conf: dict - - :param wipe: set true to cleanup all previous content from the output - folder - :type wipe: bool - - :param force_new: Create a new TestEnv object even if there is - one available for this session. By default, TestEnv only - creates one object per session, use this to override this - behaviour. - :type force_new: bool - """ super(TestEnv, self).__init__() if self._initialized and not force_new: @@ -236,12 +302,8 @@ class TestEnv(ShareState): """ Load the target configuration from the specified file. - The configuration file path must be relative to the test suite - installation root folder. - - :param filepath: A string representing the path of the target - configuration file. This path must be relative to the root folder of - the test suite. + :param filepath: Path of the target configuration file. Relative to the + root folder of the test suite. :type filepath: str """ @@ -500,7 +562,8 @@ class TestEnv(ShareState): def install_tools(self, tools): """ - Install tools additional to those specified in the test config + Install tools additional to those specified in the test config 'tools' + field :param tools: The list of names of tools to install :type tools: list(str) @@ -710,6 +773,15 @@ class TestEnv(ShareState): return self._calib def resolv_host(self, host=None): + """ + Resolve a host name or IP address to a MAC address + + .. TODO Is my networking terminology correct here? + + :param host: IP address or host name to resolve. If None, use 'host' + value from target_config. + :type host: str + """ if host is None: host = self.conf['host'] @@ -777,6 +849,14 @@ class TestEnv(ShareState): return (macaddr, ipaddr) def reboot(self, reboot_time=120, ping_time=15): + """ + Reboot target. + + :param boot_time: Time to wait for the target to become available after + reboot before declaring failure. + :param ping_time: Period between attempts to ping the target while + waiting for reboot. + """ # Send remote target a reboot command if self._feature('no-reboot'): self._log.warning('Reboot disabled by conf features') @@ -830,6 +910,16 @@ class TestEnv(ShareState): self._init_energy(force) def install_kernel(self, tc, reboot=False): + """ + Deploy kernel and DTB via TFTP, optionally rebooting + + :param tc: Dicionary containing optional keys 'kernel' and 'dtb'. Values + are paths to the binaries to deploy. + :type tc: dict + + :param reboot: Reboot thet target after deployment + :type reboot: bool + """ # Default initialize the kernel/dtb settings tc.setdefault('kernel', None) @@ -878,6 +968,9 @@ class TestEnv(ShareState): def tftp_deploy(self, src): + """ + .. TODO + """ tftp = self.conf['tftp'] diff --git a/libs/utils/executor.py b/libs/utils/executor.py index bba847cc5991ee43516795569dbd2730416f9b78..fe3c5468072e75655dc2749ffa045809e2a8201c 100644 --- a/libs/utils/executor.py +++ b/libs/utils/executor.py @@ -41,6 +41,133 @@ Experiment = namedtuple('Experiment', ['wload_name', 'wload', 'conf', 'iteration', 'out_dir']) class Executor(): + """ + Abstraction for running sets of experiments and gathering data from targets + + An executor can be configured to run a set of workloads (wloads) in each + different target configuration of a specified set (confs). These wloads and + confs can be specified by the "experiments_conf" input dictionary. Each + (workload, conf, iteration) tuple is called an "experiment". + + After the workloads have been run, the Executor object's `experiments` + attribute is a list of Experiment objects. The `out_dir` attribute of these + objects can be used to find the results of the experiment. This output + directory follows this format: + + results//::/ + + where: + + test_id + Is the "tid" defined by the experiments_conf, or a timestamp based + folder in case "tid" is not specified. + wltype + Is the class of workload executed, e.g. rtapp or sched_perf. + conf + Is the "tag" of one of the specified **confs**. + wload + Is the identifier of one of the specified **wloads**. + run_id + Is the progressive execution number from 1 up to the specified + **iterations**. + + :param experiments_conf: Dict with experiment configuration. Keys are: + + **confs** + Mandatory. Platform configurations to be tested. List of dicts, + each with keys: + + tag + String to identify this configuration. Required, may be empty. + flags + List of strings describing features required for this + conf. Available flags are: + + "ftrace" + Enable collecting ftrace during the experiment. + "freeze_userspace" + Use the cgroups freezer to freeze as many userspace tasks as + possible during the experiment execution, in order to reduce + system noise. Some tasks cannot be frozen, such as those + required to maintain a connection to LISA. + + sched_features + Optional list of features to be written to + /sys/kernel/debug/sched_features. Prepend "NO\_" to a feature to + actively disable it. Requires ``CONFIG_SCHED_DEBUG`` in target + kernel. + cpufreq + Parameters to configure cpufreq via Devlib's cpufreq + module. Dictionary with fields: + + .. TODO link to devlib cpufreq module docs (which don't exist) + + governor + cpufreq governor to set (for all CPUs) before execution. The + previous governor is not restored when execution is finished. + governor_tunables + Dictionary of governor-specific tunables, expanded and passed as + kwargs to the cpufreq module's ``set_governor_tunables`` method. + freq + Requires "governor" to be "userspace". Dictionary mapping CPU + numbers to frequencies. Exact frequencies should be available on + those CPUs. It is not necessary to provide a frequency for every + CPU - the frequency for unspecified CPUs is not affected. Note + that cpufreq will transparrently set the frequencies of any + other CPUs sharing a clock domain. + + cgroups + Optional cgroups configuration. To use this, ensure the 'cgroups' + devlib module is enabled in your test_conf Contains fields: + + .. TODO reference test_conf + .. TODO link to devlib cgroup module's docs (which don't exist) + + conf + Dict specifying the cgroup controllers, cgroups, and cgroup + parameters to setup. If a controller listed here is not + enabled in the target kernel, a message is logged and the + configuration is **ignored**. Of the form: + + :: + + "" : { + "" : { " } + "" : { " } + } + + These cgroups can then be used in the "cgroup" field of workload + specifications. + + default + The default cgroup to run workloads in, if no "cgroup" is + specified. + + For example, to create a cpuset cgroup named "/big" which + restricts constituent tasks to CPUs 1 and 2: + + :: + + "cgroups" : { + "conf" : { + "cpuset" : { + "/big" : {"cpus" : "1-2"}, + } + }, + "default" : "/", + } + + **wloads** + .. TODO document wloads field. + + Mandatory. Workloads to run on each platform configuration + + **iterations** + Number of iterations for each workload/conf combination. Default + is 1. + :type experiments_conf: dict + """ + critical_tasks = { 'linux': ['init', 'systemd', 'sh', 'ssh'], 'android': [ @@ -52,40 +179,12 @@ class Executor(): 'thermal-engine' ] } - """Tasks in the system that we can't afford to freeze""" + """ + Dictionary mapping OS name to list of task names that we can't afford to + freeze when using freeeze_userspace. + """ def __init__(self, test_env, experiments_conf): - """ - Tests Executor - - A tests executor is a module which support the execution of a - configured set of experiments. Each experiment is composed by: - - a target configuration - - a worload to execute - - The executor module can be configured to run a set of workloads (wloads) - in each different target configuration of a specified set (confs). These - wloads and confs can be specified by the "experiments_conf" input - dictionary. Each (workload, conf, iteration) tuple is called an - "experiment". - - All the results generated by each experiment will be collected a result - folder which is named according to this template: - results//::/ - where: - - : the "tid" defined by the experiments_conf, or a timestamp - based folder in case "tid" is not specified - - : the class of workload executed, e.g. rtapp or sched_perf - - : the identifier of one of the specified configurations - - : the identified of one of the specified workload - - : the progressive execution number from 1 up to the - specified iterations - - After the workloads have been run, the Executor object's `experiments` - attribute is a list of Experiment objects. The `out_dir` attribute of - these objects can be used to find the results of the experiment. - """ - # Initialize globals self._default_cgroup = None self._cgroup = None diff --git a/libs/utils/trace.py b/libs/utils/trace.py index e8efebaa0e3443b1ef8ac554363df230235392e3..4b6b2f2ae27b8997d3f535df8777c87974228bcd 100644 --- a/libs/utils/trace.py +++ b/libs/utils/trace.py @@ -743,9 +743,10 @@ class Trace(object): """ Build a square wave representing the active (i.e. non-idle) CPU time, i.e.: - cpu_active[t] == 1 if the CPU is reported to be non-idle by cpuidle - at time t - cpu_active[t] == 0 otherwise + + cpu_active[t] == 1 if the CPU is reported to be non-idle by cpuidle at + time t + cpu_active[t] == 0 otherwise :param cpu: CPU ID :type cpu: int @@ -781,9 +782,10 @@ class Trace(object): """ Build a square wave representing the active (i.e. non-idle) cluster time, i.e.: - cluster_active[t] == 1 if at least one CPU is reported to be - non-idle by CPUFreq at time t - cluster_active[t] == 0 otherwise + + cluster_active[t] == 1 if at least one CPU is reported to be non-idle + by CPUFreq at time t + cluster_active[t] == 0 otherwise :param cluster: list of CPU IDs belonging to a cluster :type cluster: list(int)