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) | ||
