diff options
author | Mac Mollison <mollison@cs.unc.edu> | 2009-03-03 20:16:52 -0500 |
---|---|---|
committer | Mac Mollison <mollison@cs.unc.edu> | 2009-03-03 20:16:52 -0500 |
commit | ab1f1ca679d1ef327f9a3cac2eba48027ccd0cda (patch) | |
tree | 3624b84e14ff7ccf7c7021e7b8aa77c97b199353 | |
parent | b2d14e0e42b0f3983611128c1f6aae91892f29e7 (diff) |
Re-implemented EDF test with new stragety. Not tested yet, but a lot of progress has been made.
-rw-r--r-- | README | 19 | ||||
-rwxr-xr-x | run.py | 5 | ||||
-rwxr-xr-x | sta.py | 244 |
3 files changed, 105 insertions, 163 deletions
@@ -10,21 +10,12 @@ The general idea it that you use run.py to put in the commands you want to do, | |||
10 | and then do something like ./run.py > out to write out the records. | 10 | and then do something like ./run.py > out to write out the records. |
11 | 11 | ||
12 | 12 | ||
13 | ############################ | ||
14 | Gotchas | ||
15 | ############################ | ||
16 | Remember that a StReleaseData record has 'release_time', not 'when', as a field. | ||
17 | |||
18 | |||
19 | ############################# | 13 | ############################# |
20 | Development Notes | 14 | Development Notes |
21 | ############################# | 15 | ############################# |
22 | 16 | ||
23 | EDF tester seems to be working, but does not account for this scenario: | 17 | Need to account for situation where there is a tie in deadline which spans the |
24 | -release | 18 | topN category. |
25 | -switch_to | 19 | |
26 | -switch_away | 20 | Might think about adding in hooks, so you do the trace, then add in the hook to |
27 | -switch_to | 21 | see the state at the place you're curious about. |
28 | Rather, it finds the release and the first switch_to, leaving the second | ||
29 | switch_to in the queue of switches, thus upsetting the order of switches. The | ||
30 | way to solve this is to add switch_aways into the release filter. | ||
@@ -6,8 +6,8 @@ import sta | |||
6 | ###################################### | 6 | ###################################### |
7 | 7 | ||
8 | def main(): | 8 | def main(): |
9 | myEDF() | 9 | #myEDF() |
10 | #myTrace() | 10 | myTrace() |
11 | #switchToTrace() | 11 | #switchToTrace() |
12 | #releaseTrace() | 12 | #releaseTrace() |
13 | #oneCPU() | 13 | #oneCPU() |
@@ -27,6 +27,7 @@ def myEDF(): | |||
27 | def myTrace(): | 27 | def myTrace(): |
28 | trace = sta.Trace(g6_list) | 28 | trace = sta.Trace(g6_list) |
29 | trace.sort('when',alt='release_time') | 29 | trace.sort('when',alt='release_time') |
30 | trace.filter('type==2') | ||
30 | trace.print_count(True) | 31 | trace.print_count(True) |
31 | trace.print_records() | 32 | trace.print_records() |
32 | 33 | ||
@@ -146,168 +146,118 @@ class Trace: | |||
146 | ################## | 146 | ################## |
147 | 147 | ||
148 | class EDF: | 148 | class EDF: |
149 | """Object representing an EDF test | ||
150 | 149 | ||
151 | The strategy is to create a model of runnable and running tasks, which is | 150 | def __init__(self,trace_files, tolerance=150000, N=4): |
152 | updated and checked against an invariant every tick_size time units | ||
153 | |||
154 | The invariant is that every running task much have an earlier deadline | ||
155 | than every runnable task; an error message is not generated until the | ||
156 | invariant is false for more than a specified number of ticks (given by | ||
157 | 'tolerance')""" | ||
158 | |||
159 | def __init__(self,trace_files, tick_size=1000000, tolerance=1): | ||
160 | """Create an EDF test. | ||
161 | |||
162 | tick_size = check the invariant every tick_size units of time | ||
163 | |||
164 | tolerance = number of tick_size time units which can pass before | ||
165 | a false invariant triggers an error message""" | ||
166 | self.trace_files = trace_files | 151 | self.trace_files = trace_files |
167 | self.errors = 0 | ||
168 | self.runnables = [] | ||
169 | self.runnings = [] | ||
170 | self.time = None | ||
171 | self.tick_size = tick_size | ||
172 | self.tolerance = tolerance | 152 | self.tolerance = tolerance |
153 | self.jobs = [] | ||
154 | self.N = N #number of cores | ||
155 | self.now = 0 | ||
173 | 156 | ||
174 | def run_test(self): | 157 | def run_test(self): |
175 | """Run an EDF test""" | ||
176 | |||
177 | #Make the trace, in order | ||
178 | trace = Trace(self.trace_files) | 158 | trace = Trace(self.trace_files) |
179 | trace.sort('when',alt='release_time') | 159 | trace.sort('when',alt='release_time') |
180 | trace.iter = trace.iter.__iter__() | ||
181 | |||
182 | #Find the start time from the SysRelease record | ||
183 | while True: | ||
184 | record = trace.iter.__next__() | ||
185 | if record['type']==10: | ||
186 | self.time = record['when'] | ||
187 | print("Starting time: " + str(self.time)) | ||
188 | break | ||
189 | |||
190 | #Initialize variables needed for the algorithm | ||
191 | last_record = trace.iter.__next__() | ||
192 | finished = False | ||
193 | |||
194 | #Increment the time, update the model, and check the invariant | ||
195 | while not finished: | ||
196 | |||
197 | #Increment the time | ||
198 | self.time += self.tick_size | ||
199 | print("-"*50) | ||
200 | |||
201 | #Update the model with records that have passed the time | ||
202 | while Trace.getTime(last_record) < self.time: | ||
203 | last_record['overtime'] = 0 | ||
204 | self.update_model(last_record) | ||
205 | try: | ||
206 | last_record = trace.iter.__next__() | ||
207 | except StopIteration: | ||
208 | finished = True | ||
209 | break | ||
210 | |||
211 | #Check the invariant | ||
212 | self.check_invariant() | ||
213 | |||
214 | print('Errors : {0}'.format(self.errors)) | ||
215 | |||
216 | 160 | ||
217 | def check_invariant(self): | 161 | for record in trace.iter: |
218 | """Check the invariant: the earliest deadline in runnables should be | 162 | |
219 | later than the latest deadline in runnings""" | 163 | #Update now |
220 | 164 | if 'when' in record: | |
221 | #Find the max deadline in runnings | 165 | self.now = record['when'] |
222 | max_deadline = None | 166 | elif 'release_time' in record: |
223 | for record in self.runnings: | 167 | self.now = record['release_time'] |
224 | if max_deadline==None: | 168 | |
225 | max_deadline = record['deadline'] | 169 | #Process record |
170 | if record['type'] == 3: | ||
171 | if self.is_duplicate_release(record): continue | ||
172 | job = EDF.Job() | ||
173 | job.deadline = record['deadline'] | ||
174 | job.release_time = record['release_time'] | ||
175 | job.job = record['job'] | ||
176 | job.pid = record['pid'] | ||
177 | self.jobs.append(job) | ||
178 | print('{0}: {1} was released'.format(self.now,job.get_name())) | ||
179 | elif record['type'] == 5: | ||
180 | job = self.get_job(record['pid'],record['job']) | ||
181 | if job: | ||
182 | job.running = True | ||
183 | else: | ||
184 | continue | ||
185 | print('{0}: {1} was switched to' | ||
186 | .format(self.now,job.get_name())) | ||
187 | elif record['type'] == 6: | ||
188 | job = self.get_job(record['pid'],record['job']) | ||
189 | if job: | ||
190 | job.running = False | ||
191 | else: | ||
192 | continue | ||
193 | print('{0}: {1} was switched away' | ||
194 | .format(self.now,job.get_name())) | ||
195 | elif record['type'] == 7: | ||
196 | job = self.get_job(record['pid'],record['job']) | ||
197 | if job: | ||
198 | self.jobs.remove(job) | ||
199 | else: | ||
200 | continue | ||
201 | print('{0}: {1} completed' | ||
202 | .format(self.now,job.get_name())) | ||
203 | else: | ||
226 | continue | 204 | continue |
227 | elif record['deadline'] > max_deadline: | 205 | |
228 | max_deadline = record['deadline'] | 206 | #Sort jobs by deadline |
229 | 207 | self.jobs = sorted(self.jobs,key=lambda job: job.deadline) | |
230 | #Check against the deadlines in runnables | 208 | |
231 | if max_deadline: | 209 | #Check for inversions (and end-of inversions) in the top N jobs |
232 | for record in self.runnables: | 210 | for job in self.jobs[0:self.N]: |
233 | if record['deadline'] < max_deadline: | 211 | job.topN = True |
234 | record['overtime'] += 1 | 212 | if job.running == False: |
235 | if record['overtime'] > self.tolerance: | 213 | if job.inversion_start_time==0: |
236 | print("INVALID!") | 214 | job.inversion_start_time=self.now |
237 | self.print_runnables() | 215 | elif job.running == True: |
238 | self.print_runnings() | 216 | if job.inversion_start_time > 0: |
239 | record['overtime'] = -99999999999999999 | 217 | self.check_error(job) |
240 | self.errors += 1 | 218 | job.inversion_start_time = 0 |
241 | 219 | ||
242 | def update_model(self, record): | 220 | #Check for end-of-inversions in the other jobs |
243 | """Update our model of the system: running tasks ('self.runnings') and | 221 | for job in self.jobs[self.N:]: |
244 | runnable tasks ('self.runnable')""" | 222 | if job.topN == True: |
245 | 223 | job.topN = False | |
246 | #Releases | 224 | self.check_error(job) |
247 | if record['type'] == 3: | 225 | |
248 | if not self.check_duplicate_release(record): | 226 | def check_error(self, job): |
249 | self.runnables.append(record) | 227 | if job.inversion_start_time == 0: return |
250 | print("{0} became runnable" | 228 | if self.now - job.inversion_start_time > self.tolerance: |
251 | .format(Trace.getStr(record))) | 229 | print(' ' * 16 + job.get_name() + |
252 | 230 | ' was inverted for {0} time units,' | |
253 | #Switch Tos | 231 | .format(self.now - job.inversion_start_time)) |
254 | elif record['type'] == 5: | 232 | print(' '*26 + 'since {0}'.format(job.inversion_start_time)) |
255 | release_record = EDF.pop_job(record, self.runnables) | 233 | job.inversion_start_time = 0 |
256 | self.runnings.append(release_record) | 234 | |
257 | print("{0} became running".format(Trace.getStr(record))) | 235 | def get_job(self, pid, job): |
258 | 236 | for x in self.jobs: | |
259 | #Switch Aways | 237 | if x.pid == pid and x.job == job: |
260 | elif record['type'] == 6: | 238 | return x |
261 | release_record = EDF.pop_job(record, self.runnings) | 239 | |
262 | if release_record: | 240 | def is_duplicate_release(self, record): |
263 | self.runnables.append(release_record) | ||
264 | print('{0} went from running to runnable' | ||
265 | .format(Trace.getStr(record))) | ||
266 | |||
267 | #Completions | ||
268 | elif record['type'] == 7: | ||
269 | release_record = EDF.pop_job(record,self.runnings) | ||
270 | if not release_record: | ||
271 | release_record = EDF.pop_job(record,self.runnables) | ||
272 | print('{0} completed' | ||
273 | .format(Trace.getStr(record))) | ||
274 | |||
275 | def pop_job(record, record_list): | ||
276 | """Pop a job from a list of jobs""" | ||
277 | job = record['job'] | ||
278 | pid = record['pid'] | ||
279 | for record in record_list: | ||
280 | if record['job'] == job and record['pid'] == pid: | ||
281 | record_copy = copy.copy(record) | ||
282 | record_list.remove(record) | ||
283 | return record_copy | ||
284 | return None | ||
285 | |||
286 | def check_duplicate_release(self, record): | ||
287 | """Make sure we don't get duplicate releases""" | 241 | """Make sure we don't get duplicate releases""" |
288 | job = record['job'] | 242 | job = record['job'] |
289 | pid = record['pid'] | 243 | pid = record['pid'] |
290 | for record in self.runnables: | 244 | for x in self.jobs: |
291 | if record['job'] == job and record['pid'] == pid: | 245 | if x.job == job and x.pid == pid: |
292 | return True | 246 | return True |
293 | return False | 247 | return False |
294 | 248 | ||
295 | def print_runnables(self): | 249 | class Job: |
296 | """Print the runnable jobs""" | 250 | def __init__(self): |
297 | print("Runnable jobs:") | 251 | self.release_time = 0 |
298 | for record in self.runnables: | 252 | self.deadline = 0 |
299 | print('{0}, Deadline: {1}'.format(Trace.getStr(record, | 253 | self.job = 0 |
300 | omitTime=True), | 254 | self.pid = 0 |
301 | record['deadline'])) | 255 | self.running = False |
302 | 256 | self.topN = False | |
303 | def print_runnings(self): | 257 | self.inversion_start_time = 0 |
304 | """Print the runnable jobs""" | 258 | |
305 | print("Running jobs:") | 259 | def get_name(self): |
306 | for record in self.runnings: | 260 | return '({0},{1})'.format(self.pid,self.job) |
307 | print('{0}, Deadline: {1}'.format(Trace.getStr(record, | ||
308 | omitTime=True), | ||
309 | record['deadline'])) | ||
310 | |||
311 | 261 | ||
312 | #################################### | 262 | #################################### |
313 | # Types for binary data conversion # | 263 | # Types for binary data conversion # |