From ff4fde3db9c49e20431630eec5cf69dccbb11455 Mon Sep 17 00:00:00 2001 From: Douglas RAILLARD Date: Thu, 5 Dec 2019 11:24:26 +0000 Subject: [PATCH 1/6] lisa.conf: Add MultiSrcConf.to_yaml_map_str() Allow rendering a configuration object as a YAML string. --- lisa/conf.py | 12 ++++++++++++ lisa/wlgen/rta.py | 11 ++++++++++- tools/lisa-conf-cat | 5 ++--- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lisa/conf.py b/lisa/conf.py index 0969c8809..564f2d397 100644 --- a/lisa/conf.py +++ b/lisa/conf.py @@ -28,6 +28,7 @@ import re import contextlib import pprint import os +import io import lisa @@ -686,6 +687,17 @@ class MultiSrcConfABC(Serializable, abc.ABC, metaclass=MultiSrcConfMeta): """ return self._to_path(self.as_yaml_map, path, fmt='yaml') + def to_yaml_map_str(self, **kwargs): + """ + Return the content of the file that would be create by + :meth:`to_yaml_map` in a string. + + :Variable keyword arguments: Forwarded to :meth:`to_yaml_map` + """ + content = io.StringIO() + self.to_yaml_map(content, **kwargs) + return content.getvalue() + # Only used with Python >= 3.6, but since that is just a sanity check it # should be okay @classmethod diff --git a/lisa/wlgen/rta.py b/lisa/wlgen/rta.py index 2fbd3ded7..66ce6d5a2 100644 --- a/lisa/wlgen/rta.py +++ b/lisa/wlgen/rta.py @@ -480,7 +480,16 @@ class RTA(Workload): pload[cpu] = int(pload_match.group(1)) logger.debug('>>> CPU{}: {}'.format(cpu, pload[cpu])) - logger.info('Target RT-App calibration: {}'.format(pload)) + # Avoid circular import issue + from lisa.platforms.platinfo import PlatformInfo + snippet_plat_info = PlatformInfo({ + 'rtapp': { + 'calib': pload, + }, + }) + logger.info('Platform info rt-app calibration configuration:\n{}'.format( + snippet_plat_info.to_yaml_map_str() + )) plat_info = target.plat_info diff --git a/tools/lisa-conf-cat b/tools/lisa-conf-cat index 449fea322..d6ec4e838 100755 --- a/tools/lisa-conf-cat +++ b/tools/lisa-conf-cat @@ -24,9 +24,8 @@ def main(): fragments = {} for conf_cls, conf in sorted(conf_map.items(), key=key): - content = io.StringIO() - conf.to_yaml_map(content) - fragments[conf_cls.__qualname__] = content.getvalue() + content = conf.to_yaml_map_str() + fragments[conf_cls.__qualname__] = content print('\n'.join( '\n{}'.format(content) -- GitLab From 5386e5fe6d96b3ced47b954a70e3e9d6f8596897 Mon Sep 17 00:00:00 2001 From: Douglas RAILLARD Date: Thu, 5 Dec 2019 11:28:22 +0000 Subject: [PATCH 2/6] lisa.trace: Allow any iterable for Trace(events=...) parameter In particular, allow sets. --- lisa/trace.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lisa/trace.py b/lisa/trace.py index a1adeb873..c8a8776a1 100644 --- a/lisa/trace.py +++ b/lisa/trace.py @@ -33,7 +33,7 @@ import shlex import contextlib import tempfile from functools import reduce, wraps -from collections.abc import Sequence +from collections.abc import Iterable from collections import namedtuple from operator import itemgetter @@ -451,10 +451,10 @@ class Trace(Loggable, TraceBase): events = sorted(proxy_cls.get_all_events()) elif isinstance(events, str): events = [events] - elif isinstance(events, Sequence): + elif isinstance(events, Iterable): events = list(events) else: - raise ValueError('Events must be a string or a sequence of strings') + raise ValueError('Events must be a string or an iterable of strings') # Register devlib fake cpu_frequency events if 'cpu_frequency' in events: @@ -1334,7 +1334,7 @@ class AssociativeTraceEventChecker(TraceEventCheckerBase): Build an instance of the class, converting ``str`` to ``TraceEventChecker``. - :param events: Sequence of events + :param events: Iterable of events :type events: list(str or TraceEventCheckerBase) """ def make_event(e): -- GitLab From 4ede9af7c6b7155fb18c98dc5f13cf0887bc281e Mon Sep 17 00:00:00 2001 From: Douglas RAILLARD Date: Thu, 5 Dec 2019 10:31:07 +0000 Subject: [PATCH 3/6] lisa.assets: Provide the absolute path to all shipped binaries The path of each binary can be taken from: lisa.assets.abi_binaries[][] --- lisa/assets/__init__.py | 46 ++++++++++++++++++++++++++++++++++++++++- lisa/utils.py | 6 +----- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/lisa/assets/__init__.py b/lisa/assets/__init__.py index 58988a6ba..d171d2dc1 100644 --- a/lisa/assets/__init__.py +++ b/lisa/assets/__init__.py @@ -1 +1,45 @@ -# Provide an empty __init__.py so that lisa.assets.__file__ can point to it +#! /USSR/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (C) 2019, ARM Limited and contributors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import os +import stat + +ASSETS_PATH = os.path.dirname(__file__) +""" +Path in which all assets the ``lisa`` package relies on are located in. +""" + +def _get_abi_bin(): + def list_binaries(path): + return { + entry.name: os.path.abspath(entry.path) + for entry in os.scandir(path) + if entry.stat().st_mode & stat.S_IXUSR + } + + bin_path = os.path.join(ASSETS_PATH, 'binaries') + return { + entry.name: list_binaries(entry.path) + for entry in os.scandir(bin_path) + if entry.is_dir() + } + +ABI_BINARIES = _get_abi_bin() +del _get_abi_bin + + +# vim :set tabstop=4 shiftwidth=4 textwidth=80 expandtab diff --git a/lisa/utils.py b/lisa/utils.py index 8c4eb0b89..ab305ea12 100644 --- a/lisa/utils.py +++ b/lisa/utils.py @@ -59,6 +59,7 @@ except ImportError: import lisa import lisa.assets from lisa.version import version_tuple, parse_version, format_version +from lisa.assets import ASSETS_PATH # Do not infer the value using __file__, since it will break later on when @@ -69,11 +70,6 @@ LISA_HOME = os.getenv('LISA_HOME') The detected location of your LISA installation """ -ASSETS_PATH = os.path.dirname(lisa.assets.__file__) -""" -Path in which all assets the ``lisa`` package relies on are located in. -""" - RESULT_DIR = 'results' LATEST_LINK = 'results_latest' -- GitLab From 2c53f2945b33dc19eb61150cc32c0467bf2410cf Mon Sep 17 00:00:00 2001 From: Douglas RAILLARD Date: Thu, 5 Dec 2019 10:41:42 +0000 Subject: [PATCH 4/6] lisa.assets: Detect host abi in lisa.assets.HOST_ABI Also expose the relevant list of binaries in lisa.assets.host_binaries --- lisa/assets/__init__.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lisa/assets/__init__.py b/lisa/assets/__init__.py index d171d2dc1..eff1f2010 100644 --- a/lisa/assets/__init__.py +++ b/lisa/assets/__init__.py @@ -17,6 +17,21 @@ # import os import stat +import platform + +def _get_abi(): + machine = platform.machine() + return dict( + x86_64='x86_64', + aarch64='arm64', + arm='arm', + )[machine] + +HOST_ABI = _get_abi() +""" +ABI of the machine that imported that module. +""" +del _get_abi ASSETS_PATH = os.path.dirname(__file__) """ @@ -41,5 +56,7 @@ def _get_abi_bin(): ABI_BINARIES = _get_abi_bin() del _get_abi_bin +HOST_BINARIES = ABI_BINARIES[HOST_ABI] + # vim :set tabstop=4 shiftwidth=4 textwidth=80 expandtab -- GitLab From 7d351b0425e087e1d568ce58ec445464617583cc Mon Sep 17 00:00:00 2001 From: Douglas RAILLARD Date: Wed, 4 Dec 2019 15:32:24 +0000 Subject: [PATCH 5/6] lisa.tests.base: Always wrap from_target() definitions Apply the wrapping logic to all definitions of from_target, not only the ones created by TestBundleMeta. This allows non-inherited implementations of from_target() to benefit from the same wrapping as the inherited ones. --- lisa/tests/base.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/lisa/tests/base.py b/lisa/tests/base.py index 646eeea26..e1d36347d 100644 --- a/lisa/tests/base.py +++ b/lisa/tests/base.py @@ -408,9 +408,8 @@ class TestBundleMeta(abc.ABCMeta): stub. The annotation is then removed from ``_from_target`` so that it is not picked up by exekall. - The signature of ``from_target`` is the result of merging - ``super().from_target`` parameters with the ones defined in - ``_from_target``. + The signature of ``from_target`` is the result of merging the original + ``cls.from_target`` parameters with the ones defined in ``_from_target``. """ @staticmethod def test_method(func): @@ -462,10 +461,11 @@ class TestBundleMeta(abc.ABCMeta): f = metacls.test_method(f) setattr(new_cls, name, f) - # If that class defines _from_target but not from_target, we create a - # stub from_target and move the annotations of _from_target to - # from_target - if '_from_target' in dct and 'from_target' not in dct: + # If that class defines _from_target, stub from_target and move the + # annotations of _from_target to from_target. If from_target was + # already defined on that class, it's wrapped by the stub, otherwise + # super().from_target is used. + if '_from_target' in dct: assert isinstance(dct['_from_target'], classmethod) _from_target = new_cls._from_target @@ -519,10 +519,20 @@ class TestBundleMeta(abc.ABCMeta): return_annotation=sig2.return_annotation ) + if 'from_target' in dct: + # Bind the classmethod object to the class + orig_from_target = dct['from_target'] + def get_orig_from_target(cls): + return orig_from_target.__get__(cls, cls) + else: + def get_orig_from_target(cls): + return super(new_cls, cls).from_target + # Make a stub that we can freely update @functools.wraps(_from_target.__func__) def from_target(cls, *args, **kwargs): - return super(new_cls, cls).from_target(*args, **kwargs) + from_target = get_orig_from_target(cls) + return from_target(*args, **kwargs) # Hide the fact that we wrapped the function, so exekall does not # get confused -- GitLab From 5158db368e17a0fce9adc45b1bc77d73ecb4e44a Mon Sep 17 00:00:00 2001 From: Douglas RAILLARD Date: Wed, 4 Dec 2019 16:03:32 +0000 Subject: [PATCH 6/6] lisa.tests.base: Crop trace.dat to avoid large artifacts Since the test is only going to use a given window in the trace, crop around that window to reduce the artifacts size. --- lisa/tests/base.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/lisa/tests/base.py b/lisa/tests/base.py index e1d36347d..7f3d6bdb6 100644 --- a/lisa/tests/base.py +++ b/lisa/tests/base.py @@ -27,6 +27,7 @@ import inspect import copy import contextlib import itertools +import subprocess from datetime import datetime from collections import OrderedDict, ChainMap @@ -54,6 +55,7 @@ from lisa.conf import ( SimpleMultiSrcConf, KeyDesc, TopLevelKeyDesc, StrList, ) +from lisa.assets import HOST_BINARIES def _nested_formatter(multiline): @@ -1473,6 +1475,39 @@ class RTATestBundle(FtraceTestBundle, DmesgTestBundle): """ return cls.run_rtapp(*args, **kwargs) + @classmethod + def from_target(cls, target: Target, *, res_dir: ArtifactPath = None, **kwargs): + test_bundle = super().from_target(target=target, res_dir=res_dir, **kwargs) + + # Crop the trace around the area we are interested in to reduce its size + trace = test_bundle.get_trace( + events=test_bundle.trace_window.used_events.get_all_events(), + # Keep absolute timestamps that we can give to trace-cmd + normalize_time=False, + ) + window = test_bundle.trace_window(trace) + margin = (0.5, 0.1) + window = ( + max(window[0] - margin[0], 0), + window[1] + margin[1], + ) + trace_path = trace.trace_path + split_path = '{}.split'.format(trace_path) + subprocess.check_call( + [ + HOST_BINARIES['trace-cmd'], 'split', + '-i', trace_path, + '-o', split_path, + *map(str, window), + ], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + actual_split_path = '{}.1'.format(split_path) + os.rename(actual_split_path, trace_path) + + return test_bundle + @classmethod def _from_target(cls, target: Target, *, res_dir: ArtifactPath, ftrace_coll: FtraceCollector = None) -> 'RTATestBundle': """ -- GitLab