def run_workload(cls): big_cpu = cls.env.target.bl.bigs[0] big_cpufreq = "/sys/devices/system/cpu/cpu{}/cpufreq".format(big_cpu) max_freq_path = os.path.join(big_cpufreq, "scaling_max_freq") available_freqs_path = os.path.join(big_cpufreq, "scaling_available_frequencies") available_freqs_str = cls.env.target.read_value(available_freqs_path) available_freqs = available_freqs_str.split() min_frequency = available_freqs[0] max_frequency = available_freqs[-1] wload = RTA(cls.env.target, "busy_threads", calibration=cls.env.calibration()) wload.conf(kind="profile", params=cls.params) phase_duration = WORKLOAD_DURATION_S / 3. cls.env.ftrace.start() wload.run(out_dir=cls.env.res_dir, background=True) time.sleep(phase_duration) cls.env.target.write_value(max_freq_path, min_frequency) time.sleep(phase_duration) cls.env.target.write_value(max_freq_path, max_frequency) time.sleep(phase_duration) cls.env.ftrace.stop() cls.env.ftrace.get_trace(cls.trace_file)
def _do_test(self, task, exp_phases): rtapp = RTA(self.target, name='test', calibration=self.calibration) rtapp.conf( kind = 'profile', params = {'my_task': task.get()}, run_dir=self.target_run_dir ) with open(rtapp.json) as f: conf = json.load(f, object_pairs_hook=OrderedDict) # Check that the configuration looks like we expect it to phases = conf['tasks']['my_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(out_dir=self.host_out_dir) 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_00.json') self.assert_output_file_exists('rt-app-my_task-0.log') self.assert_can_read_logfile(exp_tasks=['my_task'])
def __init__(self, name, test_env, cpus, period_ms=100, duty_cycle_pct=50, duration_s=1, kind='profile', num_tasks=1): super(Task, self).__init__("task") self.name = name self.period_ms = period_ms self.duty_cycle_pct = duty_cycle_pct self.duration_s = duration_s self.cpus = cpus allowed_kinds = ['profile', 'custom'] if kind not in allowed_kinds: raise ValueError('{} not allowed, kind can be one of {}' .format(kind, allowed_kinds)) self.kind = kind self.num_tasks = num_tasks # Create rt-app workload t = Periodic(period_ms=period_ms, duty_cycle_pct=duty_cycle_pct, duration_s=duration_s).get() self.wload = RTA(test_env.target, name, test_env.calibration()) if num_tasks > 1: conf_params = {name + "_{}".format(i): t for i in xrange(num_tasks)} else: conf_params = {name: t} self.wload.conf(kind=kind, params=conf_params, run_dir=test_env.target.working_directory)
def populate_params(cls): for idx in range(len(cls.env.target.bl.bigs)): task = cls.task_prefix + str(idx) cls.params[task] = RTA.periodic(**BIG_WORKLOAD) for idx in range(len(cls.env.target.bl.littles)): task = cls.task_prefix + str(idx) cls.params[task] = RTA.periodic(**SMALL_WORKLOAD)
def _get_calib_conf(self, calibration): rtapp = RTA(self.target, name='test', calibration=calibration) rtapp.conf(kind='profile', params={'t1': Periodic().get()}, run_dir=self.target_run_dir) with open(rtapp.json) as f: return json.load(f)['global']['calibration']
def _get_calib_conf(self, calibration): rtapp = RTA(self.target, name='test', calibration=calibration) rtapp.conf( kind = 'profile', params = {'t1': Periodic().get()}, run_dir=self.target_run_dir ) with open(rtapp.json) as f: return json.load(f)['global']['calibration']
def run_workload(cls): wload = RTA( cls.env.target, "wake_migration", calibration=cls.env.calibration()) wload.conf(kind="profile", params=cls.params) cls.env.ftrace.start() wload.run( out_dir=cls.env.res_dir, background=False) cls.env.ftrace.stop() trace = cls.env.ftrace.get_trace(cls.trace_file)
def populate_tasks(cls): migrator_workload = BIG_WORKLOAD.copy() migrator_workload["duration_s"] = 9 migrator_workload["delay_s"] = 1 for idx in range(cls.num_tasks): task = "early_starters" + str(idx) cls.params[task] = RTA.periodic(**BIG_WORKLOAD) cls.early_starters.append(task) # Tasks that will be idle pulled task = "migrator" + str(idx) cls.params[task] = RTA.periodic(**migrator_workload) cls.migrators.append(task)
def calibration(self, force=False): if not force and self._calib: return self._calib required = False if force: required = True if 'rt-app' in self.__tools: required = True elif 'wloads' in self.conf: wloads = self.conf['wloads'] for wl_idx in wloads: if 'rt-app' in wloads[wl_idx]['type']: required = True break if not required: logging.debug('No RT-App workloads, skipping calibration') return if not force and 'rtapp-calib' in self.conf: logging.info('Loading RTApp calibration from configuration file...') self._calib = { int(key): int(value) for key, value in self.conf['rtapp-calib'].items() } else: logging.info('Calibrating RTApp...') self._calib = RTA.calibrate(self.target) logging.info('Using RT-App calibration values: %s', "{" + ", ".join('"%r": %r' % (key, self._calib[key]) for key in sorted(self._calib)) + "}") return self._calib
def calibration(self, force=False): """ Get rt-app calibration. Run calibration on target if necessary. :param force: Always run calibration on target, even if we have not installed rt-app or have already run calibration. :returns: A dict with calibration results, which can be passed as the ``calibration`` parameter to :class:`RTA`, or ``None`` if force=False and we have not installed rt-app. """ if not force and self._calib: return self._calib required = force or 'rt-app' in self.__installed_tools if not required: self._log.debug('No RT-App workloads, skipping calibration') return if not force and 'rtapp-calib' in self.conf: self._log.warning('Using configuration provided RTApp calibration') self._calib = { int(key): int(value) for key, value in self.conf['rtapp-calib'].items() } else: self._log.info('Calibrating RTApp...') self._calib = RTA.calibrate(self.target) self._log.info('Using RT-App calibration values:') self._log.info(' %s', "{" + ", ".join('"%r": %r' % (key, self._calib[key]) for key in sorted(self._calib)) + "}") return self._calib
def _do_test(self, task, exp_phases): rtapp = RTA(self.target, name='test', calibration=self.calibration) rtapp.conf(kind='profile', params={'my_task': task.get()}, run_dir=self.target_run_dir) with open(rtapp.json) as f: conf = json.load(f, object_pairs_hook=OrderedDict) # Check that the configuration looks like we expect it to phases = conf['tasks']['my_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(out_dir=self.host_out_dir) 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_00.json') self.assert_output_file_exists('rt-app-my_task-0.log') self.assert_can_read_logfile(exp_tasks=['my_task'])
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(os.getenv('LISA_HOME'), 'assets', 'mp3-short.json') rtapp = RTA(self.target, name='test', calibration=calibration) # Configure this RTApp instance to: rtapp.conf(kind='custom', params=json_path, duration=5, run_dir=self.target_run_dir) with open(rtapp.json) as f: conf = json.load(f) # Convert k to str because the json loader gives us unicode strings tasks = set([str(k) for k in conf['tasks'].keys()]) self.assertSetEqual( tasks, set(['AudioTick', 'AudioOut', 'AudioTrack', 'mp3.decoder', 'OMXCall'])) # 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(out_dir=self.host_out_dir) 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_00.json')
def populate_params(cls): cls.rtapp = RTA(cls.target,cls.rta_name) cls.rtapp.conf( kind='profile', params={ cls.task_name: Periodic( period_ms=40, duty_cycle_pct=1, duration_s=2, cpus=cls.test_cpu, ).get(), }, run_dir='/tmp' )
def run_workload(cls): wload = RTA(cls.env.target, "wake_migration", calibration=cls.env.calibration()) wload.conf(kind="profile", params=cls.params) cls.env.ftrace.start() wload.run(out_dir=cls.env.res_dir, background=False) cls.env.ftrace.stop() trace = cls.env.ftrace.get_trace(cls.trace_file)
def calibration(self, force=False): if not force and self._calib: return self._calib required = False if force: required = True if 'rt-app' in self.__tools: required = True elif 'wloads' in self.conf: wloads = self.conf['wloads'] for wl_idx in wloads: if 'rt-app' in wloads[wl_idx]['type']: required = True break if not required: logging.debug('No RT-App workloads, skipping calibration') return if not force and 'rtapp-calib' in self.conf: logging.warning( r'%14s - Using configuration provided RTApp calibration', 'Target') self._calib = { int(key): int(value) for key, value in self.conf['rtapp-calib'].items() } else: logging.info(r'%14s - Calibrating RTApp...', 'Target') self._calib = RTA.calibrate(self.target) logging.info(r'%14s - Using RT-App calibration values:', 'Target') logging.info( r'%14s - %s', 'Target', "{" + ", ".join('"%r": %r' % (key, self._calib[key]) for key in sorted(self._calib)) + "}") return self._calib
def test_profile_periodic_smoke(self): """ Smoketest Periodic rt-app workload Creates a workload using Periodic, tests that the JSON has the expected content, then tests that it can be run. """ rtapp = RTA(self.target, name='test', calibration=self.calibration) rtapp.conf(kind='profile', params={ 'task_p20': Periodic( period_ms=100, duty_cycle_pct=20, duration_s=1, ).get(), }, run_dir=self.target_run_dir) with open(rtapp.json) as f: conf = json.load(f) [phase] = conf['tasks']['task_p20']['phases'].values() self.assertDictEqual( phase, { 'loop': 10, 'run': 20000, 'timer': { 'period': 100000, 'ref': 'task_p20' } }) rtapp.run(out_dir=self.host_out_dir) 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_00.json') self.assert_output_file_exists('rt-app-task_p20-0.log') self.assert_can_read_logfile(exp_tasks=['task_p20'])
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(os.getenv('LISA_HOME'), 'assets', 'mp3-short.json') rtapp = RTA(self.target, name='test', calibration=calibration) # Configure this RTApp instance to: rtapp.conf(kind='custom', params=json_path, duration=5, run_dir=self.target_run_dir) with open(rtapp.json) as f: conf = json.load(f) # Convert k to str because the json loader gives us unicode strings tasks = set([str(k) for k in conf['tasks'].keys()]) self.assertSetEqual( tasks, set([ 'AudioTick', 'AudioOut', 'AudioTrack', 'mp3.decoder', 'OMXCall' ])) # 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(out_dir=self.host_out_dir) 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_00.json')
def run_workload(cls): big_cpu = cls.env.target.bl.bigs[0] big_cpufreq = "/sys/devices/system/cpu/cpu{}/cpufreq".format(big_cpu) max_freq_path = os.path.join(big_cpufreq, "scaling_max_freq") available_freqs_path = os.path.join(big_cpufreq, "scaling_available_frequencies") available_freqs_str = cls.env.target.read_value(available_freqs_path) available_freqs = available_freqs_str.split() min_frequency = available_freqs[0] max_frequency = available_freqs[-1] wload = RTA(cls.env.target, "busy_threads", calibration=cls.env.calibration()) wload.conf(kind="profile", params=cls.params) phase_duration = WORKLOAD_DURATION_S / 3. cls.env.ftrace.start() wload.run(out_dir=cls.env.res_dir, background=True) time.sleep(phase_duration) # Writing values on the target can take a non-negligible amount of time. # To prevent this from shifting the transitions between # constrained/unconstrained phases, measure this write latency and # reduce our sleep time by that amount. def write_and_sleep(max_freq): time_before = time.time() cls.env.target.write_value(max_freq_path, max_freq) write_latency = time.time() - time_before if (write_latency > phase_duration): raise ValueError( "Latency of Target.write_value greater than phase duration! " "Increase WORKLOAD_DURATION_S or speed up target connection") time.sleep(phase_duration - write_latency) write_and_sleep(min_frequency) write_and_sleep(max_frequency) cls.env.ftrace.stop() cls.env.ftrace.get_trace(cls.trace_file)
class Task(SchedEntity): """ Task Entity class :param name: Name of the task. :type name: str :param test_env: Test environment. :type test_env: env.TestEnv :param cpus: List of CPUs the workload can run on. :type cpus: list(int) :param period_ms: Period of each task in milliseconds. :type period_ms: int :param duty_cycle_pct: Dduty cycle of the periodic workload. Default 50% :type duty_cycle_pct: int :param duration_s: Total duration of the workload. Default 1 second. :type duration_s: int :param kind: Type of RTA workload. Can be 'profile' or 'custom'. Default value is 'profile'. :type kind: str :param num_tasks: Number of tasks to spawn. :type num_tasks: int """ def __init__(self, name, test_env, cpus, period_ms=100, duty_cycle_pct=50, duration_s=1, kind='profile', num_tasks=1): super(Task, self).__init__("task") self.name = name self.period_ms = period_ms self.duty_cycle_pct = duty_cycle_pct self.duration_s = duration_s self.cpus = cpus allowed_kinds = ['profile', 'custom'] if kind not in allowed_kinds: raise ValueError('{} not allowed, kind can be one of {}'.format( kind, allowed_kinds)) self.kind = kind self.num_tasks = num_tasks # Create rt-app workload t = Periodic(period_ms=period_ms, duty_cycle_pct=duty_cycle_pct, duration_s=duration_s).get() self.wload = RTA(test_env.target, name, test_env.calibration()) if num_tasks > 1: conf_params = { name + "_{}".format(i): t for i in xrange(num_tasks) } else: conf_params = {name: t} self.wload.conf(kind=kind, params=conf_params, run_dir=test_env.target.working_directory) def __repr__(self): return "Task: " + self.name def add_children(self, ses): raise TypeError('Cannot add children entities to a task entity.') def get_expected_util(self): """ Get expected utilization value. For tasks this corresponds to corresponds to the duty cycle of the task. :returns: int - expected utilization of the task """ return 1024 * (self.duty_cycle_pct * self.num_tasks / 100.0)
def populate_params(cls): cls.params[cls.task_prefix] = RTA.step(**STEP_WORKLOAD) cls.params[cls.task_prefix + "1"] = RTA.step(**STEP_WORKLOAD)
def populate_params(cls): for i in range(cls.num_tasks): task = cls.task_prefix + str(i) cls.params[task] = RTA.periodic(**SMALL_WORKLOAD)
class Task(SchedEntity): """ Task Entity class :param name: Name of the task. :type name: str :param test_env: Test environment. :type test_env: env.TestEnv :param cpus: List of CPUs the workload can run on. :type cpus: list(int) :param period_ms: Period of each task in milliseconds. :type period_ms: int :param duty_cycle_pct: Dduty cycle of the periodic workload. Default 50% :type duty_cycle_pct: int :param duration_s: Total duration of the workload. Default 1 second. :type duration_s: int :param kind: Type of RTA workload. Can be 'profile' or 'custom'. Default value is 'profile'. :type kind: str :param num_tasks: Number of tasks to spawn. :type num_tasks: int """ def __init__(self, name, test_env, cpus, period_ms=100, duty_cycle_pct=50, duration_s=1, kind='profile', num_tasks=1): super(Task, self).__init__("task") self.name = name self.period_ms = period_ms self.duty_cycle_pct = duty_cycle_pct self.duration_s = duration_s self.cpus = cpus allowed_kinds = ['profile', 'custom'] if kind not in allowed_kinds: raise ValueError('{} not allowed, kind can be one of {}' .format(kind, allowed_kinds)) self.kind = kind self.num_tasks = num_tasks # Create rt-app workload t = Periodic(period_ms=period_ms, duty_cycle_pct=duty_cycle_pct, duration_s=duration_s).get() self.wload = RTA(test_env.target, name, test_env.calibration()) if num_tasks > 1: conf_params = {name + "_{}".format(i): t for i in xrange(num_tasks)} else: conf_params = {name: t} self.wload.conf(kind=kind, params=conf_params, run_dir=test_env.target.working_directory) def __repr__(self): return "Task: " + self.name def add_children(self, ses): raise TypeError('Cannot add children entities to a task entity.') def get_expected_util(self): """ Get expected utilization value. For tasks this corresponds to corresponds to the duty cycle of the task. :returns: int - expected utilization of the task """ return 1024 * (self.duty_cycle_pct * self.num_tasks / 100.0)
def test_composition(self): """ Test RTA task composition with __add__ Creates a composed workload by +-ing RTATask objects, tests that the JSON has the expected content, then tests running the workload """ rtapp = RTA(self.target, name='test', calibration=self.calibration) light = Periodic(duty_cycle_pct=10, duration_s=1.0, period_ms=10) start_pct = 10 end_pct = 90 delta_pct = 20 num_ramp_phases = ((end_pct - start_pct) / delta_pct) + 1 ramp = Ramp(start_pct=start_pct, end_pct=end_pct, delta_pct=delta_pct, time_s=1, period_ms=50) heavy = Periodic(duty_cycle_pct=90, duration_s=0.1, period_ms=100) lrh_task = light + ramp + heavy rtapp.conf(kind='profile', params={'task_ramp': lrh_task.get()}, run_dir=self.target_run_dir) with open(rtapp.json) as f: conf = json.load(f, object_pairs_hook=OrderedDict) phases = conf['tasks']['task_ramp']['phases'].values() exp_phases = [ # Light phase: { "loop": 100, "run": 1000, "timer": { "period": 10000, "ref": "task_ramp" } }, # Ramp phases: { "loop": 20, "run": 5000, "timer": { "period": 50000, "ref": "task_ramp" } }, { "loop": 20, "run": 15000, "timer": { "period": 50000, "ref": "task_ramp" } }, { "loop": 20, "run": 25000, "timer": { "period": 50000, "ref": "task_ramp" } }, { "loop": 20, "run": 35000, "timer": { "period": 50000, "ref": "task_ramp" } }, { "loop": 20, "run": 45000, "timer": { "period": 50000, "ref": "task_ramp" } }, # Heavy phase: { "loop": 1, "run": 90000, "timer": { "period": 100000, "ref": "task_ramp" } } ] self.assertListEqual(phases, exp_phases) rtapp.run(out_dir=self.host_out_dir) 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_00.json') self.assert_output_file_exists('rt-app-task_ramp-0.log') self.assert_can_read_logfile(exp_tasks=['task_ramp'])