diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-03-30 11:30:01 -0400 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-04-15 11:38:30 -0400 |
commit | 7cef798367892aff5ae76780b15c3a0f135d0234 (patch) | |
tree | 406b88703d51b750c11180e1d9eaebd78a3edcda | |
parent | 625e0f2d3fd50f079c7eb84825992b70421bd78e (diff) |
Added mixed-criticality generator.
-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) | ||