math_vis: remove use of register_module
[blender-addons.git] / netrender / balancing.py
blobe60165ddfd287517a32e68e33e1e7dd1ad157e77
1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
19 import time
21 from netrender.utils import *
22 import netrender.model
24 class RatingRule:
25 def __init__(self):
26 self.enabled = True
27 self.editable = False
29 def id(self):
30 return str(id(self))
32 def rate(self, job):
33 return 0
35 class ExclusionRule:
36 def __init__(self):
37 self.enabled = True
38 self.editable = True
39 def id(self):
40 return str(id(self))
42 def test(self, job):
43 return False
45 class PriorityRule:
46 def __init__(self):
47 self.enabled = True
48 self.editable = True
49 def id(self):
50 return str(id(self))
52 def test(self, job):
53 return False
55 class Balancer:
56 def __init__(self):
57 self.rules = []
58 self.priorities = []
59 self.exceptions = []
61 def ruleByID(self, rule_id):
62 for rule in self.rules:
63 if rule.id() == rule_id:
64 return rule
65 for rule in self.priorities:
66 if rule.id() == rule_id:
67 return rule
68 for rule in self.exceptions:
69 if rule.id() == rule_id:
70 return rule
72 return None
74 def addRule(self, rule):
75 self.rules.append(rule)
77 def addPriority(self, priority):
78 self.priorities.append(priority)
80 def addException(self, exception):
81 self.exceptions.append(exception)
83 def applyRules(self, job):
84 return sum((rule.rate(job) for rule in self.rules if rule.enabled))
86 def applyPriorities(self, job):
87 for priority in self.priorities:
88 if priority.enabled and priority.test(job):
89 return True # priorities are first
91 return False
93 def applyExceptions(self, job):
94 for exception in self.exceptions:
95 if exception.enabled and exception.test(job):
96 return True # exceptions are last
98 return False
100 def sortKey(self, job):
101 return (1 if self.applyExceptions(job) else 0, # exceptions after
102 0 if self.applyPriorities(job) else 1, # priorities first
103 self.applyRules(job))
105 def balance(self, jobs):
106 if jobs:
107 # use inline copy to make sure the list is still accessible while sorting
108 jobs[:] = sorted(jobs, key=self.sortKey)
109 return jobs[0]
110 else:
111 return None
113 # ==========================
115 class RatingUsage(RatingRule):
116 def __str__(self):
117 return "Usage per job"
119 def rate(self, job):
120 # less usage is better
121 return job.usage / job.priority
122 def serialize(self):
123 return { "type": "rating",
124 "enabled": self.enabled,
125 "descritpiton":str(self),
126 "limit":"",
127 "id":self.id()
131 class RatingUsageByCategory(RatingRule):
132 def __init__(self, get_jobs):
133 super().__init__()
134 self.getJobs = get_jobs
136 def __str__(self):
137 return "Usage per category"
139 def rate(self, job):
140 total_category_usage = sum([j.usage for j in self.getJobs() if j.category == job.category])
141 maximum_priority = max([j.priority for j in self.getJobs() if j.category == job.category])
143 # less usage is better
144 return total_category_usage / maximum_priority
146 def serialize(self):
147 return { "type": "rating",
148 "enabled": self.enabled,
149 "editable": self.editable,
150 "descritpiton":str(self),
151 "limit":"",
152 "id":self.id()
156 class NewJobPriority(PriorityRule):
157 def __init__(self, limit = 1):
158 super().__init__()
159 self.limit = limit
161 def setLimit(self, value):
162 self.limit = int(value)
164 def str_limit(self):
165 return "less than %i frame%s done" % (self.limit, "s" if self.limit > 1 else "")
167 def __str__(self):
168 return "Priority to new jobs"
170 def test(self, job):
171 return job.countFrames(status = netrender.model.FRAME_DONE) < self.limit
172 def serialize(self):
173 return { "type": "priority",
174 "enabled": self.enabled,
175 "editable": self.editable,
176 "descritpiton":str(self),
177 "limit": self.limit,
178 "limit_str":self.str_limit(),
179 "id":self.id()
182 class MinimumTimeBetweenDispatchPriority(PriorityRule):
183 def __init__(self, limit = 10):
184 super().__init__()
185 self.limit = limit
187 def setLimit(self, value):
188 self.limit = int(value)
190 def str_limit(self):
191 return "more than %i minute%s since last" % (self.limit, "s" if self.limit > 1 else "")
193 def __str__(self):
194 return "Priority to jobs that haven't been dispatched recently"
196 def test(self, job):
197 return job.countFrames(status = netrender.model.FRAME_DISPATCHED) == 0 and (time.time() - job.last_dispatched) / 60 > self.limit
199 def serialize(self):
200 return { "type": "priority",
201 "enabled": self.enabled,
202 "editable": self.editable,
203 "descritpiton":str(self),
204 "limit": self.limit,
205 "limit_str":self.str_limit(),
206 "id":self.id()
209 class ExcludeQueuedEmptyJob(ExclusionRule):
210 def __init__(self):
211 super().__init__()
212 self.editable= False
213 def __str__(self):
214 return "Exclude non queued or empty jobs"
216 def test(self, job):
217 return job.status != netrender.model.JOB_QUEUED or job.countFrames(status = netrender.model.FRAME_QUEUED) == 0
219 def serialize(self):
220 return { "type": "exception",
221 "enabled": self.enabled,
222 "editable": self.editable,
223 "descritpiton":str(self),
224 "limit": "",
225 "limit_str":"",
226 "id":self.id()
230 class ExcludeSlavesLimit(ExclusionRule):
231 def __init__(self, count_jobs, count_slaves, limit = 0.75):
232 super().__init__()
233 self.count_jobs = count_jobs
234 self.count_slaves = count_slaves
235 self.limit = limit
237 def setLimit(self, value):
238 self.limit = float(value)
240 def str_limit(self):
241 return "more than %.0f%% of all slaves" % (self.limit * 100)
243 def __str__(self):
244 return "Exclude jobs that would use too many slaves"
246 def test(self, job):
247 return not ( self.count_jobs() == 1 or self.count_slaves() <= 1 or float(job.countSlaves() + 1) / self.count_slaves() <= self.limit )
249 def serialize(self):
250 return { "type": "exception",
251 "enabled": self.enabled,
252 "editable": self.editable,
253 "descritpiton":str(self),
254 "limit": self.limit,
255 "limit_str":self.str_limit(),
256 "id":self.id()