def _check_env(): global ssh, scp, sshpass # pylint: disable=global-statement if not ssh: ssh = which("ssh") scp = which("scp") sshpass = which("sshpass") if not (ssh and scp): raise HostError("OpenSSH must be installed on the host.")
def _check_env(): global ssh, scp, sshpass # pylint: disable=global-statement if not ssh: ssh = which('ssh') scp = which('scp') sshpass = which('sshpass') if not (ssh and scp): raise HostError('OpenSSH must be installed on the host.')
def __init__( self, target, events=None, buffer_size=None, buffer_size_step=1000, buffer_size_file='/sys/kernel/debug/tracing/buffer_size_kb', marker_file='/sys/kernel/debug/tracing/trace_marker', automark=True, autoreport=True, autoview=False, no_install=False, ): super(FtraceCollector, self).__init__(target) self.events = events if events is not None else DEFAULT_EVENTS self.buffer_size = buffer_size self.buffer_size_step = buffer_size_step self.buffer_size_file = buffer_size_file self.marker_file = marker_file self.automark = automark self.autoreport = autoreport self.autoview = autoview self.target_output_file = os.path.join(self.target.working_directory, OUTPUT_TRACE_FILE) self.target_binary = None self.host_binary = None self.start_time = None self.stop_time = None self.event_string = _build_trace_events(self.events) self._reset_needed = True self.host_binary = which('trace-cmd') self.kernelshark = which('kernelshark') if not self.target.is_rooted: raise TargetError( 'trace-cmd instrument cannot be used on an unrooted device.') if self.autoreport and self.host_binary is None: raise HostError( 'trace-cmd binary must be installed on the host if autoreport=True.' ) if self.autoview and self.kernelshark is None: raise HostError( 'kernelshark binary must be installed on the host if autoview=True.' ) if not no_install: host_file = os.path.join(PACKAGE_BIN_DIRECTORY, self.target.abi, 'trace-cmd') self.target_binary = self.target.install(host_file) else: if not self.target.is_installed('trace-cmd'): raise TargetError( 'No trace-cmd found on device and no_install=True is specified.' ) self.target_binary = 'trace-cmd'
def __init__(self, target, resistor_values, labels=None, device_entry='/dev/ttyACM0', ): super(EnergyProbeInstrument, self).__init__(target) self.resistor_values = resistor_values if labels is not None: self.labels = labels else: self.labels = ['PORT_{}'.format(i) for i in xrange(len(resistor_values))] self.device_entry = device_entry self.caiman = which('caiman') if self.caiman is None: raise HostError('caiman must be installed on the host ' '(see https://github.com/ARM-software/caiman)') if pandas is None: self.logger.info("pandas package will significantly speed up this instrument") self.logger.info("to install it try: pip install pandas") self.attributes_per_sample = 3 self.bytes_per_sample = self.attributes_per_sample * 4 self.attributes = ['power', 'voltage', 'current'] self.command = None self.raw_output_directory = None self.process = None for label in self.labels: for kind in self.attributes: self.add_channel(label, kind)
def __init__(self, target, resistor_values, labels=None, device_entry='/dev/ttyACM0', ): super(EnergyProbeInstrument, self).__init__(target) self.resistor_values = resistor_values if labels is not None: self.labels = labels else: self.labels = ['PORT_{}'.format(i) for i in xrange(len(resistor_values))] self.device_entry = device_entry self.caiman = which('caiman') if self.caiman is None: raise HostError('caiman must be installed on the host ' '(see https://github.com/ARM-software/caiman)') self.attributes_per_sample = 3 self.bytes_per_sample = self.attributes_per_sample * 4 self.attributes = ['power', 'voltage', 'current'] self.command = None self.raw_output_directory = None self.process = None self.sample_rate_hz = 10000 # Determined empirically self.raw_data_file = None for label in self.labels: for kind in self.attributes: self.add_channel(label, kind)
class MonsoonBackend(EnergyInstrumentBackend): name = 'monsoon' description = """ Monsoon Solutions power monitor To use this instrument, you need to install the monsoon.py script available from the Android Open Source Project. As of May 2017 this is under the CTS repository: https://android.googlesource.com/platform/cts/+/master/tools/utils/monsoon.py Collects power measurements only, from a selection of two channels, the USB passthrough channel and the main output channel. """ parameters = [ Parameter('monsoon_bin', default=which('monsoon.py'), description=""" Path to monsoon.py executable. If not provided, ``PATH`` is searched. """), Parameter('tty_device', default='/dev/ttyACM0', description=""" TTY device to use to communicate with the Power Monitor. If not provided, /dev/ttyACM0 is used. """) ] instrument = MonsoonInstrument
def __init__( self, target, resistor_values, labels=None, device_entry='/dev/ttyACM0', ): super(EnergyProbeInstrument, self).__init__(target) self.resistor_values = resistor_values if labels is not None: self.labels = labels else: self.labels = [ 'PORT_{}'.format(i) for i in xrange(len(resistor_values)) ] self.device_entry = device_entry self.caiman = which('caiman') if self.caiman is None: raise HostError('caiman must be installed on the host ' '(see https://github.com/ARM-software/caiman)') if pandas is None: self.logger.info( "pandas package will significantly speed up this instrument") self.logger.info("to install it try: pip install pandas") self.attributes_per_sample = 3 self.bytes_per_sample = self.attributes_per_sample * 4 self.attributes = ['power', 'voltage', 'current'] self.command = None self.raw_output_directory = None self.process = None for label in self.labels: for kind in self.attributes: self.add_channel(label, kind)
def __init__(self, system, simulator, **kwargs): simulator_args = copy.copy(simulator.get('args', [])) system_platform = system['platform'] # Get gem5 binary arguments simulator_args.append('--listener-mode=on') simulator_args.append(system_platform['description']) simulator_args.extend(system_platform.get('args', [])) simulator_args += ['--kernel {}'.format(system['kernel']), '--dtb {}'.format(system['dtb']), '--disk-image {}'.format(system['disk'])] # Quote/escape arguments and build the command line gem5_args = ' '.join(shlex.quote(a) for a in simulator_args) diod_path = which('diod') if diod_path is None: raise RuntimeError('Failed to find "diod" on your host machine, check your installation or your PATH variable') # Setup virtio # Brackets are there to let the output dir be created automatically virtio_args = '--which-diod={} --workload-automation-vio={{}}'.format(diod_path) super().__init__( gem5_args=gem5_args, gem5_bin=simulator['bin'], virtio_args=virtio_args, **kwargs )
def __init__( self, target, resistor_values, labels=None, device_entry='/dev/ttyACM0', ): super(EnergyProbeInstrument, self).__init__(target) self.resistor_values = resistor_values if labels is not None: self.labels = labels else: self.labels = [ 'PORT_{}'.format(i) for i in range(len(resistor_values)) ] self.device_entry = device_entry self.caiman = which('caiman') if self.caiman is None: raise HostError('caiman must be installed on the host ' '(see https://github.com/ARM-software/caiman)') self.attributes_per_sample = 3 self.bytes_per_sample = self.attributes_per_sample * 4 self.attributes = ['power', 'voltage', 'current'] self.command = None self.raw_output_directory = None self.process = None self.sample_rate_hz = 10000 # Determined empirically self.raw_data_file = None for label in self.labels: for kind in self.attributes: self.add_channel(label, kind)
def __init__( self, target, events=None, buffer_size=None, buffer_size_step=1000, buffer_size_file="/sys/kernel/debug/tracing/buffer_size_kb", marker_file="/sys/kernel/debug/tracing/trace_marker", automark=True, autoreport=True, autoview=False, no_install=False, ): super(FtraceCollector, self).__init__(target) self.events = events if events is not None else DEFAULT_EVENTS self.buffer_size = buffer_size self.buffer_size_step = buffer_size_step self.buffer_size_file = buffer_size_file self.marker_file = marker_file self.automark = automark self.autoreport = autoreport self.autoview = autoview self.target_output_file = os.path.join(self.target.working_directory, OUTPUT_TRACE_FILE) self.target_binary = None self.host_binary = None self.start_time = None self.stop_time = None self.event_string = _build_trace_events(self.events) self._reset_needed = True self.host_binary = which("trace-cmd") self.kernelshark = which("kernelshark") if not self.target.is_rooted: raise TargetError("trace-cmd instrument cannot be used on an unrooted device.") if self.autoreport and self.host_binary is None: raise HostError("trace-cmd binary must be installed on the host if autoreport=True.") if self.autoview and self.kernelshark is None: raise HostError("kernelshark binary must be installed on the host if autoview=True.") if not no_install: host_file = os.path.join(PACKAGE_BIN_DIRECTORY, self.target.abi, "trace-cmd") self.target_binary = self.target.install(host_file) else: if not self.target.is_installed("trace-cmd"): raise TargetError("No trace-cmd found on device and no_install=True is specified.") self.target_binary = "trace-cmd"
def _initialize_without_android_home(env): if which('adb'): env.adb = 'adb' else: raise HostError('ANDROID_HOME is not set and adb is not in PATH. ' 'Have you installed Android SDK?') logger.debug('Discovering ANDROID_HOME from adb path.') env.platform_tools = os.path.dirname(env.adb) env.android_home = os.path.dirname(env.platform_tools) _init_common(env) return env
def _discover_aapt(env): if env.build_tools: aapt_path = '' aapt2_path = '' versions = os.listdir(env.build_tools) for version in reversed(sorted(versions)): if not os.path.isfile(aapt2_path): aapt2_path = os.path.join(env.build_tools, version, 'aapt2') if not os.path.isfile(aapt_path): aapt_path = os.path.join(env.build_tools, version, 'aapt') aapt_version = 1 # Use latest available version for aapt/appt2 but ensure at least one is valid. if os.path.isfile(aapt2_path) or os.path.isfile(aapt_path): break # Use aapt2 only if present and we have a suitable version if aapt2_path and _check_supported_aapt2(aapt2_path): aapt_path = aapt2_path aapt_version = 2 # Use the aapt version discoverted from build tools. if aapt_path: logger.debug('Using {} for version {}'.format(aapt_path, version)) env.aapt = aapt_path env.aapt_version = aapt_version return # Try detecting aapt2 and aapt from PATH if not env.aapt: aapt2_path = which('aapt2') if _check_supported_aapt2(aapt2_path): env.aapt = aapt2_path env.aapt_version = 2 else: env.aapt = which('aapt') env.aapt_version = 1 if not env.aapt: raise HostError( 'aapt/aapt2 not found. Please make sure it is avaliable in PATH' ' or at least one Android platform is installed')
def _init_target_gem5(self): system = self.conf['gem5']['system'] simulator = self.conf['gem5']['simulator'] # Get gem5 binary arguments args = simulator.get('args', []) args.append('--listener-mode=on') # Get platform description args.append(system['platform']['description']) # Get platform arguments args += system['platform'].get('args', []) args += [ '--kernel {}'.format(system['kernel']), '--dtb {}'.format(system['dtb']), '--disk-image {}'.format(system['disk']) ] # Gather all arguments args = ' '.join(args) diod_path = which('diod') if diod_path is None: raise RuntimeError('Failed to find "diod" on your host machine, ' 'check your installation or your PATH variable') # Setup virtio # Brackets are there to let the output dir be created automatically virtio_args = '--which-diod={} --workload-automation-vio={{}}'.format( diod_path) # Change conf['board'] to include platform information suffix = os.path.splitext( os.path.basename(system['platform']['description']))[0] self.conf['board'] = self.conf['board'].lower() + suffix board = self._load_board(self.conf['board']) # Merge all arguments platform = devlib.platform.gem5.Gem5SimulationPlatform( name='gem5', gem5_bin=simulator['bin'], gem5_args=args, gem5_virtio=virtio_args, host_output_dir=self.res_dir, core_names=board['cores'] if board else None, core_clusters=self._get_clusters(board['cores']) if board else None, big_core=board.get('big_core', None) if board else None, ) return platform
def _initialize_without_android_home(env): adb_full_path = which('adb') if adb_full_path: env.adb = 'adb' else: raise HostError('ANDROID_HOME is not set and adb is not in PATH. ' 'Have you installed Android SDK?') logger.debug('Discovering ANDROID_HOME from adb path.') env.platform_tools = os.path.dirname(adb_full_path) env.android_home = os.path.dirname(env.platform_tools) try: _init_common(env) except: env.aapt = which('aapt') if env.aapt: logger.info('Using aapt: ' + env.aapt) else: raise RuntimeError('aapt not found, try setting ANDROID_HOME to \ Android SDK or run LISA from android environment' ) return env
def __init__(self, target, monsoon_bin=None, tty_device=None): super(MonsoonInstrument, self).__init__(target) self.monsoon_bin = monsoon_bin or which('monsoon.py') if not self.monsoon_bin: raise HostError(INSTALL_INSTRUCTIONS) self.tty_device = tty_device self.process = None self.output = None self.sample_rate_hz = 500 self.add_channel('output', 'power') self.add_channel('USB', 'power')
def _init_target_gem5(self): system = self.conf['gem5']['system'] simulator = self.conf['gem5']['simulator'] # Get gem5 binary arguments args = simulator.get('args', []) args.append('--listener-mode=on') # Get platform description args.append(system['platform']['description']) # Get platform arguments args += system['platform'].get('args', []) args += ['--kernel {}'.format(system['kernel']), '--dtb {}'.format(system['dtb']), '--disk-image {}'.format(system['disk'])] # Gather all arguments args = ' '.join(args) diod_path = which('diod') if diod_path is None: raise RuntimeError('Failed to find "diod" on your host machine, ' 'check your installation or your PATH variable') # Setup virtio # Brackets are there to let the output dir be created automatically virtio_args = '--which-diod={} --workload-automation-vio={{}}'.format(diod_path) # Change conf['board'] to include platform information suffix = os.path.splitext(os.path.basename( system['platform']['description']))[0] self.conf['board'] = self.conf['board'].lower() + suffix board = self._load_board(self.conf['board']) # Merge all arguments platform = devlib.platform.gem5.Gem5SimulationPlatform( name = 'gem5', gem5_bin = simulator['bin'], gem5_args = args, gem5_virtio = virtio_args, host_output_dir = self.res_dir, core_names = board['cores'] if board else None, core_clusters = self._get_clusters(board['cores']) if board else None, big_core = board.get('big_core', None) if board else None, ) return platform
def __init__(self, target, config_file='./config-aep', keep_raw=False): super(ArmEnergyProbeInstrument, self).__init__(target) self.arm_probe = which('arm-probe') if self.arm_probe is None: raise HostError('arm-probe must be installed on the host') #todo detect is config file exist self.attributes = ['power', 'voltage', 'current'] self.sample_rate_hz = 10000 self.config_file = config_file self.keep_raw = keep_raw self.parser = AepParser() #TODO make it generic topo = self.parser.topology_from_config(self.config_file) for item in topo: if item == 'time': self.add_channel('timestamp', 'time') else: self.add_channel(item, 'power')
def __init__(self, target, iio_capture=which('iio-capture'), host='baylibre-acme.local', iio_device='iio:device0', buffer_size=256): super(AcmeCapeInstrument, self).__init__(target) self.iio_capture = iio_capture self.host = host self.iio_device = iio_device self.buffer_size = buffer_size self.sample_rate_hz = 100 if self.iio_capture is None: raise HostError('Missing iio-capture binary') self.command = None self.process = None self.add_channel('shunt', 'voltage') self.add_channel('bus', 'voltage') self.add_channel('device', 'power') self.add_channel('device', 'current') self.add_channel('timestamp', 'time_ms')
def __init__( self, target, events=None, functions=None, buffer_size=None, buffer_size_step=1000, tracing_path='/sys/kernel/debug/tracing', automark=True, autoreport=True, autoview=False, no_install=False, ): super(FtraceCollector, self).__init__(target) self.events = events if events is not None else DEFAULT_EVENTS self.functions = functions self.buffer_size = buffer_size self.buffer_size_step = buffer_size_step self.tracing_path = tracing_path self.automark = automark self.autoreport = autoreport self.autoview = autoview self.target_output_file = os.path.join(self.target.working_directory, OUTPUT_TRACE_FILE) self.target_binary = None self.host_binary = None self.start_time = None self.stop_time = None self.event_string = _build_trace_events(self.events) self.function_string = _build_trace_functions(self.functions) self._reset_needed = True # Setup tracing paths self.available_functions_file = self.target.path.join( self.tracing_path, 'available_filter_functions') self.buffer_size_file = self.target.path.join(self.tracing_path, 'buffer_size_kb') self.current_tracer_file = self.target.path.join( self.tracing_path, 'current_tracer') self.function_profile_file = self.target.path.join( self.tracing_path, 'function_profile_enabled') self.marker_file = self.target.path.join(self.tracing_path, 'trace_marker') self.ftrace_filter_file = self.target.path.join( self.tracing_path, 'set_ftrace_filter') self.host_binary = which('trace-cmd') self.kernelshark = which('kernelshark') if not self.target.is_rooted: raise TargetError( 'trace-cmd instrument cannot be used on an unrooted device.') if self.autoreport and self.host_binary is None: raise HostError( 'trace-cmd binary must be installed on the host if autoreport=True.' ) if self.autoview and self.kernelshark is None: raise HostError( 'kernelshark binary must be installed on the host if autoview=True.' ) if not no_install: host_file = os.path.join(PACKAGE_BIN_DIRECTORY, self.target.abi, 'trace-cmd') self.target_binary = self.target.install(host_file) else: if not self.target.is_installed('trace-cmd'): raise TargetError( 'No trace-cmd found on device and no_install=True is specified.' ) self.target_binary = 'trace-cmd' # Check for function tracing support if self.functions: if not self.target.file_exists(self.function_profile_file): raise TargetError('Function profiling not supported. '\ 'A kernel build with CONFIG_FUNCTION_PROFILER enable is required') # Validate required functions to be traced available_functions = self.target.execute('cat {}'.format( self.available_functions_file)).splitlines() for function in self.functions: if function not in available_functions: raise TargetError( 'Function [{}] not available for filtering'.format( function))
def __init__( self, target, events=None, functions=None, buffer_size=None, buffer_size_step=1000, tracing_path="/sys/kernel/debug/tracing", automark=True, autoreport=True, autoview=False, no_install=False, ): super(FtraceCollector, self).__init__(target) self.events = events if events is not None else DEFAULT_EVENTS self.functions = functions self.buffer_size = buffer_size self.buffer_size_step = buffer_size_step self.tracing_path = tracing_path self.automark = automark self.autoreport = autoreport self.autoview = autoview self.target_output_file = os.path.join(self.target.working_directory, OUTPUT_TRACE_FILE) self.target_binary = None self.host_binary = None self.start_time = None self.stop_time = None self.event_string = _build_trace_events(self.events) self.function_string = _build_trace_functions(self.functions) self._reset_needed = True # Setup tracing paths self.available_functions_file = self.target.path.join(self.tracing_path, "available_filter_functions") self.buffer_size_file = self.target.path.join(self.tracing_path, "buffer_size_kb") self.current_tracer_file = self.target.path.join(self.tracing_path, "current_tracer") self.function_profile_file = self.target.path.join(self.tracing_path, "function_profile_enabled") self.marker_file = self.target.path.join(self.tracing_path, "trace_marker") self.ftrace_filter_file = self.target.path.join(self.tracing_path, "set_ftrace_filter") self.host_binary = which("trace-cmd") self.kernelshark = which("kernelshark") if not self.target.is_rooted: raise TargetError("trace-cmd instrument cannot be used on an unrooted device.") if self.autoreport and self.host_binary is None: raise HostError("trace-cmd binary must be installed on the host if autoreport=True.") if self.autoview and self.kernelshark is None: raise HostError("kernelshark binary must be installed on the host if autoview=True.") if not no_install: host_file = os.path.join(PACKAGE_BIN_DIRECTORY, self.target.abi, "trace-cmd") self.target_binary = self.target.install(host_file) else: if not self.target.is_installed("trace-cmd"): raise TargetError("No trace-cmd found on device and no_install=True is specified.") self.target_binary = "trace-cmd" # Check for function tracing support if self.functions: if not self.target.file_exists(self.function_profile_file): raise TargetError( "Function profiling not supported. " "A kernel build with CONFIG_FUNCTION_PROFILER enable is required" ) # Validate required functions to be traced available_functions = self.target.execute("cat {}".format(self.available_functions_file)).splitlines() for function in self.functions: if function not in available_functions: raise TargetError("Function [{}] not available for filtering".format(function))
def __init__( self, target, events=None, functions=None, buffer_size=None, buffer_size_step=1000, tracing_path='/sys/kernel/debug/tracing', automark=True, autoreport=True, autoview=False, no_install=False, strict=False, report_on_target=False, ): super(FtraceCollector, self).__init__(target) self.events = events if events is not None else DEFAULT_EVENTS self.functions = functions self.buffer_size = buffer_size self.buffer_size_step = buffer_size_step self.tracing_path = tracing_path self.automark = automark self.autoreport = autoreport self.autoview = autoview self.report_on_target = report_on_target self.target_output_file = target.path.join( self.target.working_directory, OUTPUT_TRACE_FILE) text_file_name = target.path.splitext(OUTPUT_TRACE_FILE)[0] + '.txt' self.target_text_file = target.path.join(self.target.working_directory, text_file_name) self.target_binary = None self.host_binary = None self.start_time = None self.stop_time = None self.event_string = None self.function_string = None self._reset_needed = True # Setup tracing paths self.available_events_file = self.target.path.join( self.tracing_path, 'available_events') self.available_functions_file = self.target.path.join( self.tracing_path, 'available_filter_functions') self.buffer_size_file = self.target.path.join(self.tracing_path, 'buffer_size_kb') self.current_tracer_file = self.target.path.join( self.tracing_path, 'current_tracer') self.function_profile_file = self.target.path.join( self.tracing_path, 'function_profile_enabled') self.marker_file = self.target.path.join(self.tracing_path, 'trace_marker') self.ftrace_filter_file = self.target.path.join( self.tracing_path, 'set_ftrace_filter') self.host_binary = which('trace-cmd') self.kernelshark = which('kernelshark') if not self.target.is_rooted: raise TargetError( 'trace-cmd instrument cannot be used on an unrooted device.') if self.autoreport and not self.report_on_target and self.host_binary is None: raise HostError( 'trace-cmd binary must be installed on the host if autoreport=True.' ) if self.autoview and self.kernelshark is None: raise HostError( 'kernelshark binary must be installed on the host if autoview=True.' ) if not no_install: host_file = os.path.join(PACKAGE_BIN_DIRECTORY, self.target.abi, 'trace-cmd') self.target_binary = self.target.install(host_file) else: if not self.target.is_installed('trace-cmd'): raise TargetError( 'No trace-cmd found on device and no_install=True is specified.' ) self.target_binary = 'trace-cmd' # Validate required events to be traced available_events = self.target.execute('cat {}'.format( self.available_events_file), as_root=True).splitlines() selected_events = [] for event in self.events: # Convert globs supported by FTrace into valid regexp globs _event = event if event[0] != '*': _event = '*' + event event_re = re.compile(_event.replace('*', '.*')) # Select events matching the required ones if len(filter(event_re.match, available_events)) == 0: message = 'Event [{}] not available for tracing'.format(event) if strict: raise TargetError(message) self.target.logger.warning(message) else: selected_events.append(event) # If function profiling is enabled we always need at least one event. # Thus, if not other events have been specified, try to add at least # a tracepoint which is always available and possibly triggered few # times. if self.functions and len(selected_events) == 0: selected_events = ['sched_wakeup_new'] self.event_string = _build_trace_events(selected_events) # Check for function tracing support if self.functions: if not self.target.file_exists(self.function_profile_file): raise TargetError('Function profiling not supported. '\ 'A kernel build with CONFIG_FUNCTION_PROFILER enable is required') # Validate required functions to be traced available_functions = self.target.execute( 'cat {}'.format(self.available_functions_file), as_root=True).splitlines() selected_functions = [] for function in self.functions: if function not in available_functions: message = 'Function [{}] not available for profiling'.format( function) if strict: raise TargetError(message) self.target.logger.warning(message) else: selected_functions.append(function) self.function_string = _build_trace_functions(selected_functions)
def __init__(self, target, events=None, functions=None, tracer=None, trace_children_functions=False, buffer_size=None, buffer_size_step=1000, tracing_path='/sys/kernel/debug/tracing', automark=True, autoreport=True, autoview=False, no_install=False, strict=False, report_on_target=False, trace_clock='local', saved_cmdlines_nr=4096, ): super(FtraceCollector, self).__init__(target) self.events = events if events is not None else DEFAULT_EVENTS self.functions = functions self.tracer = tracer self.trace_children_functions = trace_children_functions self.buffer_size = buffer_size self.buffer_size_step = buffer_size_step self.tracing_path = tracing_path self.automark = automark self.autoreport = autoreport self.autoview = autoview self.strict = strict self.report_on_target = report_on_target self.target_output_file = target.path.join(self.target.working_directory, OUTPUT_TRACE_FILE) text_file_name = target.path.splitext(OUTPUT_TRACE_FILE)[0] + '.txt' self.target_text_file = target.path.join(self.target.working_directory, text_file_name) self.target_binary = None self.host_binary = None self.start_time = None self.stop_time = None self.event_string = None self.function_string = None self.trace_clock = trace_clock self.saved_cmdlines_nr = saved_cmdlines_nr self._reset_needed = True # pylint: disable=bad-whitespace # Setup tracing paths self.available_events_file = self.target.path.join(self.tracing_path, 'available_events') self.available_functions_file = self.target.path.join(self.tracing_path, 'available_filter_functions') self.buffer_size_file = self.target.path.join(self.tracing_path, 'buffer_size_kb') self.current_tracer_file = self.target.path.join(self.tracing_path, 'current_tracer') self.function_profile_file = self.target.path.join(self.tracing_path, 'function_profile_enabled') self.marker_file = self.target.path.join(self.tracing_path, 'trace_marker') self.ftrace_filter_file = self.target.path.join(self.tracing_path, 'set_ftrace_filter') self.trace_clock_file = self.target.path.join(self.tracing_path, 'trace_clock') self.save_cmdlines_size_file = self.target.path.join(self.tracing_path, 'saved_cmdlines_size') self.available_tracers_file = self.target.path.join(self.tracing_path, 'available_tracers') self.host_binary = which('trace-cmd') self.kernelshark = which('kernelshark') if not self.target.is_rooted: raise TargetStableError('trace-cmd instrument cannot be used on an unrooted device.') if self.autoreport and not self.report_on_target and self.host_binary is None: raise HostError('trace-cmd binary must be installed on the host if autoreport=True.') if self.autoview and self.kernelshark is None: raise HostError('kernelshark binary must be installed on the host if autoview=True.') if not no_install: host_file = os.path.join(PACKAGE_BIN_DIRECTORY, self.target.abi, 'trace-cmd') self.target_binary = self.target.install(host_file) else: if not self.target.is_installed('trace-cmd'): raise TargetStableError('No trace-cmd found on device and no_install=True is specified.') self.target_binary = 'trace-cmd' # Validate required events to be traced def event_to_regex(event): if not event.startswith('*'): event = '*' + event return re.compile(event.replace('*', '.*')) def event_is_in_list(event, events): return any( event_to_regex(event).match(_event) for _event in events ) unavailable_events = [ event for event in self.events if not event_is_in_list(event, self.available_events) ] if unavailable_events: message = 'Events not available for tracing: {}'.format( ', '.join(unavailable_events) ) if self.strict: raise TargetStableError(message) else: self.target.logger.warning(message) selected_events = sorted(set(self.events) - set(unavailable_events)) if self.tracer and self.tracer not in self.available_tracers: raise TargetStableError('Unsupported tracer "{}". Available tracers: {}'.format( self.tracer, ', '.join(self.available_tracers))) # Check for function tracing support if self.functions: if not self.target.file_exists(self.function_profile_file): raise TargetStableError('Function profiling not supported. '\ 'A kernel build with CONFIG_FUNCTION_PROFILER enable is required') # Validate required functions to be traced available_functions = self.target.execute( 'cat {}'.format(self.available_functions_file), as_root=True).splitlines() selected_functions = [] for function in self.functions: if function not in available_functions: message = 'Function [{}] not available for profiling'.format(function) if self.strict: raise TargetStableError(message) self.target.logger.warning(message) else: selected_functions.append(function) if self.tracer is None: self.function_string = _build_trace_functions(selected_functions) # If function profiling is enabled we always need at least one event. # Thus, if not other events have been specified, try to add at least # a tracepoint which is always available and possibly triggered few # times. if not selected_events: selected_events = ['sched_wakeup_new'] elif self.tracer == 'function_graph': self.function_string = _build_graph_functions(selected_functions, trace_children_functions) self.event_string = _build_trace_events(selected_events)
def __init__(self, target, events=None, functions=None, buffer_size=None, buffer_size_step=1000, tracing_path='/sys/kernel/debug/tracing', automark=True, autoreport=True, autoview=False, no_install=False, strict=False, ): super(FtraceCollector, self).__init__(target) self.events = events if events is not None else DEFAULT_EVENTS self.functions = functions self.buffer_size = buffer_size self.buffer_size_step = buffer_size_step self.tracing_path = tracing_path self.automark = automark self.autoreport = autoreport self.autoview = autoview self.target_output_file = os.path.join(self.target.working_directory, OUTPUT_TRACE_FILE) self.target_binary = None self.host_binary = None self.start_time = None self.stop_time = None self.event_string = None self.function_string = None self._reset_needed = True # Setup tracing paths self.available_events_file = self.target.path.join(self.tracing_path, 'available_events') self.available_functions_file = self.target.path.join(self.tracing_path, 'available_filter_functions') self.buffer_size_file = self.target.path.join(self.tracing_path, 'buffer_size_kb') self.current_tracer_file = self.target.path.join(self.tracing_path, 'current_tracer') self.function_profile_file = self.target.path.join(self.tracing_path, 'function_profile_enabled') self.marker_file = self.target.path.join(self.tracing_path, 'trace_marker') self.ftrace_filter_file = self.target.path.join(self.tracing_path, 'set_ftrace_filter') self.host_binary = which('trace-cmd') self.kernelshark = which('kernelshark') if not self.target.is_rooted: raise TargetError('trace-cmd instrument cannot be used on an unrooted device.') if self.autoreport and self.host_binary is None: raise HostError('trace-cmd binary must be installed on the host if autoreport=True.') if self.autoview and self.kernelshark is None: raise HostError('kernelshark binary must be installed on the host if autoview=True.') if not no_install: host_file = os.path.join(PACKAGE_BIN_DIRECTORY, self.target.abi, 'trace-cmd') self.target_binary = self.target.install(host_file) else: if not self.target.is_installed('trace-cmd'): raise TargetError('No trace-cmd found on device and no_install=True is specified.') self.target_binary = 'trace-cmd' # Validate required events to be traced available_events = self.target.execute( 'cat {}'.format(self.available_events_file)).splitlines() selected_events = [] for event in self.events: # Convert globs supported by FTrace into valid regexp globs _event = event if event[0] != '*': _event = '*' + event event_re = re.compile(_event.replace('*', '.*')) # Select events matching the required ones if len(filter(event_re.match, available_events)) == 0: message = 'Event [{}] not available for tracing'.format(event) if strict: raise TargetError(message) self.target.logger.warning(message) else: selected_events.append(event) # If function profiling is enabled we always need at least one event. # Thus, if not other events have been specified, try to add at least # a tracepoint which is always available and possibly triggered few # times. if self.functions and len(selected_events) == 0: selected_events = ['sched_wakeup_new'] self.event_string = _build_trace_events(selected_events) # Check for function tracing support if self.functions: if not self.target.file_exists(self.function_profile_file): raise TargetError('Function profiling not supported. '\ 'A kernel build with CONFIG_FUNCTION_PROFILER enable is required') # Validate required functions to be traced available_functions = self.target.execute( 'cat {}'.format(self.available_functions_file)).splitlines() selected_functions = [] for function in self.functions: if function not in available_functions: message = 'Function [{}] not available for profiling'.format(function) if strict: raise TargetError(message) self.target.logger.warning(message) else: selected_functions.append(function) self.function_string = _build_trace_functions(selected_functions)
class AcmeCapeBackend(EnergyInstrumentBackend): name = 'acme_cape' description = """ BayLibre ACME cape This backend relies on iio-capture utility: https://github.com/BayLibre/iio-capture For more information about ACME cape please see: https://baylibre.com/acme/ """ parameters = [ Parameter('iio-capture', default=which('iio-capture'), description=""" Path to the iio-capture binary will be taken from the environment, if not specfied. """), Parameter('host', default='baylibre-acme.local', description=""" Host name (or IP address) of the ACME cape board. """), Parameter('iio-devices', default='iio:device0', kind=list_or_string, description=""" """), Parameter('buffer-size', kind=int, default=256, description=""" Size of the capture buffer (in KB). """), ] # pylint: disable=arguments-differ def get_instruments(self, target, metadir, iio_capture, host, iio_devices, buffer_size): # # Devlib's ACME instrument uses iio-capture under the hood, which can # only capture data from one IIO device at a time. Devlib's instrument # API expects to produce a single CSV file for the Instrument, with a # single axis of sample timestamps. These two things cannot be correctly # reconciled without changing the devlib Instrument API - get_data would # need to be able to return two distinct sets of data. # # Instead, where required WA will instantiate the ACME instrument # multiple times (once for each IIO device), producing two separate CSV # files. Aggregated energy info _can_ be meaningfully combined from # multiple IIO devices, so we will later sum the derived stats across # each of the channels reported by the instruments. # ret = {} for iio_device in iio_devices: ret[iio_device] = AcmeCapeInstrument(target, iio_capture=iio_capture, host=host, iio_device=iio_device, buffer_size=buffer_size) return ret