def check_from_target(cls, target): super().check_from_target(target) kconfig = target.plat_info['kernel']['config'] if not kconfig.get('UCLAMP_TASK'): ResultBundle.raise_skip( "The target's kernel needs CONFIG_UCLAMP_TASK=y kconfig enabled" )
def check_from_target(cls, target): super().check_from_target(target) try: cls._reset_fail(target, 0) except TargetStableError: ResultBundle.raise_skip( "Target can't reset the hotplug fail interface")
def exp_power(row): task_utils = row.to_dict() try: expected_utils = nrg_model.get_optimal_placements( task_utils, capacity_margin_pct)[0] except EnergyModelCapacityError: ResultBundle.raise_skip( 'The workload will result in overutilized status for all possible task placement, making it unsuitable to test EAS on this platform' ) power = nrg_model.estimate_from_cpu_util(expected_utils) columns = list(power.keys()) # Assemble a dataframe to plot the expected utilization data.append(expected_utils) index.append(row.name) return pd.Series([power[c] for c in columns], index=columns)
def check_from_target(cls, target): super().check_from_target(target) kconfig = target.plat_info['kernel']['config'] for option in ( 'CONFIG_ENERGY_MODEL', 'CONFIG_CPU_FREQ_GOV_SCHEDUTIL', ): if not kconfig.get(option): ResultBundle.raise_skip( f"The target's kernel needs {option}=y kconfig enabled") for domain in target.plat_info['freq-domains']: if "schedutil" not in target.cpufreq.list_governors(domain[0]): ResultBundle.raise_skip( f"Can't set schedutil governor for domain {domain}") if 'nrg-model' not in target.plat_info: ResultBundle.raise_skip("Energy model not available")
def get_simulated_pelt(self, task, signal_name): """ Simulate a PELT signal for a given task. :param task: task to look for in the trace. :type task: int or str or tuple(int, str) :param signal_name: Name of the PELT signal to simulate. :type signal_name: str :return: A :class:`pandas.DataFrame` with a ``simulated`` column containing the simulated signal, along with the column of the signal as found in the trace. """ logger = self.logger trace = self.trace task = trace.get_task_id(task) df_activation = trace.ana.tasks.df_task_activation( task, # Util only takes into account times where the task is actually # executing preempted_value=0, ) pinned_cpus = sorted(self.cpus) assert len(pinned_cpus) == 1 df = self._get_trace_signal(task, pinned_cpus, signal_name) df = df.copy(deep=False) # Ignore the first activation, as its signals are incorrect df_activation = df_activation.iloc[2:] # Make sure the activation df does not start before the dataframe of # signal values, otherwise we cannot provide a sensible init value df_activation = df_activation[df.index[0]:] # Get the initial signal value matching the first activation we will care about init_iloc = df.index.get_indexer([df_activation.index[0]], method='ffill')[0] init = df[signal_name].iloc[init_iloc] try: # PELT clock in nanoseconds clock = df['update_time'] * 1e-9 except KeyError: if any(self.plat_info['cpu-capacities']['rtapp'][cpu] != UTIL_SCALE for phase in self.wlgen_task.phases for cpu in phase['cpus']): ResultBundle.raise_skip( 'PELT time scaling can only be simulated when the PELT clock is available from the trace' ) logger.warning( 'PELT clock is not available, ftrace timestamp will be used at the expense of accuracy' ) clock = None try: cpus = trace.ana.tasks.cpus_of_tasks([task]) capacity = trace.ana.load_tracking.df_cpus_signal('capacity', cpus) except MissingTraceEventError: capacity = None else: capacity = capacity[['cpu', 'capacity_curr']] # We are interested in the current CPU capacity as seen by CFS. # This takes into account: # * The frequency # * The capacity of other sched classes (RT, IRQ etc) capacity = capacity.rename(columns={'capacity_curr': 'capacity'}) # Reshape the capacity dataframe so that we get one column per CPU capacity = capacity.pivot(columns=['cpu']) capacity.columns = capacity.columns.droplevel(0) capacity.ffill(inplace=True) capacity = df_refit_index(capacity, window=(df_activation.index[0], df_activation.index[-1])) # Make sure we end up with the timestamp at which the capacity # changes, rather than the timestamps at which the task is enqueued # or dequeued. activation_cpu = df_activation['cpu'].reindex(capacity.index, method='ffill') capacity = series_dereference(activation_cpu, capacity) df['simulated'] = simulate_pelt( df_activation['active'], index=df.index, init=init, clock=clock, capacity=capacity, ) # Since load is now CPU invariant in recent kernel versions, we don't # rescale it back. To match the old behavior, that line is # needed: # df['simulated'] /= self.plat_info['cpu-capacities']['rtapp'][cpu] / UTIL_SCALE kernel_version = self.plat_info['kernel']['version'] if (signal_name == 'load' and kernel_version.parts[:2] < (5, 1)): logger().warning( f'Load signal is assumed to be CPU invariant, which is true for recent mainline kernels, but may be wrong for {kernel_version}' ) df['error'] = df[signal_name] - df['simulated'] df = df.dropna() return df
def check_from_target(cls, target): super().check_from_target(target) if len(target.plat_info["capacity-classes"]) < 2: ResultBundle.raise_skip( 'Cannot test migration on single capacity group')
def check_from_target(cls, target): super().check_from_target(target) if target.number_of_nodes < 2: ResultBundle.raise_skip( "Target doesn't have at least two NUMA nodes")
def check_from_target(cls, target): super().check_from_target(target) if not cls._has_asym_cpucapacity(target): ResultBundle.raise_skip( "Target doesn't have asymmetric CPU capacities")