-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathState.rb
154 lines (129 loc) · 3.27 KB
/
State.rb
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
Dir['*rb'].each { |f| require_relative f }
class State
def initialize o={}
@o = {
max: {
:l2l3req_tl => 25,
:l2l3req_o => ( o[:l2l3req_tl] || 25) *2,
:l2l3resp_tl => 25,
:l2l3resp_o => ( o[:l2l3resp_tl] || 25 ) *2,
:l3memreq_tl => o[:mem_tl] || 120,
:l3memreq_o => ( o[:l3memreq_tl] || 120 ) *2,
:l3memresp_tl => o[:mem_tl] || 120,
:l3memresp_o => ( o[:l3memresp_tl] || 120) *2,
:mem_tl => 120,
:mem_o => ( o[:mem_tl] || 120 ) *2
},
min: {
:l2l3req_tl => 1,
:l2l3req_o => 0,
:l2l3resp_tl => 1,
:l2l3resp_o => 0,
:l3memreq_tl => 1,
:l3memreq_o => 0,
:l3memresp_tl => 1,
:l3memresp_o => 0,
:mem_tl => 66,
:mem_o => 0
},
deltas: lambda{ |p| -3.upto(3).to_a - [0] },
}.merge o
@max = @o[:max]
@min = @o[:min]
@deltas = @o[:deltas]
@params = @o[:params] || [
:l2l3req_tl,
:l2l3req_o,
:l2l3resp_tl,
:l2l3resp_o,
:l3memreq_tl,
:l3memreq_o,
:l3memresp_tl,
:l3memresp_o,
:mem_tl,
:mem_o,
]
# @params.each do |p|
# eval "instance_variable_set(\"#{p}\",o[:#{p}]) unless o[:#{p}].nil?"
# end
end
def legal o
@params.each do |p|
return false if o[p] > @max[p]
return false if o[p] < @min[p]
return false if badprime o[p]
end
return true
end
def badprime n
return false if n < 20
not [*2..n-1].inject(false){ |notprime,i| notprime |= (n%i == 0) }
end
# Generates a neighbor of this state by randomly selecting a parameter and
# then changing it by a randomly selected delta
def neighbor &block
factory = block || lambda { |o| State.new o }
new_params = @o.merge(
(p = @params.sample) => @o[p] + @deltas.call(p).sample
)
legal(new_params)?
factory.call(new_params) :
neighbor
end
# Lower energy -> more likely to accept.
# Suitable options:
# EV(l3 hit latency)
# EV(l3 miss latency)
# l3 mss latency constrained to best l3 hit latency
# weighted balance of l3 hit/miss latency
def energy
(lat = l3_miss_latencies @o).inject{ |a,l| a+=l }/lat.size.to_f
end
#Randomly generate a new legal
def shuffle &block
factory = block || lambda { |o| State.new o }
factory.call @o.merge(
@params.inject({}) do |params,p|
params[p] = @min[p].upto(@max[p]).to_a.sample
params
end
)
end
def to_s
@params.inject({}){ |h,p| h[p] = @o[p]; h }.to_s
end
end
class MaximizingState < State
def energy
super * -1
end
def shuffle
super{ |o| MaximizingState.new o }
end
def neighbor
super{ |o| MaximizingState.new o}
end
end
class BalancedHitState < State
def energy
super * 0.1 +
0.9*(lat = l3_miss_latencies @o).inject{ |a,l| a+=l }/lat.size.to_f
end
def shuffle
super{ |o| BalancedHitState.new o }
end
def neighbor
super{ |o| BalancedHitState.new o}
end
end
class HitState < State
def initialize o={}
params = o[:params] || [
:l2l3req_tl,
:l2l3req_o,
:l2l3resp_tl,
:l2l3resp_o,
]
super o.merge( params: params )
end
end