def get_analysis_list(meth_type): rst_list = [] for subclass in get_subclasses(TraceAnalysisBase): class_path = "{}.{}".format(subclass.__module__, subclass.__qualname__) analysis = subclass.__module__.split(".")[-1] if meth_type == 'plot': meth_list = [f.__name__ for f in subclass.get_plot_methods()] elif meth_type == 'df': meth_list = [ name for name, member in inspect.getmembers(subclass, callable) if name.startswith('df_') ] else: raise ValueError() rst_list += [ ":class:`{analysis_name}<{cls}>`::meth:`~{cls}.{meth}`".format( analysis_name=analysis, cls=class_path, meth=meth, ) for meth in meth_list ] joiner = '\n* ' return joiner + joiner.join(rst_list)
def from_conf(cls, target, conf, res_dir=None): """ Build an instance of :class:`EnergyMeter` from a configuration object. :param target: Target to use :type target: lisa.target.Target :param conf: Configuration object to use :param res_dir: Result directory to use :type res_dir: str or None """ # Select the right subclass according to the type of the configuration # object we are given for subcls in get_subclasses(cls) | {cls}: try: conf_cls = subcls.CONF_CLASS except AttributeError: continue if isinstance(conf, conf_cls): chosen_cls = subcls break else: chosen_cls = cls chosen_cls.get_logger( f'{chosen_cls.name} energy meter configuration:\n{conf}') kwargs = chosen_cls.conf_to_init_kwargs(conf) kwargs.update( target=target, res_dir=res_dir, ) chosen_cls.check_init_param(**kwargs) return chosen_cls(**kwargs)
def get_analysis_list(meth_type): rst_list = [] deprecated = {entry['obj'] for entry in get_deprecated_map().values()} for subclass in get_subclasses(AnalysisHelpers): class_path = f"{subclass.__module__}.{subclass.__qualname__}" if meth_type == 'plot': meth_list = subclass.get_plot_methods() elif meth_type == 'df': meth_list = [ member for name, member in inspect.getmembers(subclass, callable) if name.startswith('df_') ] else: raise ValueError() meth_list = [f.__name__ for f in meth_list if f not in deprecated] rst_list += [ f":class:`{subclass.name}<{class_path}>`::meth:`~{class_path}.{meth}`" for meth in meth_list ] joiner = '\n* ' return joiner + joiner.join(sorted(rst_list))
def autodoc_process_analysis_plots(app, what, name, obj, options, lines, plot_conf): if what != 'method': return plot_methods = set(itertools.chain.from_iterable( subclass.get_plot_methods() for subclass in get_subclasses(TraceAnalysisBase) )) if obj not in plot_methods: return plot_conf = plot_conf['plots'] default_spec = plot_conf.get('default', {}) spec = plot_conf.get(obj.__qualname__, {}) spec = {**default_spec, **spec} kwargs = spec.get('kwargs', {}) trace = spec['trace'] if spec.get('hide'): return print('Generating plot for {}'.format(obj.__qualname__)) rst_figure = TraceAnalysisBase.call_on_trace(obj, trace, { 'output': 'rst', 'always_save': False, # avoid memory leaks 'interactive': False, **kwargs }) rst_figure = '\n:Example plot:\n\n{}'.format(rst_figure) lines.extend(rst_figure.splitlines())
def get_analysis_classes(cls): return { subcls.name: subcls for subcls in get_subclasses(cls) # Classes without a "name" attribute directly defined in their # scope will not get registered. That allows having unnamed # intermediate base classes that are not meant to be exposed. if 'name' in subcls.__dict__ }
def get_subclasses_bullets(cls, abbrev=True, style=None, only_leaves=False): """ Return a formatted bullet list of the subclasses of the given class, including a short description for each. """ return '\n'.join(f'* {subcls}: {doc}' for subcls, doc in sorted( (get_sphinx_name(subcls, style=style, abbrev=abbrev), get_short_doc(subcls)) for subcls in get_subclasses(cls, only_leaves=only_leaves)))
def get_prebuilt_op_set(self): non_reusable_type_set = self.get_non_reusable_type_set() op_set = set() # Try to build as many configurations instances from all the files we # are given conf_cls_set = set(get_subclasses(MultiSrcConf, only_leaves=True)) conf_list = [] for conf_path in self.args.conf: for conf_cls in conf_cls_set: try: # Do not add the default source, to avoid overriding user # configuration with the default one. conf = conf_cls.from_yaml_map(conf_path, add_default_src=False) except ValueError: continue else: conf_list.append((conf, conf_path)) def keyfunc(conf_and_path): cls = type(conf_and_path[0]) # We use the ID since classes are not comparable return id(cls), cls # Then aggregate all the conf from each type, so they just act as # alternative sources. for (_, conf_cls), conf_and_path_seq in groupby(conf_list, key=keyfunc): conf_and_path_list = list(conf_and_path_seq) # Get the default configuration, and stack all user-defined keys conf = conf_cls() for conf_src, conf_path in conf_and_path_list: src = os.path.basename(conf_path) conf.add_src(src, conf_src) op_set.add( PrebuiltOperator(conf_cls, [conf], non_reusable_type_set=non_reusable_type_set)) # Inject serialized objects as root operators for path in self.args.inject: obj = Serializable.from_path(path) op_set.add( PrebuiltOperator(type(obj), [obj], non_reusable_type_set=non_reusable_type_set)) # Inject a dummy empty TargetConf if self.args.inject_empty_target_conf: op_set.add( PrebuiltOperator(TargetConf, [TargetConf(conf={})], non_reusable_type_set=non_reusable_type_set)) return op_set
def __init__(self, path, kernel_path=None): self.path = path self.kernel_path = kernel_path collector_classes = { cls.NAME: cls for cls in get_subclasses(WACollectorBase, only_leaves=True) } auto_collectors = { name: cls for name, cls in collector_classes.items() if not self._needs_params(cls) } self._auto_collectors = auto_collectors self._available_collectors = collector_classes
def autodoc_process_analysis_methods(app, what, name, obj, options, lines): """ Append the list of required trace events """ methods = { func: subclass for subclass in get_subclasses(TraceAnalysisBase) for name, func in inspect.getmembers(subclass, callable) } try: cls = methods[obj] except (KeyError, TypeError): return else: on_trace_name = f'trace.ana.{cls.name}.{obj.__name__}' extra_doc = f"\n*Called on* :class:`~lisa.trace.Trace` *instances as* ``{on_trace_name}()``\n\n" # prepend lines[:0] = extra_doc.splitlines()
def autodoc_process_analysis_plots(app, what, name, obj, options, lines, plot_conf): if what != 'method': return plot_methods = set( itertools.chain.from_iterable( subclass.get_plot_methods() for subclass in get_subclasses(TraceAnalysisBase))) if obj not in plot_methods: return plot_conf = plot_conf['plots'] default_spec = plot_conf.get('default', {}) spec = plot_conf.get(obj.__qualname__, {}) spec = {**default_spec, **spec} kwargs = spec.get('kwargs', {}) trace = spec['trace'] if spec.get('hide'): return print(f'Generating plot for {obj.__qualname__}') # Suppress deprecation warnings so we can still have them in the doc with warnings.catch_warnings(): warnings.simplefilter("ignore", category=DeprecationWarning) rst_figure = TraceAnalysisBase.call_on_trace( obj, trace, { 'backend': 'bokeh', 'output': 'sphinx-rst', 'interactive': False, **kwargs }) rst_figure = f'\n:Example plot:\n\n{rst_figure}' lines.extend(rst_figure.splitlines())
def _init_target(self, kind, name, workdir, device, host, port, username, password, keyfile, devlib_platform, devlib_excluded_modules, wait_boot, wait_boot_timeout, ): """ Initialize the Target """ logger = self.get_logger() conn_settings = {} # If the target is Android, we need just (eventually) the device if kind == 'android': logger.debug('Setting up Android target...') devlib_target_cls = devlib.AndroidTarget # Workaround for ARM-software/devlib#225 workdir = workdir or '/data/local/tmp/devlib-target' if device: pass elif host: port = port or self.ADB_PORT_DEFAULT device = '{}:{}'.format(host, port) else: device = 'DEFAULT' conn_settings['device'] = device elif kind == 'linux': logger.debug('Setting up Linux target...') devlib_target_cls = devlib.LinuxTarget conn_settings['username'] = username conn_settings['port'] = port or self.SSH_PORT_DEFAULT conn_settings['host'] = host # Configure password or SSH keyfile if keyfile: conn_settings['keyfile'] = keyfile else: conn_settings['password'] = password elif kind == 'host': logger.debug('Setting up localhost Linux target...') devlib_target_cls = devlib.LocalLinuxTarget # If we are given a password, assume we can use it as a sudo # password. conn_settings['unrooted'] = password is None conn_settings['password'] = password else: raise ValueError('Unsupported platform type {}'.format(kind)) logger.info('%s %s target connection settings:', kind, name) for key, val in conn_settings.items(): logger.info('%10s : %s', key, val) ######################################################################## # Devlib Platform configuration ######################################################################## if not devlib_platform: devlib_platform = devlib.platform.Platform() ######################################################################## # Devlib modules configuration ######################################################################## # Make sure all submodules of devlib.module are imported so the classes # are all created import_all_submodules(devlib.module) # Get all devlib Module subclasses that exist devlib_module_set = { cls.name for cls in get_subclasses(devlib.module.Module) if ( getattr(cls, 'name', None) # early modules try to connect to UART and do very # platform-specific things we are not interested in and getattr(cls, 'stage') != 'early' ) } # The platform can define a list of modules to exclude, in case a given # module really have troubles on a given platform. devlib_module_set.difference_update(devlib_excluded_modules) devlib_module_list = sorted(devlib_module_set) logger.info('Devlib modules to load: %s', ', '.join(devlib_module_list)) ######################################################################## # Create devlib Target object ######################################################################## target = devlib_target_cls( platform = devlib_platform, modules = devlib_module_list, load_default_modules = False, connection_settings = conn_settings, working_directory = workdir, connect=False, ) target.connect(check_boot_completed=wait_boot, timeout=wait_boot_timeout) logger.debug('Checking target connection...') logger.debug('Target info:') logger.debug(' ABI: %s', target.abi) logger.debug(' CPUs: %s', target.cpuinfo) logger.debug(' clusters: %s', target.core_clusters) logger.debug(' workdir: %s', target.working_directory) target.setup() if isinstance(target, devlib.AndroidTarget): target.adb_root(force=True) # Verify that all the required modules have been initialized for module in devlib_module_list: if not hasattr(target, module): logger.warning('Failed to initialized "{}" devlib Module'.format(module)) return target
from lisa.conf import SimpleMultiSrcConf, KeyDesc, LevelKeyDesc, TopLevelKeyDesc, StrList, Configurable from lisa.platforms.platinfo import PlatformInfo class PasswordKeyDesc(KeyDesc): def pretty_format(self, v): return '<password>' # Make sure all submodules of devlib.module are imported so the classes # are all created before we list them import_all_submodules(devlib.module) _DEVLIB_AVAILABLE_MODULES = { cls.name for cls in get_subclasses(devlib.module.Module) if (getattr(cls, 'name', None) # early modules try to connect to UART and do very # platform-specific things we are not interested in and getattr(cls, 'stage') != 'early') } class TargetConf(SimpleMultiSrcConf, HideExekallID): """ Target connection settings. Only keys defined below are allowed, with the given meaning and type: {generated_help}