aboutsummaryrefslogtreecommitdiffstats
path: root/gen/color.py
blob: 46ec8dcac89147a0a41a792fb2380848862d2a98 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import os
import re

from collections import namedtuple,defaultdict
from math import ceil
from random import randint

class ColorScheme(object):
    def __init__(self, colors, ways):
        self.colors = colors
        self.ways = ways

    def color(self, tasks, wss):
        '''Assign a color->replicas dict to each task in tasks.'''
        raise NotImplementedError

class BlockColorScheme(ColorScheme):
    def __init__(self, colors, ways, way_first):
        super(BlockColorScheme, self).__init__(colors, ways)
        self.way_first = way_first

    def color(self, tasks, pages_needed):
        '''Pages are assigned in blocks, either maximizing the number of ways
        or maximizing the number of colors used.'''
        cpus = defaultdict(list)
        for t in tasks:
            cpus[t.cpu].append(t)

        if self.way_first:
            # Way first means maximize ways
            pages_per_color = min(self.ways, pages_needed)
            colors_per_task = int(ceil(float(pages_needed)/pages_per_color))
        else:
            # Color first means maximize colors
            colors_per_task = min(self.colors, pages_needed)
            pages_per_color = int(ceil(float(pages_needed)/colors_per_task))

        curr_color = 0
        for cpu, tasks in cpus.iteritems():
            # All tasks on a CPU have the same coloring scheme
            cpu_colors = defaultdict(int)
            for _ in xrange(colors_per_task):
                cpu_colors[curr_color] = pages_per_color
                curr_color = (curr_color + 1) % self.colors

            if sum(cpu_colors.values()) < pages_needed:
                raise Exception("Failed to block color cpu, %s" % cpu_colors)

            for t in tasks:
                t.colors = cpu_colors

class RandomColorScheme(ColorScheme):
    def color(self, tasks, pages_needed):
        '''Pages are placed randomly in the cache'''
        if pages_needed >= self.ways * self.colors:
            raise Exception("Too many pages: %d > %d * %d" %
                            (pages_needed, self.ways, self.colors))

        for t in tasks:
            t.colors = defaultdict(int)

            for _ in xrange(pages_needed):
                # Find the next color with available ways
                while True:
                    next_color = randint(0, self.colors - 1)
                    if t.colors[next_color] != self.ways:
                        break

                t.colors[next_color] += 1;

class EvilColorScheme(ColorScheme):
    def color(self, tasks, pages_needed):
        '''All tasks' working sets are placed at the front of the cache'''
        colors = defaultdict(int)
        color  = 0

        while pages_needed > 0:
            colors[color] = min(self.ways, pages_needed)
            pages_needed -= colors[color]

            color += 1

        for t in tasks:
            t.colors = colors

INFO_FIELDS = ['cache', 'line', 'page', 'ways', 'sets', 'colors']
INFO_PROC   = '/proc/sys/litmus/color/cache_info'

# Build parsing regex
FIELD_REGEX = r"(?:.*?{0}.*?(?P<{0}>\d+).*?)"
INFO_REGEX  = "|".join([FIELD_REGEX.format(field) for field in INFO_FIELDS])
INFO_REGEX  = r"(?:{})*".format(INFO_REGEX)

# To fill up this
CacheInfo = namedtuple('CacheInfo', INFO_FIELDS)

def get_cache_info():
    if os.path.exists(INFO_PROC):
        with open(INFO_PROC, 'r') as f:
            data   = f.read()
            values = re.search(INFO_REGEX, data, re.M|re.I|re.S).groupdict()
            return CacheInfo(**values)
    else:
        return None