Beispiel #1
0
    def _run_rtapp(cls,
                   target,
                   res_dir,
                   profile,
                   ftrace_coll=None,
                   cg_cfg=None):
        wload = RTA.by_profile(target,
                               "rta_{}".format(cls.__name__.lower()),
                               profile,
                               res_dir=res_dir)

        trace_path = os.path.join(res_dir, cls.TRACE_PATH)
        dmesg_path = os.path.join(res_dir, cls.DMESG_PATH)
        ftrace_coll = ftrace_coll or FtraceCollector.from_conf(
            target, cls.ftrace_conf)
        dmesg_coll = DmesgCollector(target)

        cgroup = cls._target_configure_cgroup(target, cg_cfg)
        as_root = cgroup is not None

        with dmesg_coll, ftrace_coll, target.freeze_userspace():
            wload.run(cgroup=cgroup, as_root=as_root)

        ftrace_coll.get_trace(trace_path)
        dmesg_coll.get_trace(dmesg_path)
        return trace_path
Beispiel #2
0
    def _do_test(self, profile, exp_phases):
        rtapp = RTA.by_profile(self.target,
                               name='test',
                               profile=profile,
                               res_dir=self.res_dir,
                               calibration=None)

        with open(rtapp.local_json) as f:
            conf = json.load(f, object_pairs_hook=OrderedDict)

        # Check that the configuration looks like we expect it to
        phases = list(conf['tasks']['test_task']['phases'].values())
        self.assertEqual(len(phases), len(exp_phases),
                         'Wrong number of phases')
        for phase, exp_phase in zip(phases, exp_phases):
            self.assertDictEqual(phase, exp_phase)

        # Try running the workload and check that it produces the expected log
        # files
        rtapp.run()

        # rtapp_cmds = [c for c in self.target.executed_commands if 'rt-app' in c]
        # self.assertListEqual(rtapp_cmds, [self.get_expected_command(rtapp)])

        self.assert_output_file_exists('output.log')
        self.assert_output_file_exists('test.json')
        self.assert_output_file_exists('rt-app-test_task-0.log')
        self.assert_can_read_logfile(exp_tasks=['test_task'])
