diff options
| -rw-r--r-- | gen/mc_generators.py | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/gen/mc_generators.py b/gen/mc_generators.py new file mode 100644 index 0000000..d6d8d90 --- /dev/null +++ b/gen/mc_generators.py | |||
| @@ -0,0 +1,205 @@ | |||
| 1 | import gen.rv as rv | ||
| 2 | |||
| 3 | from common import try_get_config_option | ||
| 4 | from gen.generator import GenOption,Generator,NAMED_UTILIZATIONS,NAMED_PERIODS | ||
| 5 | |||
| 6 | |||
| 7 | NAMED_SHARES = { | ||
| 8 | 'weighted' : [1, 1, 8, 1], | ||
| 9 | 'harmonic' : [1, 2, 4, 1], | ||
| 10 | 'fair' : [1, 1, 1, 1], | ||
| 11 | } | ||
| 12 | |||
| 13 | TP_BASE = """#for $t in $lvl{0} | ||
| 14 | {1}-g {0} -s $scale{0} $t.cost $t.period | ||
| 15 | #end for""" | ||
| 16 | TP_LVLA = """#if $lvla | ||
| 17 | /proc/litmus/plugins/MC-CE/ce_file{ | ||
| 18 | #for $t in $lvla | ||
| 19 | $t.cpu, $t.id, $t.budget | ||
| 20 | #end for | ||
| 21 | } | ||
| 22 | #end if | ||
| 23 | """ + TP_BASE.format("a", "-i $t.id -p $t.cpu ") | ||
| 24 | TP_LVLB = TP_BASE.format("b", "-p $t.cpu ") | ||
| 25 | TP_LVLC = TP_BASE.format("c", "") | ||
| 26 | TP_LVLD = """#if $be | ||
| 27 | #for $i in range($cpus) | ||
| 28 | #if $d_fifo | ||
| 29 | #set $fopt='-f' | ||
| 30 | #else | ||
| 31 | #set $fopt='' | ||
| 32 | #end if | ||
| 33 | #if d_nice | ||
| 34 | #set $nopt='-n' | ||
| 35 | #else | ||
| 36 | #set $nopt='' | ||
| 37 | #end if | ||
| 38 | bespin -s $i -f $i.misses $be_opts -p $i $fopt $nopt | ||
| 39 | #end for | ||
| 40 | #end if""" | ||
| 41 | |||
| 42 | TM_OPT = 'MERGE_TIMERS' | ||
| 43 | SS_OPT = 'PLUGIN_MC_LINUX_SLACK_STEALING' | ||
| 44 | RD_OPT = 'PLUGIN_MC_REDIRECT' | ||
| 45 | MC_OPT = 'PLUGIN_MC' | ||
| 46 | LEVELS = 3 | ||
| 47 | |||
| 48 | class McGenerator(Generator): | ||
| 49 | def __init__(self, params = {}): | ||
| 50 | super(McGenerator, self).__init__("MC", | ||
| 51 | [TP_LVLA, TP_LVLB, TP_LVLC, TP_LVLD], | ||
| 52 | self.__make_options(), | ||
| 53 | params) | ||
| 54 | |||
| 55 | def __make_options(self): | ||
| 56 | timer_merging = try_get_config_option(TM_OPT, False) | ||
| 57 | slack_stealing = try_get_config_option(SS_OPT, False) | ||
| 58 | redirect = try_get_config_option(RD_OPT, True) | ||
| 59 | |||
| 60 | return [GenOption('levels', range(1, LEVELS+1), [3], | ||
| 61 | 'Number of criticality levels: C, BC, ABC'), | ||
| 62 | GenOption('be', [True,False], [False], | ||
| 63 | 'Execute background work using bespin.'), | ||
| 64 | |||
| 65 | GenOption('timer_merging', [True,False], [timer_merging], | ||
| 66 | 'Require timer-merging support.'), | ||
| 67 | GenOption('redirect', [True,False], [redirect], | ||
| 68 | 'Redirect work to the interrupt master.'), | ||
| 69 | GenOption('slack_stealing', [True,False], [slack_stealing], | ||
| 70 | 'Schedule linux tasks in the background.'), | ||
| 71 | |||
| 72 | GenOption('d_nice', [True,False], [False], | ||
| 73 | 'Schedule level-D tasks using nice().'), | ||
| 74 | GenOption('d_fifo', [True, False], [False], | ||
| 75 | 'Schedule level-D tasks under SCHED_FIFO.'), | ||
| 76 | |||
| 77 | GenOption('a_hyperperiod', float, 25.0, | ||
| 78 | 'Level-A hyperperiod (ms).'), | ||
| 79 | Generator._dist_option('b_periods', ['harmonic'], NAMED_PERIODS, | ||
| 80 | 'Level-B task periods. Harmonic is always used if level A is present.'), | ||
| 81 | Generator._dist_option('c_periods', ['harmonic'], | ||
| 82 | NAMED_PERIODS, 'Level-C task periods.'), | ||
| 83 | |||
| 84 | Generator._dist_option('a_utils', ['bimo-light'], | ||
| 85 | NAMED_UTILIZATIONS, | ||
| 86 | 'Level-A task utilizations (at level A).'), | ||
| 87 | Generator._dist_option('b_utils', ['bimo-light'], | ||
| 88 | NAMED_UTILIZATIONS, | ||
| 89 | 'Level-B task utilizations (at level B).'), | ||
| 90 | Generator._dist_option('c_utils', ['bimo-light'], | ||
| 91 | NAMED_UTILIZATIONS, | ||
| 92 | 'Level-C task utilizations (at level C).'), | ||
| 93 | |||
| 94 | Generator._dist_option('shares', ['fair'], NAMED_SHARES, | ||
| 95 | 'Distribution of actual utilizations.')] | ||
| 96 | |||
| 97 | def __partition_worst_fit(self, params, ts): | ||
| 98 | # Partition using worst-fit for most even distribution | ||
| 99 | utils = [0]*int(params['cpus']) | ||
| 100 | tasks = [0]*int(params['cpus']) | ||
| 101 | for t in ts: | ||
| 102 | t.cpu = utils.index(min(utils)) | ||
| 103 | t.id = tasks[t.cpu] | ||
| 104 | |||
| 105 | utils[t.cpu] += t.utilization() | ||
| 106 | tasks[t.cpu] += 1 | ||
| 107 | |||
| 108 | def __adjust(self, params, level): | ||
| 109 | # Adjust for levels which aren't used | ||
| 110 | ldiff = LEVELS - params['levels'] | ||
| 111 | shares = self.shares[ldiff:] | ||
| 112 | level -= ldiff | ||
| 113 | |||
| 114 | return shares, level | ||
| 115 | |||
| 116 | def __get_max_util(self, params, level): | ||
| 117 | shares, level = self.__adjust(params, level) | ||
| 118 | return float(shares[level]) / sum(shares[:level]) * params['cpus'] | ||
| 119 | |||
| 120 | def __get_scale(self, params, level): | ||
| 121 | shares, level = self.__adjust(params, level) | ||
| 122 | return float(shares[level]) / sum(shares) | ||
| 123 | |||
| 124 | def __create_lvla_sched(self, params): | ||
| 125 | if params['levels'] < 3: | ||
| 126 | return [] | ||
| 127 | |||
| 128 | utils = self._create_dist('utilization', params['a_utils'], | ||
| 129 | NAMED_UTILIZATIONS) | ||
| 130 | periods = self._create_dist('period', params['a_hyperperiod'], None) | ||
| 131 | |||
| 132 | ts = self._create_taskset(params, periods, utils) | ||
| 133 | |||
| 134 | # Make the budget used by the cyclic executive larger than the | ||
| 135 | # actual WCET because of overheads | ||
| 136 | for t in ts: | ||
| 137 | t.budget = int(1.05 * 1000000 * t.cost) | ||
| 138 | t.wcet = int(t.cost) | ||
| 139 | |||
| 140 | self.__partition_worst_fit(params, ts) | ||
| 141 | |||
| 142 | return ts | ||
| 143 | |||
| 144 | def __create_lvlb_sched(self, params): | ||
| 145 | if params['levels'] < 2: | ||
| 146 | return [] | ||
| 147 | |||
| 148 | utils = self._create_dist('utilization', params['b_utils'], | ||
| 149 | NAMED_UTILIZATIONS) | ||
| 150 | |||
| 151 | # Level-A is present, b must be harmonic with lvla hyperperiod | ||
| 152 | if params['levels'] > 2: | ||
| 153 | plist = [params['a_hyperperiod']*2**x for x in xrange(0, 4)] | ||
| 154 | periods = rv.uniform_choice(plist) | ||
| 155 | else: | ||
| 156 | periods = self._create_dist('period', params['b_periods'], | ||
| 157 | NAMED_PERIODS) | ||
| 158 | max_util = self.__get_max_util(params, 1) | ||
| 159 | |||
| 160 | ts = self._create_taskset(params, periods, utils, max_util) | ||
| 161 | self.__partition_worst_fit(params, ts) | ||
| 162 | |||
| 163 | return ts | ||
| 164 | |||
| 165 | def __create_lvlc_sched(self, params): | ||
| 166 | utils = self._create_dist('utilization', params['c_utils'], | ||
| 167 | NAMED_UTILIZATIONS) | ||
| 168 | periods = self._create_dist('period', params['c_periods'], | ||
| 169 | NAMED_PERIODS) | ||
| 170 | max_util = self.__get_max_util(params, 2) | ||
| 171 | |||
| 172 | return self._create_taskset(params, periods, utils, max_util) | ||
| 173 | |||
| 174 | def _create_exp(self, params): | ||
| 175 | # Ugly way of doing it | ||
| 176 | self.shares = self._create_dist('shares', params['shares'], | ||
| 177 | NAMED_SHARES) | ||
| 178 | |||
| 179 | tasks = {'lvla': self.__create_lvla_sched(params), | ||
| 180 | 'lvlb': self.__create_lvlb_sched(params), | ||
| 181 | 'lvlc': self.__create_lvlc_sched(params)} | ||
| 182 | |||
| 183 | conf_options = {MC_OPT : 'y'} | ||
| 184 | if params['timer_merging']: | ||
| 185 | conf_options[TM_OPT] = 'y' | ||
| 186 | if params['redirect']: | ||
| 187 | if not params['release_master']: | ||
| 188 | print("Forcing release master option to enable redirection.") | ||
| 189 | params['release_master'] = 'y' | ||
| 190 | conf_options[RD_OPT] = 'y' | ||
| 191 | if params['slack_stealing']: | ||
| 192 | conf_options[SS_OPT] = 'y' | ||
| 193 | |||
| 194 | scales = [] | ||
| 195 | for index, level in enumerate('abc'): | ||
| 196 | scales += [('scale%s' % level, self.__get_scale(params, index))] | ||
| 197 | |||
| 198 | schedule_variables = params.items() + tasks.items() + scales | ||
| 199 | param_variables = params.items() + [('config-options',conf_options)] | ||
| 200 | |||
| 201 | self._write_schedule(dict(schedule_variables)) | ||
| 202 | self._write_params(dict(param_variables)) | ||
| 203 | |||
| 204 | # Ugly | ||
| 205 | del(self.shares) | ||
