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
|