Beispiel #3
0
    def run_rtapp(cls,
                  target,
                  res_dir,
                  profile=None,
                  ftrace_coll=None,
                  cg_cfg=None):
        """
        Run the given RTA profile on the target, and collect an ftrace trace.

        :param target: target to execute the workload on.
        :type target: lisa.target.Target

        :param res_dir: Artifact folder where the artifacts will be stored.
        :type res_dir: str or lisa.utils.ArtifactPath

        :param profile: ``rt-app`` profile, as a dictionary of
            ``dict(task_name, RTATask)``. If ``None``,
            :meth:`~lisa.tests.base.RTATestBundle.get_rtapp_profile` is called
            with ``target.plat_info``.
        :type profile: dict(str, lisa.wlgen.rta.RTATask)

        :param ftrace_coll: Ftrace collector to use to record the trace. This
            allows recording extra events compared to the default one, which is
            based on the ``ftrace_conf`` class attribute.
        :type ftrace_coll: lisa.trace.FtraceCollector

        :param cg_cfg: CGroup configuration dictionary. If ``None``,
            :meth:`lisa.tests.base.RTATestBundle.get_cgroup_configuration` is
            called with ``target.plat_info``.
        :type cg_cfg: dict
        """

        trace_path = ArtifactPath.join(res_dir, cls.TRACE_PATH)
        dmesg_path = ArtifactPath.join(res_dir, cls.DMESG_PATH)
        ftrace_coll = ftrace_coll or FtraceCollector.from_conf(
            target, cls.ftrace_conf)
        dmesg_coll = DmesgCollector(target)

        profile = profile or cls.get_rtapp_profile(target.plat_info)
        cg_cfg = cg_cfg or cls.get_cgroup_configuration(target.plat_info)

        wload = RTA.by_profile(target,
                               "rta_{}".format(cls.__name__.lower()),
                               profile,
                               res_dir=res_dir)
        cgroup = cls._target_configure_cgroup(target, cg_cfg)
        as_root = cgroup is not None

        # Pre-hit the calibration information, in case this is a lazy value.
        # This avoids polluting the trace and the dmesg output with the
        # calibration tasks. Since we know that rt-app will always need it for
        # anything useful, it's reasonable to do it here.
        target.plat_info['rtapp']['calib']

        with dmesg_coll, ftrace_coll, target.freeze_userspace():
            wload.run(cgroup=cgroup, as_root=as_root)

        ftrace_coll.get_trace(trace_path)
        dmesg_coll.get_trace(dmesg_path)
        return trace_path
    def _do_test(self, profile, exp_phases):
        rtapp = RTA.from_profile(
            self.target, name='test', profile=profile, res_dir=self.res_dir,
            calibration=None, log_stats=True)

        with rtapp:
            with open(rtapp.local_json) as f:
                conf = json.load(f)

            # Check that the configuration looks like we expect it to
            phases = list(conf['tasks']['test']['phases'].values())
            assert len(phases) == len(exp_phases), 'Wrong number of phases'
            for phase, exp_phase in zip(phases, exp_phases):
                assert phase == exp_phase

            # Try running the workload and check that it produces the expected log
            # files
            rtapp.run()

        # rtapp_cmds = [c for c in self.target.executed_commands if 'rt-app' in c]
        # assert rtapp_cmds == [self.get_expected_command(rtapp)]

        self.assert_output_file_exists('stdout.log')
        self.assert_output_file_exists('stderr.log')
        self.assert_output_file_exists('test.json')
        self.assert_output_file_exists('rt-app-test-0.log')
    def _do_test(self, profile, exp_phases):
        rtapp = RTA.by_profile(
            self.target, name='test', profile=profile, res_dir=self.res_dir,
            calibration=None, log_stats=True)

        with open(rtapp.local_json) as f:
            conf = json.load(f, object_pairs_hook=OrderedDict)

        # Check that the configuration looks like we expect it to
        phases = list(conf['tasks']['test']['phases'].values())
        assert len(phases) == len(exp_phases), 'Wrong number of phases'
        for phase, exp_phase in zip(phases, exp_phases):
            if 'cpus' not in exp_phase:
                exp_phase = copy.copy(exp_phase)
                exp_phase.update(
                    cpus=sorted(range(self.target.plat_info['cpus-count'])),
                    nodes_membind=sorted(range(self.target.plat_info['numa-nodes-count'])),
                )
            assert phase == exp_phase

        # Try running the workload and check that it produces the expected log
        # files
        rtapp.run()

        # rtapp_cmds = [c for c in self.target.executed_commands if 'rt-app' in c]
        # assert rtapp_cmds == [self.get_expected_command(rtapp)]

        self.assert_output_file_exists('output.log')
        self.assert_output_file_exists('test.json')
        self.assert_output_file_exists('rt-app-test-0.log')
        self.assert_can_read_logfile(exp_tasks=['test-0'])
    def _get_calib_conf(self, calibration):
        profile = {"test": Periodic()}
        rtapp = RTA.by_profile(
            self.target, name='test', res_dir=self.res_dir, profile=profile,
            calibration=calibration)

        with open(rtapp.local_json) as fh:
            return json.load(fh)['global']['calibration']
    def _test_custom_smoke(self, calibration):
        """
        Test RTA custom workload

        Creates an rt-app workload using 'custom' and checks that the json
        roughly matches the file we provided. If we have root, attempts to run
        the workload.
        """

        json_path = os.path.join(ASSET_DIR, 'mp3-short.json')

        with open(json_path, 'r') as fh:
            str_conf = fh.read()

        rtapp = RTA.from_str(
            self.target,
            name='test',
            str_conf=str_conf,
            res_dir=self.res_dir,
            max_duration_s=5,
            calibration=calibration,
            as_root=True,
        )

        with rtapp:
            with open(rtapp.local_json, 'r') as fh:
                conf = json.load(fh)

            tasks = {
                'AudioTick',
                'AudioOut',
                'AudioTrack',
                'mp3.decoder',
                'OMXCall'
            }
            assert conf['tasks'].keys() == tasks

            # Would like to try running the workload but mp3-short.json has nonzero
            # 'priority' fields, and we probably don't have permission for that
            # unless we're root.
            if self.target.is_rooted:
                rtapp.run()

                # rtapp_cmds = [c for c in self.target.executed_commands
                #               if 'rt-app' in c]
                # assert rtapp_cmds == [self.get_expected_command(rtapp)]

                self.assert_output_file_exists('stdout.log')
                self.assert_output_file_exists('stderr.log')
                self.assert_output_file_exists('test.json')
Beispiel #8
0
def compute_rtapp_capacities(conf):
    """
    Compute the capacities that will be used for rtapp.

    If the CPU capacities are not writeable on the target, the orig capacities
    will be used, otherwise the capacities adjusted with rtapp calibration will
    be used.
    """
    writeable = conf['writeable']
    orig_capacities = conf['orig']

    rtapp_calib = conf['..']['rtapp']['calib']
    rtapp_capacities = RTA.get_cpu_capacities_from_calibrations(orig_capacities, rtapp_calib)

    return rtapp_capacities if writeable else orig_capacities
Beispiel #9
0
    def _get_calib_conf(self, calibration):
        profile = {
            "test":
            RTAPhase(prop_wload=PeriodicWload(
                duty_cycle_pct=50,
                period=100e-3,
                duration=1,
            ))
        }
        rtapp = RTA.from_profile(self.target,
                                 name='test',
                                 res_dir=self.res_dir,
                                 profile=profile,
                                 calibration=calibration)

        with open(rtapp.local_json) as fh:
            return json.load(fh)['global']['calibration']
