diff options
author | Bjoern Brandenburg <bbb@mpi-sws.org> | 2012-08-08 09:53:50 -0400 |
---|---|---|
committer | Bjoern Brandenburg <bbb@mpi-sws.org> | 2013-02-12 06:55:15 -0500 |
commit | 52452d0589ed8654288a575c0083816cef43a2ba (patch) | |
tree | 56cbdea3cc26bfb20ada5f1f41cc498abebd5f9e | |
parent | 615e752dd11fb8c83cb60aa87819010169a77abd (diff) |
Make C++ and Python LP-based blocking bounds available in bounds.py
Use the faster C++ version if available, unless the caller specifically requested
the Python implementation.
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | schedcat/locking/bounds.py | 63 | ||||
-rw-r--r-- | tests/locking.py | 84 |
4 files changed, 147 insertions, 4 deletions
@@ -23,3 +23,5 @@ schedcat/sim/_sim.so | |||
23 | schedcat/sim/native.py | 23 | schedcat/sim/native.py |
24 | tmp/ | 24 | tmp/ |
25 | TAGS | 25 | TAGS |
26 | schedcat/locking/linprog/_lp_analysis.so | ||
27 | schedcat/locking/linprog/native.py | ||
@@ -14,11 +14,13 @@ cpp: | |||
14 | links: clean-links cpp | 14 | links: clean-links cpp |
15 | cd schedcat/sched; ln -s ../../native/_sched.so; ln -s ../../native/sched.py native.py | 15 | cd schedcat/sched; ln -s ../../native/_sched.so; ln -s ../../native/sched.py native.py |
16 | cd schedcat/locking; ln -s ../../native/_locking.so; ln -s ../../native/locking.py native.py | 16 | cd schedcat/locking; ln -s ../../native/_locking.so; ln -s ../../native/locking.py native.py |
17 | cd schedcat/locking/linprog; ln -s ../../../native/_lp_analysis.so; ln -s ../../../native/lp_analysis.py native.py | ||
17 | cd schedcat/sim; ln -s ../../native/_sim.so; ln -s ../../native/sim.py native.py | 18 | cd schedcat/sim; ln -s ../../native/_sim.so; ln -s ../../native/sim.py native.py |
18 | 19 | ||
19 | clean-links: | 20 | clean-links: |
20 | cd schedcat/sched; rm -f _sched.so native.py | 21 | cd schedcat/sched; rm -f _sched.so native.py |
21 | cd schedcat/locking; rm -f _locking.so native.py | 22 | cd schedcat/locking; rm -f _locking.so native.py |
23 | cd schedcat/locking/linprog; rm -f _lp_analysis.so native.py | ||
22 | cd schedcat/sim; rm -f _sim.so native.py; | 24 | cd schedcat/sim; rm -f _sim.so native.py; |
23 | 25 | ||
24 | clean: clean-links | 26 | clean: clean-links |
diff --git a/schedcat/locking/bounds.py b/schedcat/locking/bounds.py index 8e8f708..0b47fb4 100644 --- a/schedcat/locking/bounds.py +++ b/schedcat/locking/bounds.py | |||
@@ -66,20 +66,26 @@ def apply_mpcp_bounds(all_tasks, use_virtual_spin=False): | |||
66 | def get_round_robin_resource_mapping(num_resources, num_cpus, | 66 | def get_round_robin_resource_mapping(num_resources, num_cpus, |
67 | dedicated_irq=cpp.NO_CPU): | 67 | dedicated_irq=cpp.NO_CPU): |
68 | "Default resource assignment: just assign resources to CPUs in index order." | 68 | "Default resource assignment: just assign resources to CPUs in index order." |
69 | loc = cpp.ResourceLocality() | 69 | loc = {} |
70 | for res_id in xrange(num_resources): | 70 | for res_id in xrange(num_resources): |
71 | cpu = res_id % num_cpus | 71 | cpu = res_id % num_cpus |
72 | if cpu == dedicated_irq: | 72 | if cpu == dedicated_irq: |
73 | cpu = (cpu + 1) % num_cpus | 73 | cpu = (cpu + 1) % num_cpus |
74 | loc.assign_resource(res_id, cpu) | 74 | loc[res_id] = cpu |
75 | return loc | 75 | return loc |
76 | 76 | ||
77 | # default resource assignment: round robin | 77 | def get_cpp_topology(res_mapping): |
78 | map = cpp.ResourceLocality() | ||
79 | for res_id in res_mapping: | ||
80 | map.assign_resource(res_id, res_mapping[res_id]) | ||
81 | return map | ||
82 | |||
78 | def apply_dpcp_bounds(all_tasks, resource_mapping): | 83 | def apply_dpcp_bounds(all_tasks, resource_mapping): |
79 | # The DPCP bounds are expressed in terms of task periods, | 84 | # The DPCP bounds are expressed in terms of task periods, |
80 | # not response time. | 85 | # not response time. |
81 | model = get_cpp_model(all_tasks) | 86 | model = get_cpp_model(all_tasks) |
82 | res = cpp.dpcp_bounds(model, resource_mapping) | 87 | topo = get_cpp_topology(resource_mapping) |
88 | res = cpp.dpcp_bounds(model, topo) | ||
83 | 89 | ||
84 | for i,t in enumerate(all_tasks): | 90 | for i,t in enumerate(all_tasks): |
85 | # remote blocking <=> suspension time | 91 | # remote blocking <=> suspension time |
@@ -167,3 +173,52 @@ def apply_phase_fair_rw_bounds(all_tasks, procs_per_cluster, | |||
167 | apply_suspension_oblivious(all_tasks, res) | 173 | apply_suspension_oblivious(all_tasks, res) |
168 | 174 | ||
169 | 175 | ||
176 | |||
177 | ### S-aware LP-based analysis of distributed locking protocols | ||
178 | |||
179 | try: | ||
180 | import schedcat.locking.linprog.native as lp_cpp | ||
181 | |||
182 | lp_cpp_available = True | ||
183 | except ImportError: | ||
184 | lp_cpp_available = False | ||
185 | |||
186 | import schedcat.locking.linprog.dflp as dflp | ||
187 | import schedcat.locking.linprog.dpcp as dpcp | ||
188 | |||
189 | def apply_py_lp_bounds(bounds, all_tasks, resource_mapping, *args): | ||
190 | for t in all_tasks: | ||
191 | lp = bounds.get_lp_for_task(resource_mapping, | ||
192 | all_tasks, t, *args) | ||
193 | |||
194 | lp.kill_non_positive_vars() | ||
195 | solution = lp.solve() | ||
196 | |||
197 | # total blocking | ||
198 | t.blocked = int(solution(lp.objective_function)) | ||
199 | t.suspended = int(solution(lp.remote_objective)) | ||
200 | |||
201 | def apply_lp_dflp_bounds(all_tasks, resource_mapping, | ||
202 | use_py=False): | ||
203 | if use_py or not lp_cpp_available: | ||
204 | apply_py_lp_bounds(dflp, all_tasks, resource_mapping) | ||
205 | else: | ||
206 | model = get_cpp_model(all_tasks) | ||
207 | topo = get_cpp_topology(resource_mapping) | ||
208 | res = lp_cpp.lp_dflp_bounds(model, topo) | ||
209 | for i, t in enumerate(all_tasks): | ||
210 | t.suspended = res.get_remote_blocking(i) | ||
211 | t.blocked = res.get_blocking_term(i) | ||
212 | |||
213 | def apply_lp_dpcp_bounds(all_tasks, resource_mapping, | ||
214 | use_rta = True, use_py=False): | ||
215 | if use_py or not lp_cpp_available: | ||
216 | apply_py_lp_bounds(dpcp, all_tasks, resource_mapping, use_rta) | ||
217 | else: | ||
218 | model = get_cpp_model(all_tasks) | ||
219 | topo = get_cpp_topology(resource_mapping) | ||
220 | res = lp_cpp.lp_dpcp_bounds(model, topo, use_rta) | ||
221 | for i, t in enumerate(all_tasks): | ||
222 | t.suspended = res.get_remote_blocking(i) | ||
223 | t.blocked = res.get_blocking_term(i) | ||
224 | |||
diff --git a/tests/locking.py b/tests/locking.py index b16c453..94dda3b 100644 --- a/tests/locking.py +++ b/tests/locking.py | |||
@@ -9,6 +9,8 @@ import schedcat.locking.partition as lp | |||
9 | import schedcat.model.tasks as tasks | 9 | import schedcat.model.tasks as tasks |
10 | import schedcat.model.resources as r | 10 | import schedcat.model.resources as r |
11 | 11 | ||
12 | import schedcat.util.linprog | ||
13 | |||
12 | class Locking(unittest.TestCase): | 14 | class Locking(unittest.TestCase): |
13 | def setUp(self): | 15 | def setUp(self): |
14 | self.ts = tasks.TaskSystem([ | 16 | self.ts = tasks.TaskSystem([ |
@@ -637,3 +639,85 @@ class Test_partition(unittest.TestCase): | |||
637 | self.assertIn(self.ts[1], subsets[0]) | 639 | self.assertIn(self.ts[1], subsets[0]) |
638 | self.assertIn(self.ts[2], subsets[1]) | 640 | self.assertIn(self.ts[2], subsets[1]) |
639 | self.assertIn(self.ts[3], subsets[1]) | 641 | self.assertIn(self.ts[3], subsets[1]) |
642 | |||
643 | |||
644 | class Test_linprog(unittest.TestCase): | ||
645 | def setUp(self): | ||
646 | self.t1 = tasks.SporadicTask(10, 100) | ||
647 | self.t2 = tasks.SporadicTask(25, 200) | ||
648 | self.t3 = tasks.SporadicTask(33, 33) | ||
649 | self.ts = tasks.TaskSystem([self.t1, self.t2, self.t3]) | ||
650 | |||
651 | self.ts.assign_ids() | ||
652 | lb.assign_fp_locking_prios(self.ts) | ||
653 | |||
654 | for t in self.ts: | ||
655 | t.response_time = t.period | ||
656 | t.partition = t.id % 2 | ||
657 | |||
658 | self.ts_no_req = self.ts.copy() | ||
659 | |||
660 | r.initialize_resource_model(self.ts) | ||
661 | r.initialize_resource_model(self.ts_no_req) | ||
662 | |||
663 | self.t1.resmodel[0].add_request(1) | ||
664 | self.t2.resmodel[0].add_request(2) | ||
665 | self.t3.resmodel[0].add_request(3) | ||
666 | |||
667 | # only one resource, assigned to the first processor | ||
668 | self.resource_locality = { 0: 0 } | ||
669 | |||
670 | def test_dpcp_cpp(self): | ||
671 | lb.apply_lp_dpcp_bounds(self.ts, self.resource_locality, use_py=False) | ||
672 | |||
673 | @unittest.skipIf(not schedcat.util.linprog.cplex_available, "no LP solver available") | ||
674 | def test_dpcp_py(self): | ||
675 | lb.apply_lp_dpcp_bounds(self.ts, self.resource_locality, use_py=True) | ||
676 | |||
677 | def test_dflp_cpp(self): | ||
678 | lb.apply_lp_dflp_bounds(self.ts, self.resource_locality, use_py=False) | ||
679 | |||
680 | @unittest.skipIf(not schedcat.util.linprog.cplex_available, "no LP solver available") | ||
681 | def test_dflp_py(self): | ||
682 | lb.apply_lp_dflp_bounds(self.ts, self.resource_locality, use_py=True) | ||
683 | |||
684 | |||
685 | |||
686 | def test_dpcp_cpp_no_req(self): | ||
687 | lb.apply_lp_dpcp_bounds(self.ts_no_req, {}, use_py=False) | ||
688 | self.assertEqual(self.ts_no_req[0].blocked, 0) | ||
689 | self.assertEqual(self.ts_no_req[0].suspended, 0) | ||
690 | self.assertEqual(self.ts_no_req[1].blocked, 0) | ||
691 | self.assertEqual(self.ts_no_req[1].suspended, 0) | ||
692 | self.assertEqual(self.ts_no_req[2].blocked, 0) | ||
693 | self.assertEqual(self.ts_no_req[2].suspended, 0) | ||
694 | |||
695 | @unittest.skipIf(not schedcat.util.linprog.cplex_available, "no LP solver available") | ||
696 | def test_dpcp_py_no_req(self): | ||
697 | lb.apply_lp_dpcp_bounds(self.ts_no_req, {}, use_py=True) | ||
698 | self.assertEqual(self.ts_no_req[0].blocked, 0) | ||
699 | self.assertEqual(self.ts_no_req[0].suspended, 0) | ||
700 | self.assertEqual(self.ts_no_req[1].blocked, 0) | ||
701 | self.assertEqual(self.ts_no_req[1].suspended, 0) | ||
702 | self.assertEqual(self.ts_no_req[2].blocked, 0) | ||
703 | self.assertEqual(self.ts_no_req[2].suspended, 0) | ||
704 | |||
705 | def test_dflp_cpp_no_req(self): | ||
706 | lb.apply_lp_dflp_bounds(self.ts_no_req, {}, use_py=False) | ||
707 | self.assertEqual(self.ts_no_req[0].blocked, 0) | ||
708 | self.assertEqual(self.ts_no_req[0].suspended, 0) | ||
709 | self.assertEqual(self.ts_no_req[1].blocked, 0) | ||
710 | self.assertEqual(self.ts_no_req[1].suspended, 0) | ||
711 | self.assertEqual(self.ts_no_req[2].blocked, 0) | ||
712 | self.assertEqual(self.ts_no_req[2].suspended, 0) | ||
713 | |||
714 | @unittest.skipIf(not schedcat.util.linprog.cplex_available, "no LP solver available") | ||
715 | def test_dflp_py_no_req(self): | ||
716 | lb.apply_lp_dflp_bounds(self.ts_no_req, {}, use_py=True) | ||
717 | self.assertEqual(self.ts_no_req[0].blocked, 0) | ||
718 | self.assertEqual(self.ts_no_req[0].suspended, 0) | ||
719 | self.assertEqual(self.ts_no_req[1].blocked, 0) | ||
720 | self.assertEqual(self.ts_no_req[1].suspended, 0) | ||
721 | self.assertEqual(self.ts_no_req[2].blocked, 0) | ||
722 | self.assertEqual(self.ts_no_req[2].suspended, 0) | ||
723 | |||