aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjoern Brandenburg <bbb@mpi-sws.org>2013-01-29 07:47:01 -0500
committerBjoern Brandenburg <bbb@mpi-sws.org>2013-07-12 08:19:22 -0400
commit064f6a2915d8bcecea31f07b2a57de80203c6f37 (patch)
tree92ce02d07ba1779e434942616113f967c42d79ed
parente17645921697351bd968f034a85299c02332ad16 (diff)
Implement LP-based OMIP blocking analysis
-rw-r--r--native/Makefile2
-rw-r--r--native/include/lp_analysis.h5
-rw-r--r--native/include/lp_common.h9
-rw-r--r--native/include/sharedres_types.h7
-rw-r--r--native/src/blocking/linprog/lp_common.cpp34
-rw-r--r--native/src/blocking/linprog/lp_omip.cpp268
-rw-r--r--schedcat/locking/bounds.py6
-rw-r--r--tests/locking.py4
8 files changed, 334 insertions, 1 deletions
diff --git a/native/Makefile b/native/Makefile
index 6f1abe2..54c75d8 100644
--- a/native/Makefile
+++ b/native/Makefile
@@ -118,7 +118,7 @@ ALL = testmain _sched.so _locking.so _sim.so
118 118
119# Compile LP-based code only if we have a solver. 119# Compile LP-based code only if we have a solver.
120ifneq ($(CPLEX_PATH)$(GLPK_PATH),) 120ifneq ($(CPLEX_PATH)$(GLPK_PATH),)
121LP_OBJ = lp_common.o io.o lp_dflp.o lp_dpcp.o lp_mpcp.o lp_fmlp.o 121LP_OBJ = lp_common.o io.o lp_dflp.o lp_dpcp.o lp_mpcp.o lp_fmlp.o lp_omip.o
122 122
123ifneq ($(CPLEX_PATH),) 123ifneq ($(CPLEX_PATH),)
124LP_OBJ += cplex.o cpx.o 124LP_OBJ += cplex.o cpx.o
diff --git a/native/include/lp_analysis.h b/native/include/lp_analysis.h
index 998eeb5..862c09e 100644
--- a/native/include/lp_analysis.h
+++ b/native/include/lp_analysis.h
@@ -13,4 +13,9 @@ BlockingBounds* lp_mpcp_bounds(const ResourceSharingInfo& info);
13 13
14BlockingBounds* lp_part_fmlp_bounds(const ResourceSharingInfo& info); 14BlockingBounds* lp_part_fmlp_bounds(const ResourceSharingInfo& info);
15 15
16BlockingBounds* lp_omip_bounds(
17 const ResourceSharingInfo& info,
18 unsigned int num_procs,
19 unsigned int cluster_size);
20
16#endif /* LP_ANALYSYS_H_ */ 21#endif /* LP_ANALYSYS_H_ */
diff --git a/native/include/lp_common.h b/native/include/lp_common.h
index b459664..8f612ea 100644
--- a/native/include/lp_common.h
+++ b/native/include/lp_common.h
@@ -19,6 +19,9 @@ enum blocking_type
19 BLOCKING_PREEMPT 19 BLOCKING_PREEMPT
20}; 20};
21 21
22// s-oblivious analysis reuses BLOCKING_DIRECT as a catch-all blocking type.
23#define BLOCKING_SOB BLOCKING_DIRECT
24
22class VarMapper { 25class VarMapper {
23private: 26private:
24 hashmap<uint64_t, unsigned int> map; 27 hashmap<uint64_t, unsigned int> map;
@@ -97,6 +100,12 @@ void set_blocking_objective_part_shm(
97 LinearExpression *local_obj = 0, 100 LinearExpression *local_obj = 0,
98 LinearExpression *remote_obj = 0); 101 LinearExpression *remote_obj = 0);
99 102
103void set_blocking_objective_sob(
104 VarMapper& vars,
105 const ResourceSharingInfo& info,
106 const TaskInfo& ti,
107 LinearProgram& lp);
108
100void add_mutex_constraints(VarMapper& vars, 109void add_mutex_constraints(VarMapper& vars,
101 const ResourceSharingInfo& info, 110 const ResourceSharingInfo& info,
102 const TaskInfo& ti, LinearProgram& lp); 111 const TaskInfo& ti, LinearProgram& lp);
diff --git a/native/include/sharedres_types.h b/native/include/sharedres_types.h
index 898434c..fbe8f72 100644
--- a/native/include/sharedres_types.h
+++ b/native/include/sharedres_types.h
@@ -119,6 +119,13 @@ public:
119 return len; 119 return len;
120 } 120 }
121 121
122 unsigned int get_num_requests(unsigned int res_id) const
123 {
124 foreach(requests, it)
125 if (it->get_resource_id() == res_id)
126 return it->get_num_requests();
127 return 0;
128 }
122}; 129};
123 130
124typedef std::vector<TaskInfo> TaskInfos; 131typedef std::vector<TaskInfo> TaskInfos;
diff --git a/native/src/blocking/linprog/lp_common.cpp b/native/src/blocking/linprog/lp_common.cpp
index 1715d3b..2df1284 100644
--- a/native/src/blocking/linprog/lp_common.cpp
+++ b/native/src/blocking/linprog/lp_common.cpp
@@ -119,6 +119,40 @@ void set_blocking_objective_part_shm(
119 } 119 }
120} 120}
121 121
122// This version is for suspension-oblivious shared-memory protocols,
123// where the analysis does not differentiate among the different kinds
124// of blocking (since they are all just added to the execution time anyway).
125void set_blocking_objective_sob(
126 VarMapper& vars,
127 const ResourceSharingInfo& info,
128 const TaskInfo& ti,
129 LinearProgram& lp)
130{
131 LinearExpression *obj;
132
133 obj = lp.get_objective();
134
135 foreach_task_except(info.get_tasks(), ti, tx)
136 {
137 unsigned int t = tx->get_id();
138
139 foreach(tx->get_requests(), request)
140 {
141 unsigned int q = request->get_resource_id();
142 double length = request->get_request_length();;
143
144 foreach_request_instance(*request, ti, v)
145 {
146 unsigned int var_id;
147
148 var_id = vars.lookup(t, q, v, BLOCKING_SOB);
149 obj->add_term(length, var_id);
150 }
151 }
152 }
153}
154
155
122// Constraint 1 in [Brandenburg 2013] 156// Constraint 1 in [Brandenburg 2013]
123void add_mutex_constraints( 157void add_mutex_constraints(
124 VarMapper& vars, 158 VarMapper& vars,
diff --git a/native/src/blocking/linprog/lp_omip.cpp b/native/src/blocking/linprog/lp_omip.cpp
new file mode 100644
index 0000000..0e5d864
--- /dev/null
+++ b/native/src/blocking/linprog/lp_omip.cpp
@@ -0,0 +1,268 @@
1#include <iostream>
2#include <set>
3#include <algorithm>
4#include <cmath>
5
6#include "lp_common.h"
7#include "blocking.h"
8#include "stl-hashmap.h"
9
10#include "cpu_time.h"
11
12// Per-cluster, per-resource access counts.
13typedef hashmap<unsigned int, unsigned int> AccessCounts;
14typedef hashmap<unsigned int, AccessCounts> PerClusterACounts;
15
16static AccessCounts count_accesses(
17 const ResourceSharingInfo& info,
18 unsigned int cluster)
19{
20 AccessCounts acount;
21
22 foreach(info.get_tasks(), tx) {
23 if (tx->get_cluster() == cluster) {
24 foreach(tx->get_requests(), request)
25 {
26 unsigned int q = request->get_resource_id();
27 // count that q is being accessed by tx
28 acount[q] += 1;
29 }
30 }
31 }
32 return acount;
33}
34
35static void add_total_constraints(
36 VarMapper& vars,
37 const ResourceSharingInfo& info,
38 const TaskInfo& ti,
39 LinearProgram& lp,
40 unsigned int num_procs)
41{
42 // one constraint for each resource
43 hashmap<unsigned int, LinearExpression *> constraints;
44 LinearExpression *exp;
45
46 foreach_task_except(info.get_tasks(), ti, tx)
47 {
48 unsigned int t = tx->get_id();
49
50 //for all requests accessed by tx
51 foreach(tx->get_requests(), request)
52 {
53 unsigned int q = request->get_resource_id();
54
55 if (constraints.find(q) == constraints.end())
56 constraints[q] = new LinearExpression();
57 exp = constraints[q];
58 foreach_request_instance(*request, ti, v)
59 {
60 unsigned int var_id;
61 var_id = vars.lookup(t, q, v, BLOCKING_SOB);
62 exp->add_var(var_id);
63 }
64 }
65 }
66
67 // add each per-resource constraint
68 foreach(constraints, it) {
69 unsigned int bound = ti.get_num_requests(it->first);
70 bound *= (2 * num_procs - 1);
71 lp.add_inequality(it->second, bound);
72 }
73}
74
75
76static void add_remote_cluster_constraints(
77 VarMapper& vars,
78 const ResourceSharingInfo& info,
79 const TaskInfo& ti,
80 LinearProgram& lp,
81 AccessCounts& acount,
82 unsigned int num_procs,
83 unsigned int cluster_size)
84{
85 // one constraint for each cluster and each resource
86 hashmap<unsigned int, hashmap<unsigned int, LinearExpression *> > cluster_c;
87 LinearExpression *exp;
88
89 foreach_remote_task(info.get_tasks(), ti, tx)
90 {
91 unsigned int t = tx->get_id();
92 unsigned int c = tx->get_cluster();
93
94 hashmap<unsigned int, LinearExpression *> &constraints = cluster_c[c];
95
96 //for all requests accessed by tx
97 foreach(tx->get_requests(), request)
98 {
99 unsigned int q = request->get_resource_id();
100
101 if (constraints.find(q) == constraints.end())
102 constraints[q] = new LinearExpression();
103 exp = constraints[q];
104
105 foreach_request_instance(*request, ti, v)
106 {
107 unsigned int var_id;
108 var_id = vars.lookup(t, q, v, BLOCKING_SOB);
109 exp->add_var(var_id);
110 }
111 }
112 }
113
114 // add each per-resource constraint
115 foreach(cluster_c, ct) {
116 assert(ct->first != ti.get_cluster());
117 foreach(ct->second, it) {
118 unsigned int bound = ti.get_num_requests(it->first);
119 unsigned int q = it->first;
120 if (acount[q] <= 2 * cluster_size) {
121 // FQ-only case
122 bound *= acount[q];
123 } else {
124 // PQ case
125 bound *= (cluster_size + num_procs);
126 }
127 lp.add_inequality(it->second, bound);
128 }
129 }
130}
131
132static void add_local_cluster_constraints(
133 VarMapper& vars,
134 const ResourceSharingInfo& info,
135 const TaskInfo& ti,
136 LinearProgram& lp,
137 AccessCounts& acount,
138 unsigned int cluster_size)
139{
140 foreach_local_task_except(info.get_tasks(), ti, tx)
141 {
142 unsigned int t = tx->get_id();
143 //for all requests accessed by tx
144 foreach(tx->get_requests(), request)
145 {
146 unsigned int q = request->get_resource_id();
147 LinearExpression *exp = new LinearExpression();
148
149 foreach_request_instance(*request, ti, v)
150 {
151 unsigned int var_id;
152 var_id = vars.lookup(t, q, v, BLOCKING_SOB);
153 exp->add_var(var_id);
154 }
155 unsigned int bound = ti.get_num_requests(q);
156 if (acount[q] > 2 * cluster_size)
157 bound *= 2; // PQ case
158 lp.add_inequality(exp, bound);
159 }
160 }
161}
162
163
164static void add_omip_constraints(
165 VarMapper& vars,
166 const ResourceSharingInfo& info,
167 const TaskInfo& ti,
168 LinearProgram& lp,
169 AccessCounts& acounts,
170 unsigned int num_procs,
171 unsigned int cluster_size)
172{
173 add_total_constraints(vars, info, ti, lp, num_procs);
174 add_remote_cluster_constraints(vars, info, ti, lp, acounts, num_procs, cluster_size);
175 add_local_cluster_constraints(vars, info, ti, lp, acounts, num_procs);
176}
177
178static void apply_omip_bounds_for_task(
179 unsigned int i,
180 BlockingBounds& bounds,
181 const ResourceSharingInfo& info,
182 PerClusterACounts &pcacounts,
183 unsigned int num_procs,
184 unsigned int cluster_size)
185{
186 LinearProgram lp;
187 VarMapper vars;
188 const TaskInfo& ti = info.get_tasks()[i];
189 unsigned int cluster = ti.get_cluster();
190
191 if (pcacounts.find(cluster) == pcacounts.end())
192 pcacounts[cluster] = count_accesses(info, cluster);
193
194#if DEBUG_LP_OVERHEADS >= 2
195 static DEFINE_CPU_CLOCK(model_gen_cost);
196 static DEFINE_CPU_CLOCK(solver_cost);
197
198 std::cout << "---- " << __FUNCTION__ << " ----" << std::endl;
199
200 model_gen_cost.start();
201#endif
202
203 set_blocking_objective_sob(vars, info, ti, lp);
204 vars.seal();
205
206 add_omip_constraints(vars, info, ti, lp,
207 pcacounts[cluster], num_procs, cluster_size);
208
209#if DEBUG_LP_OVERHEADS >= 2
210 model_gen_cost.stop();
211 std::cout << model_gen_cost << std::endl;
212 solver_cost.start();
213#endif
214
215 Solution *sol = linprog_solve(lp, vars.get_num_vars());
216
217#if DEBUG_LP_OVERHEADS >= 2
218 solver_cost.stop();
219 std::cout << solver_cost << std::endl;
220#endif
221 assert(sol != NULL);
222
223 Interference total;
224
225 total.total_length = lrint(sol->evaluate(*lp.get_objective()));
226 bounds[i] = total;
227
228 delete sol;
229}
230
231
232static BlockingBounds* _lp_omip_bounds(
233 const ResourceSharingInfo& info,
234 unsigned int num_procs,
235 unsigned int cluster_size)
236{
237 PerClusterACounts pcacounts;
238 BlockingBounds* results = new BlockingBounds(info);
239
240 for (unsigned int i = 0; i < info.get_tasks().size(); i++)
241 apply_omip_bounds_for_task(i, *results, info, pcacounts, num_procs, cluster_size);
242
243 return results;
244}
245
246BlockingBounds* lp_omip_bounds(
247 const ResourceSharingInfo& info,
248 unsigned int num_procs,
249 unsigned int cluster_size)
250{
251 assert(num_procs >= cluster_size);
252 assert(num_procs % cluster_size == 0);
253
254#if DEBUG_LP_OVERHEADS >= 1
255 static DEFINE_CPU_CLOCK(cpu_costs);
256
257 cpu_costs.start();
258#endif
259
260 BlockingBounds *results = _lp_omip_bounds(info, num_procs, cluster_size);
261
262#if DEBUG_LP_OVERHEADS >= 1
263 cpu_costs.stop();
264 std::cout << cpu_costs << std::endl;
265#endif
266
267 return results;
268}
diff --git a/schedcat/locking/bounds.py b/schedcat/locking/bounds.py
index 3f31f89..f307b80 100644
--- a/schedcat/locking/bounds.py
+++ b/schedcat/locking/bounds.py
@@ -267,3 +267,9 @@ def apply_lp_part_fmlp_bounds(all_tasks):
267 t.locally_blocked = res.get_local_blocking(i) 267 t.locally_blocked = res.get_local_blocking(i)
268 268
269 return res 269 return res
270
271def apply_omip_bounds(all_tasks, num_cpus, procs_per_cluster):
272 model = get_cpp_model(all_tasks)
273 res = lp_cpp.lp_omip_bounds(model, num_cpus, procs_per_cluster)
274 apply_suspension_oblivious(all_tasks, res)
275 return res
diff --git a/tests/locking.py b/tests/locking.py
index 94dda3b..2a9766f 100644
--- a/tests/locking.py
+++ b/tests/locking.py
@@ -113,6 +113,10 @@ class ApplyBounds(unittest.TestCase):
113 lb.apply_global_omlp_bounds(self.ts, 2) 113 lb.apply_global_omlp_bounds(self.ts, 2)
114 self.sob_non_zero_blocking() 114 self.sob_non_zero_blocking()
115 115
116 def test_omip(self):
117 lb.apply_omip_bounds(self.ts, 2, 1)
118 self.sob_non_zero_blocking()
119
116 def test_clustered_omlp(self): 120 def test_clustered_omlp(self):
117 lb.apply_clustered_omlp_bounds(self.ts, 2) 121 lb.apply_clustered_omlp_bounds(self.ts, 2)
118 self.sob_non_zero_blocking() 122 self.sob_non_zero_blocking()