Beispiel #10
0
    def correct_expected_pelt(cls, plat_info, cpu, signal_value):
        """
        Correct an expected PELT signal from ``rt-app`` based on the calibration
        values.

        Since the instruction mix of ``rt-app`` might not be the same as the
        benchmark that was used to establish CPU capacities, the duty cycle of
        ``rt-app`` will only be accurate on big CPUs. When we know on which CPU
        the task actually executed, we can correct the expected value based on
        the ratio of calibration values and CPU capacities.
        """

        calib = plat_info['rtapp']['calib']
        cpu_capacities = plat_info['cpu-capacities']

        # Correct the signal mean to what it should have been if rt-app
        # workload was exactly the same as the one used to establish CPU
        # capacities
        true_capacities = RTA.get_cpu_capacities_from_calibrations(calib)
        return signal_value * cpu_capacities[cpu] / true_capacities[cpu]
Beispiel #11
0
    def df_rtapp_loop(self, task=None, wlgen_profile=None):
        """
        Dataframe of events generated by each rt-app generated task.

        :param task: the (optional) rt-app task to filter for
        :type task: int or str or lisa.trace.TaskID

        :param wlgen_profile: Dictionary of rt-app task names to
            :class:`~lisa.wlgen.rta.RTAPhase` used to resolve phase name from
            the trace and will add a ``properties`` column with the
            :class:`~lisa.wlgen.rta.RTAPhase` properties.
        :type wlgen_profile: dict(str, lisa.wlgen.rta.RTAPhase) or None

        :returns: a :class:`pandas.DataFrame` with:

          * A  ``__comm`` column: the actual rt-app trace task name
          * A  ``__cpu``  column: the CPU on which the task was running at event
                                 generation time
          * A  ``__line`` column: the ftrace line numer
          * A  ``__pid``  column: the PID of the task
          * An ``event``  column: the generated event
          * A  ``phase``  column: the phases counter for each ``__pid``:``__comm`` task
          * A  ``phase_loop``  colum: the phase_loops's counter
          * A  ``thread_loop`` column: the thread_loop's counter

        The ``event`` column can report these events:

          * ``start``: the start of the ``__pid``:``__comm`` related event
          * ``end``: the end of the ``__pid``:``__comm`` related event

        """
        df = self.trace.df_event('userspace@rtapp_loop')
        df = self._task_filtered(df, task)

        if wlgen_profile:

            def get_task_entry(task_name):
                task = wlgen_profile[task_name]
                # Build a JSON configuration so that we get the actual number
                # of phases, after loopification at the task level
                conf = RTAConf.from_profile({task_name: task},
                                            plat_info=self.trace.plat_info)
                nr_json_phases = len(conf['tasks'][task_name]['phases'])
                return (task, nr_json_phases)

            # Map TaskID to wlgen phases
            task_map = {
                task_id: get_task_entry(task_name)
                for task_name, task_ids in RTA.resolve_trace_task_names(
                    self.trace, wlgen_profile.keys()).items()
                for task_id in task_ids
            }

            class _dict(dict):
                def __missing__(self, key):
                    raise ValueError(f'Unexpected phase number "{key}"')

            def f(df):
                pid, comm = df.name
                task_id = TaskID(pid=pid, comm=comm)
                task, nr_json_phases = task_map[task_id]
                df = df.copy(deep=False)
                phase_nr = df['thread_loop'] * nr_json_phases + df['phase']

                def add_info(get):
                    return phase_nr.map(
                        _dict({
                            i: get(phase)
                            for i, phase in enumerate(task.phases)
                        }))

                df['phase'] = add_info(lambda phase: phase.get('name'))
                df['properties'] = add_info(
                    lambda phase: dict(phase.properties))

                return df

            df = df.groupby(['__pid', '__comm'], observed=True).apply(f)

        return df
Beispiel #12
0
from lisa.wlgen.rta import RTA, Periodic
from lisa.datautils import df_filter_task_ids
import pandas as pd

setup_logging()
target = Target.from_one_conf('conf/lisa/qemu_target_default.yml')
#target = Target.from_default_conf()

rtapp_profile = {}
tasks = []
for cpu in range(4):
    tasks.append("tsk{}-{}".format(cpu, cpu))
    rtapp_profile["tsk{}".format(cpu)] = Periodic(duty_cycle_pct=50,
                                                  duration_s=120)

wload = RTA.by_profile(target, "experiment_wload", rtapp_profile)

ftrace_coll = FtraceCollector(target, events=["sched_switch"])
trace_path = os.path.join(wload.res_dir, "trace.dat")
with ftrace_coll:
    wload.run()

ftrace_coll.get_trace(trace_path)
trace = Trace(trace_path, target.plat_info, events=["sched_switch"])

# sched_switch __comm  __pid  __cpu  __line prev_comm  prev_pid  prev_prio  prev_state next_comm  next_pid  next_prio
df = trace.df_events('sched_switch')[['next_pid', 'next_comm', '__cpu']]


def analize_task_migration(task_id, ddf):
    start = ddf.index[0]