diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-04-05 14:24:33 -0400 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-04-15 11:42:33 -0400 |
commit | f659a11e1c888b01cce64fee5ae064a67aa4d777 (patch) | |
tree | 4e33cbaa54a697c119e5f30b1bf84fb22db94cba | |
parent | 7cef798367892aff5ae76780b15c3a0f135d0234 (diff) |
Added ColorMcGenerator.
-rw-r--r-- | gen/__init__.py | 3 | ||||
-rw-r--r-- | gen/color.py | 102 | ||||
-rw-r--r-- | gen/generator.py | 35 | ||||
-rw-r--r-- | gen/mc_generators.py | 206 |
4 files changed, 316 insertions, 30 deletions
diff --git a/gen/__init__.py b/gen/__init__.py index 8c60b46..803bb37 100644 --- a/gen/__init__.py +++ b/gen/__init__.py | |||
@@ -1,6 +1,9 @@ | |||
1 | import generator as gen | 1 | import generator as gen |
2 | import edf_generators as edf | 2 | import edf_generators as edf |
3 | import mc_generators as mc | ||
3 | 4 | ||
4 | gen.register_generator("G-EDF", edf.GedfGenerator) | 5 | gen.register_generator("G-EDF", edf.GedfGenerator) |
5 | gen.register_generator("P-EDF", edf.PedfGenerator) | 6 | gen.register_generator("P-EDF", edf.PedfGenerator) |
6 | gen.register_generator("C-EDF", edf.CedfGenerator) | 7 | gen.register_generator("C-EDF", edf.CedfGenerator) |
8 | gen.register_generator("MC", mc.McGenerator) | ||
9 | gen.register_generator("Color-MC", mc.ColorMcGenerator) | ||
diff --git a/gen/color.py b/gen/color.py new file mode 100644 index 0000000..8184b8b --- /dev/null +++ b/gen/color.py | |||
@@ -0,0 +1,102 @@ | |||
1 | import os | ||
2 | import re | ||
3 | |||
4 | from collections import namedtuple,defaultdict | ||
5 | from math import ceil | ||
6 | from random import randint | ||
7 | |||
8 | class ColorScheme(object): | ||
9 | def __init__(self, colors, ways): | ||
10 | self.colors = colors | ||
11 | self.ways = ways | ||
12 | |||
13 | def color(self, tasks, wss): | ||
14 | '''Assign a color->replicas dict to each task in tasks.''' | ||
15 | raise NotImplementedError | ||
16 | |||
17 | class BlockColorScheme(ColorScheme): | ||
18 | def __init__(self, colors, ways, way_first): | ||
19 | super(BlockColorScheme, self).__init__(colors, ways) | ||
20 | self.way_first = way_first | ||
21 | |||
22 | def color(self, tasks, pages_needed): | ||
23 | '''Pages are assigned in blocks, either maximizing the number of ways | ||
24 | or maximizing the number of colors used.''' | ||
25 | cpus = defaultdict(list) | ||
26 | for t in tasks: | ||
27 | cpus[t.cpu].append(t) | ||
28 | |||
29 | if self.way_first: | ||
30 | # Way first means maximize ways | ||
31 | pages_per_color = min(self.ways, pages_needed) | ||
32 | colors_per_task = int(ceil(pages_needed/pages_per_color)) | ||
33 | else: | ||
34 | # Color first means maximize colors | ||
35 | colors_per_task = min(self.colors, pages_needed) | ||
36 | pages_per_color = int(ceil(pages_needed/colors_per_task)) | ||
37 | |||
38 | curr_color = 0 | ||
39 | for cpu, tasks in cpus.iteritems(): | ||
40 | # All tasks on a CPU have the same coloring scheme | ||
41 | cpu_colors = defaultdict(int) | ||
42 | for _ in xrange(colors_per_task): | ||
43 | curr_color = (curr_color + 1) % self.colors | ||
44 | cpu_colors[curr_color] = pages_per_color | ||
45 | |||
46 | for t in tasks: | ||
47 | t.colors = cpu_colors | ||
48 | |||
49 | class RandomColorScheme(ColorScheme): | ||
50 | def color(self, tasks, pages_needed): | ||
51 | '''Pages are placed randomly in the cache''' | ||
52 | if pages_needed >= self.ways * self.colors: | ||
53 | raise Exception("Too many pages: %d > %d * %d" % | ||
54 | (pages_needed, self.ways, self.colors)) | ||
55 | |||
56 | for t in tasks: | ||
57 | t.colors = defaultdict(int) | ||
58 | |||
59 | for _ in xrange(pages_needed): | ||
60 | # Find the next color with available ways | ||
61 | while True: | ||
62 | next_color = randint(0, self.colors - 1) | ||
63 | if t.colors[next_color] != self.ways: | ||
64 | break | ||
65 | |||
66 | t.colors[next_color] += 1; | ||
67 | |||
68 | class EvilColorScheme(ColorScheme): | ||
69 | def color(self, tasks, pages_needed): | ||
70 | '''All tasks' working sets are placed at the front of the cache''' | ||
71 | colors = defaultdict(int) | ||
72 | color = 0 | ||
73 | |||
74 | while pages_needed > 0: | ||
75 | colors[color] = min(self.ways, pages_needed) | ||
76 | pages_needed -= colors[color] | ||
77 | |||
78 | color += 1 | ||
79 | |||
80 | for t in tasks: | ||
81 | t.colors = colors | ||
82 | |||
83 | |||
84 | INFO_FIELDS = ['cache', 'line', 'page', 'ways', 'sets', 'colors'] | ||
85 | INFO_PROC = '/proc/sys/litmus/color/cache_info' | ||
86 | |||
87 | # Build parsing regex | ||
88 | FIELD_REGEX = r"(?:.*?{0}.*?(?P<{0}>\d+).*?)" | ||
89 | INFO_REGEX = "|".join([FIELD_REGEX.format(field) for field in INFO_FIELDS]) | ||
90 | INFO_REGEX = r"(?:{})*".format(INFO_REGEX) | ||
91 | |||
92 | # To fill up this | ||
93 | CacheInfo = namedtuple('CacheInfo', INFO_FIELDS) | ||
94 | |||
95 | def get_cache_info(): | ||
96 | if os.path.exists(INFO_PROC): | ||
97 | with open(INFO_PROC, 'r') as f: | ||
98 | data = f.read() | ||
99 | values = re.search(INFO_REGEX, data, re.M|re.I|re.S).groupdict() | ||
100 | return CacheInfo(**values) | ||
101 | else: | ||
102 | return None | ||
diff --git a/gen/generator.py b/gen/generator.py index f35a22b..1205490 100644 --- a/gen/generator.py +++ b/gen/generator.py | |||
@@ -51,38 +51,44 @@ class Generator(object): | |||
51 | This class also performs checks of parameter values and prints out help. | 51 | This class also performs checks of parameter values and prints out help. |
52 | All subclasses must implement _create_exp. | 52 | All subclasses must implement _create_exp. |
53 | ''' | 53 | ''' |
54 | def __init__(self, scheduler, templates, options, params): | 54 | def __init__(self, name, templates, options, params): |
55 | self.__make_defaults(params) | ||
56 | |||
55 | self.options = self.__make_options(params) + options | 57 | self.options = self.__make_options(params) + options |
56 | 58 | ||
57 | self.__setup_params(params) | 59 | self.__setup_params(params) |
58 | 60 | ||
59 | self.params = params | 61 | self.params = params |
60 | self.template = "\n".join([TP_RM] + templates) | 62 | self.template = "\n".join([TP_RM] + templates) |
61 | self.scheduler = scheduler | 63 | self.scheduler = name |
62 | |||
63 | def __make_options(self, params): | ||
64 | '''Return generic Litmus options.''' | ||
65 | 64 | ||
66 | # Guess defaults using the properties of this computer | 65 | def __make_defaults(self, params): |
66 | '''Guess defaults using the properties of this computer''' | ||
67 | if 'cpus' in params: | 67 | if 'cpus' in params: |
68 | cpus = min(map(int, params['cpus'])) | 68 | self.cpus = min(map(int, params['cpus'])) |
69 | else: | 69 | else: |
70 | cpus = num_cpus() | 70 | self.cpus = num_cpus() |
71 | try: | 71 | try: |
72 | config = get_config_option("RELEASE_MASTER") and True | 72 | config = get_config_option("RELEASE_MASTER") and True |
73 | except: | 73 | except: |
74 | config = False | 74 | config = False |
75 | release_master = list(set([False, config])) | 75 | self.release_master = list(set([False, config])) |
76 | 76 | ||
77 | 77 | ||
78 | return [GenOption('tasks', int, range(cpus, 5*cpus, cpus), | 78 | def __make_options(self, params): |
79 | 'Number of tasks per experiment.'), | 79 | '''Return generic Litmus options.''' |
80 | GenOption('cpus', int, [cpus], | 80 | return [GenOption('num_tasks', int, |
81 | range(self.cpus, 5*self.cpus, self.cpus), | ||
82 | 'Number of tasks per experiment.'), | ||
83 | GenOption('cpus', int, [self.cpus], | ||
81 | 'Number of processors on target system.'), | 84 | 'Number of processors on target system.'), |
82 | GenOption('release_master', [True,False], release_master, | 85 | GenOption('release_master', [True,False], self.release_master, |
83 | 'Redirect release interrupts to a single CPU.'), | 86 | 'Redirect release interrupts to a single CPU.'), |
84 | GenOption('duration', float, [30], 'Experiment duration.')] | 87 | GenOption('duration', float, [30], 'Experiment duration.')] |
85 | 88 | ||
89 | def _num_cpus(self): | ||
90 | return self.cpus | ||
91 | |||
86 | @staticmethod | 92 | @staticmethod |
87 | def _dist_option(name, default, distribution, help): | 93 | def _dist_option(name, default, distribution, help): |
88 | return GenOption(name, [str, float, type([])] + distribution.keys(), | 94 | return GenOption(name, [str, float, type([])] + distribution.keys(), |
@@ -119,6 +125,9 @@ class Generator(object): | |||
119 | max_util) | 125 | max_util) |
120 | return ts | 126 | return ts |
121 | 127 | ||
128 | def _out_dir(self): | ||
129 | return self.out_dir | ||
130 | |||
122 | def _write_schedule(self, params): | 131 | def _write_schedule(self, params): |
123 | '''Write schedule file using current template for @params.''' | 132 | '''Write schedule file using current template for @params.''' |
124 | sched_file = self.out_dir + "/" + DEFAULTS['sched_file'] | 133 | sched_file = self.out_dir + "/" + DEFAULTS['sched_file'] |
diff --git a/gen/mc_generators.py b/gen/mc_generators.py index d6d8d90..bbb1ab9 100644 --- a/gen/mc_generators.py +++ b/gen/mc_generators.py | |||
@@ -1,5 +1,6 @@ | |||
1 | import gen.rv as rv | 1 | import gen.rv as rv |
2 | 2 | ||
3 | from color import get_cache_info,CacheInfo,BlockColorScheme,RandomColorScheme,EvilColorScheme | ||
3 | from common import try_get_config_option | 4 | from common import try_get_config_option |
4 | from gen.generator import GenOption,Generator,NAMED_UTILIZATIONS,NAMED_PERIODS | 5 | from gen.generator import GenOption,Generator,NAMED_UTILIZATIONS,NAMED_PERIODS |
5 | 6 | ||
@@ -16,11 +17,11 @@ TP_BASE = """#for $t in $lvl{0} | |||
16 | TP_LVLA = """#if $lvla | 17 | TP_LVLA = """#if $lvla |
17 | /proc/litmus/plugins/MC-CE/ce_file{ | 18 | /proc/litmus/plugins/MC-CE/ce_file{ |
18 | #for $t in $lvla | 19 | #for $t in $lvla |
19 | $t.cpu, $t.id, $t.budget | 20 | $t.cpu, $t.lvla_id, $t.budget |
20 | #end for | 21 | #end for |
21 | } | 22 | } |
22 | #end if | 23 | #end if |
23 | """ + TP_BASE.format("a", "-i $t.id -p $t.cpu ") | 24 | """ + TP_BASE.format("a", "-i $t.lvla_id -p $t.cpu ") |
24 | TP_LVLB = TP_BASE.format("b", "-p $t.cpu ") | 25 | TP_LVLB = TP_BASE.format("b", "-p $t.cpu ") |
25 | TP_LVLC = TP_BASE.format("c", "") | 26 | TP_LVLC = TP_BASE.format("c", "") |
26 | TP_LVLD = """#if $be | 27 | TP_LVLD = """#if $be |
@@ -46,10 +47,12 @@ MC_OPT = 'PLUGIN_MC' | |||
46 | LEVELS = 3 | 47 | LEVELS = 3 |
47 | 48 | ||
48 | class McGenerator(Generator): | 49 | class McGenerator(Generator): |
49 | def __init__(self, params = {}): | 50 | def __init__(self, name="MC", |
50 | super(McGenerator, self).__init__("MC", | 51 | templates=[TP_LVLA, TP_LVLB, TP_LVLC, TP_LVLD], |
51 | [TP_LVLA, TP_LVLB, TP_LVLC, TP_LVLD], | 52 | options=[], params={}): |
52 | self.__make_options(), | 53 | super(McGenerator, self).__init__(name, |
54 | templates, | ||
55 | self.__make_options() + options, | ||
53 | params) | 56 | params) |
54 | 57 | ||
55 | def __make_options(self): | 58 | def __make_options(self): |
@@ -92,34 +95,46 @@ class McGenerator(Generator): | |||
92 | 'Level-C task utilizations (at level C).'), | 95 | 'Level-C task utilizations (at level C).'), |
93 | 96 | ||
94 | Generator._dist_option('shares', ['fair'], NAMED_SHARES, | 97 | Generator._dist_option('shares', ['fair'], NAMED_SHARES, |
95 | 'Distribution of actual utilizations.')] | 98 | 'Distribution of runtime utilizations.')] |
96 | 99 | ||
97 | def __partition_worst_fit(self, params, ts): | 100 | def __partition_worst_fit(self, params, ts): |
101 | cpus = int(params['cpus']) | ||
102 | if params['release_master']: | ||
103 | # No level B on the release master | ||
104 | cpus -= 1 | ||
105 | |||
98 | # Partition using worst-fit for most even distribution | 106 | # Partition using worst-fit for most even distribution |
99 | utils = [0]*int(params['cpus']) | 107 | utils = [0]*cpus |
100 | tasks = [0]*int(params['cpus']) | 108 | tasks = [0]*cpus |
101 | for t in ts: | 109 | for t in ts: |
102 | t.cpu = utils.index(min(utils)) | 110 | t.cpu = utils.index(min(utils)) |
103 | t.id = tasks[t.cpu] | 111 | t.lvla_id = tasks[t.cpu] |
104 | 112 | ||
105 | utils[t.cpu] += t.utilization() | 113 | utils[t.cpu] += t.utilization() |
106 | tasks[t.cpu] += 1 | 114 | tasks[t.cpu] += 1 |
107 | 115 | ||
116 | # Increment by one so release master has no tasks | ||
117 | t.cpu += 1 | ||
118 | |||
108 | def __adjust(self, params, level): | 119 | def __adjust(self, params, level): |
109 | # Adjust for levels which aren't used | 120 | # Adjust for levels which aren't used |
110 | ldiff = LEVELS - params['levels'] | 121 | num = params['levels'] |
111 | shares = self.shares[ldiff:] | 122 | shares = list(self.shares) |
112 | level -= ldiff | 123 | if num < 4: |
124 | shares.pop() | ||
125 | if num < 3: | ||
126 | shares.pop(0) | ||
127 | level -= 1 | ||
113 | 128 | ||
114 | return shares, level | 129 | return shares, level |
115 | 130 | ||
116 | def __get_max_util(self, params, level): | 131 | def __get_max_util(self, params, level): |
117 | shares, level = self.__adjust(params, level) | 132 | shares, level = self.__adjust(params, level) |
118 | return float(shares[level]) / sum(shares[:level]) * params['cpus'] | 133 | return float(shares[level]) / sum(shares[:level+1]) * params['cpus'] |
119 | 134 | ||
120 | def __get_scale(self, params, level): | 135 | def __get_scale(self, params, level): |
121 | shares, level = self.__adjust(params, level) | 136 | shares, level = self.__adjust(params, level) |
122 | return float(shares[level]) / sum(shares) | 137 | return float(sum(shares[:level+1])) / sum(shares) |
123 | 138 | ||
124 | def __create_lvla_sched(self, params): | 139 | def __create_lvla_sched(self, params): |
125 | if params['levels'] < 3: | 140 | if params['levels'] < 3: |
@@ -148,11 +163,13 @@ class McGenerator(Generator): | |||
148 | utils = self._create_dist('utilization', params['b_utils'], | 163 | utils = self._create_dist('utilization', params['b_utils'], |
149 | NAMED_UTILIZATIONS) | 164 | NAMED_UTILIZATIONS) |
150 | 165 | ||
151 | # Level-A is present, b must be harmonic with lvla hyperperiod | 166 | |
152 | if params['levels'] > 2: | 167 | if params['levels'] > 2: |
168 | # Level-A is present, b must be harmonic with lvla hyperperiod | ||
153 | plist = [params['a_hyperperiod']*2**x for x in xrange(0, 4)] | 169 | plist = [params['a_hyperperiod']*2**x for x in xrange(0, 4)] |
154 | periods = rv.uniform_choice(plist) | 170 | periods = rv.uniform_choice(plist) |
155 | else: | 171 | else: |
172 | # Level b can have whatever periods it wants | ||
156 | periods = self._create_dist('period', params['b_periods'], | 173 | periods = self._create_dist('period', params['b_periods'], |
157 | NAMED_PERIODS) | 174 | NAMED_PERIODS) |
158 | max_util = self.__get_max_util(params, 1) | 175 | max_util = self.__get_max_util(params, 1) |
@@ -171,6 +188,9 @@ class McGenerator(Generator): | |||
171 | 188 | ||
172 | return self._create_taskset(params, periods, utils, max_util) | 189 | return self._create_taskset(params, periods, utils, max_util) |
173 | 190 | ||
191 | def _customize(self, task_system, params): | ||
192 | pass | ||
193 | |||
174 | def _create_exp(self, params): | 194 | def _create_exp(self, params): |
175 | # Ugly way of doing it | 195 | # Ugly way of doing it |
176 | self.shares = self._create_dist('shares', params['shares'], | 196 | self.shares = self._create_dist('shares', params['shares'], |
@@ -193,13 +213,165 @@ class McGenerator(Generator): | |||
193 | 213 | ||
194 | scales = [] | 214 | scales = [] |
195 | for index, level in enumerate('abc'): | 215 | for index, level in enumerate('abc'): |
196 | scales += [('scale%s' % level, self.__get_scale(params, index))] | 216 | if tasks['lvl%s'%level]: |
217 | scales += [('scale%s' % level, self.__get_scale(params, index))] | ||
197 | 218 | ||
198 | schedule_variables = params.items() + tasks.items() + scales | 219 | schedule_variables = params.items() + tasks.items() + scales |
199 | param_variables = params.items() + [('config-options',conf_options)] | 220 | param_variables = params.items() + [('config-options',conf_options)] |
200 | 221 | ||
222 | self._customize(tasks, params) | ||
223 | |||
201 | self._write_schedule(dict(schedule_variables)) | 224 | self._write_schedule(dict(schedule_variables)) |
202 | self._write_params(dict(param_variables)) | 225 | self._write_params(dict(param_variables)) |
203 | 226 | ||
204 | # Ugly | 227 | # Ugly |
205 | del(self.shares) | 228 | del(self.shares) |
229 | |||
230 | |||
231 | # Types are base, locking, preemptive | ||
232 | # This sets up the scheduler to create each | ||
233 | TP_TYPE = """#if $type != 'unmanaged' | ||
234 | /proc/sys/litmus/color/lock_cache{1} | ||
235 | #else | ||
236 | /proc/sys/litmus/color/lock_cache{0} | ||
237 | #end if | ||
238 | #if $type == 'scheduling' | ||
239 | /proc/sys/litmus/color/preempt_cache{1} | ||
240 | #else | ||
241 | /proc/sys/litmus/color/preempt_cache{0} | ||
242 | #end if""" | ||
243 | |||
244 | # Use special spin for color tasks | ||
245 | TP_COLOR_BASE = """colorspin -y $t.id -x $t.colorcsv """ | ||
246 | |||
247 | TP_COLOR_B = TP_BASE.format("b", TP_COLOR_BASE + "-p $t.cpu ") | ||
248 | TP_COLOR_C = TP_BASE.format("c", TP_COLOR_BASE) | ||
249 | |||
250 | # Not even sure job splitting is still possible | ||
251 | TP_CHUNK = """#if $chunk_size > 0 | ||
252 | /proc/sys/litmus/color/chunk_size{$chunk_size} | ||
253 | #end if""" | ||
254 | |||
255 | COLOR_TYPES = ['scheduling', 'locking', 'unmanaged'] | ||
256 | |||
257 | class ColorMcGenerator(McGenerator): | ||
258 | def __init__(self, params = {}): | ||
259 | super(ColorMcGenerator, self).__init__("COLOR-MC", | ||
260 | templates=[TP_TYPE, TP_CHUNK, TP_COLOR_B, TP_COLOR_C], | ||
261 | options=self.__make_options(), | ||
262 | params=self.__extend_params(params)) | ||
263 | |||
264 | def __extend_params(self, params): | ||
265 | '''Add in fixed mixed-criticality parameters.''' | ||
266 | params['levels'] = 2 | ||
267 | params['be'] = False | ||
268 | params['redirect'] = True | ||
269 | params['release_master'] = True | ||
270 | params['timer_merging'] = False | ||
271 | params['slack_stealing'] = False | ||
272 | |||
273 | # Set these just so they aren't displayed to the user | ||
274 | params['d_nice'] = False | ||
275 | params['d_fifo'] = False | ||
276 | params['a_hyperperiod'] = 0 | ||
277 | params['a_utils'] = 'bimo-light' | ||
278 | |||
279 | return params | ||
280 | |||
281 | def __make_system_info(self): | ||
282 | info = get_cache_info() | ||
283 | |||
284 | if not info: | ||
285 | # Pick something semi-reasonable. these will work (wastefully) on | ||
286 | # many machines. The plugin will pidgeon hole pages into these | ||
287 | # specific areas, so even if the cache which runs this code has | ||
288 | # more ways and/or colors than these, it will run as though these | ||
289 | # are its parameters. This is sufficient for most testing | ||
290 | ways = 8 | ||
291 | colors = 8 | ||
292 | page = 4096 | ||
293 | line = 64 | ||
294 | |||
295 | cache = ways * colors * page | ||
296 | sets = cache / (line * ways) | ||
297 | |||
298 | info = CacheInfo(cache, line=line, page=page, | ||
299 | ways=ways, sets=sets, colors=colors) | ||
300 | |||
301 | self.system = info | ||
302 | |||
303 | def __make_options(self): | ||
304 | self.__make_system_info() | ||
305 | |||
306 | return [GenOption('type', COLOR_TYPES, COLOR_TYPES, | ||
307 | 'Cache management type.'), | ||
308 | GenOption('chunk_size', float, [0], 'Chunk size.'), | ||
309 | GenOption('ways', int, [self.system.ways], 'Ways (associativity).'), | ||
310 | GenOption('colors', int, [self.system.colors], | ||
311 | 'System colors (cache size / ways).'), | ||
312 | GenOption('page_size', int, [self.system.page], | ||
313 | 'System page size.'), | ||
314 | GenOption('wss', [float, int], [.5], | ||
315 | 'Task working set sizes. Can be expressed as a fraction ' + | ||
316 | 'of the cache.'), | ||
317 | GenOption('align_unmanaged', [True, False], [True], | ||
318 | 'Place all working sets of unmanaged task systems in '+ | ||
319 | 'the same location, for maximum interference.')] | ||
320 | |||
321 | |||
322 | def __get_wss_pages(self, params): | ||
323 | '''Return the number of pages in a single task's working set.''' | ||
324 | cache_pages = params['ways'] * params['colors'] | ||
325 | |||
326 | wss = params['wss'] | ||
327 | if type(wss) == float and wss <= 1.0: | ||
328 | # Can express wss as fraction of total cache | ||
329 | pages = int(wss*cache_pages) | ||
330 | else: | ||
331 | if wss < params['page_size']: | ||
332 | raise Exception(('Cannot have working set (%d) smaller than ' | ||
333 | 'a page (%d).') % (wss, params['page_size'])) | ||
334 | |||
335 | pages = wss / params['page_size'] | ||
336 | |||
337 | if pages > cache_pages: | ||
338 | raise Exception('WSS (%d) larger than the cache!' % (wss)) | ||
339 | |||
340 | return pages | ||
341 | |||
342 | |||
343 | def __make_csv(self, task): | ||
344 | '''Write task.colors into a csv file, stored as task.colorcsv.''' | ||
345 | fname = 'colors%d.csv' % task.id | ||
346 | task.colorcsv = fname | ||
347 | |||
348 | with open(self._out_dir() + "/" + fname, 'w') as f: | ||
349 | for color, replicas in task.colors.iteritems(): | ||
350 | f.write("%d, %d\n" % (color, replicas)) | ||
351 | |||
352 | def _customize(self, task_system, params): | ||
353 | '''Add coloring properties to the mixed-criticality task system.''' | ||
354 | # Every task needs a unique id for coloring and wss walk order | ||
355 | all_tasks = [] | ||
356 | for level, tasks in task_system.iteritems(): | ||
357 | all_tasks += tasks | ||
358 | for i, task in enumerate(all_tasks): | ||
359 | task.id = i | ||
360 | |||
361 | c = params['colors'] | ||
362 | w = params['ways'] | ||
363 | |||
364 | if params['type'] == 'unmanaged': | ||
365 | hrt_colorer = EvilColorScheme(c, w) | ||
366 | srt_colorer = hrt_colorer | ||
367 | else: | ||
368 | srt_colorer = RandomColorScheme(c, w) | ||
369 | hrt_colorer = BlockColorScheme(c, w, way_first=True) | ||
370 | |||
371 | pages_needed = self.__get_wss_pages(params) | ||
372 | |||
373 | hrt_colorer.color(task_system['lvlb'], pages_needed) | ||
374 | srt_colorer.color(task_system['lvlc'], pages_needed) | ||
375 | |||
376 | for t in all_tasks: | ||
377 | self.__make_csv(t) | ||