aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjoern Brandenburg <bbb@mpi-sws.org>2012-08-08 09:53:50 -0400
committerBjoern Brandenburg <bbb@mpi-sws.org>2013-02-12 06:55:15 -0500
commit52452d0589ed8654288a575c0083816cef43a2ba (patch)
tree56cbdea3cc26bfb20ada5f1f41cc498abebd5f9e
parent615e752dd11fb8c83cb60aa87819010169a77abd (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--.gitignore2
-rw-r--r--Makefile2
-rw-r--r--schedcat/locking/bounds.py63
-rw-r--r--tests/locking.py84
4 files changed, 147 insertions, 4 deletions
diff --git a/.gitignore b/.gitignore
index 44c2f4b..d37770f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,3 +23,5 @@ schedcat/sim/_sim.so
23schedcat/sim/native.py 23schedcat/sim/native.py
24tmp/ 24tmp/
25TAGS 25TAGS
26schedcat/locking/linprog/_lp_analysis.so
27schedcat/locking/linprog/native.py
diff --git a/Makefile b/Makefile
index dcaf25d..5a942b0 100644
--- a/Makefile
+++ b/Makefile
@@ -14,11 +14,13 @@ cpp:
14links: clean-links cpp 14links: 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
19clean-links: 20clean-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
24clean: clean-links 26clean: 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):
66def get_round_robin_resource_mapping(num_resources, num_cpus, 66def 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 77def 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
78def apply_dpcp_bounds(all_tasks, resource_mapping): 83def 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
179try:
180 import schedcat.locking.linprog.native as lp_cpp
181
182 lp_cpp_available = True
183except ImportError:
184 lp_cpp_available = False
185
186import schedcat.locking.linprog.dflp as dflp
187import schedcat.locking.linprog.dpcp as dpcp
188
189def 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
201def 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
213def 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
9import schedcat.model.tasks as tasks 9import schedcat.model.tasks as tasks
10import schedcat.model.resources as r 10import schedcat.model.resources as r
11 11
12import schedcat.util.linprog
13
12class Locking(unittest.TestCase): 14class 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
644class 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