summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMac Mollison <mollison@cs.unc.edu>2009-03-03 20:16:52 -0500
committerMac Mollison <mollison@cs.unc.edu>2009-03-03 20:16:52 -0500
commitab1f1ca679d1ef327f9a3cac2eba48027ccd0cda (patch)
tree3624b84e14ff7ccf7c7021e7b8aa77c97b199353
parentb2d14e0e42b0f3983611128c1f6aae91892f29e7 (diff)
Re-implemented EDF test with new stragety. Not tested yet, but a lot of progress has been made.
-rw-r--r--README19
-rwxr-xr-xrun.py5
-rwxr-xr-xsta.py244
3 files changed, 105 insertions, 163 deletions
diff --git a/README b/README
index 4be61b3..16450df 100644
--- a/README
+++ b/README
@@ -10,21 +10,12 @@ The general idea it that you use run.py to put in the commands you want to do,
10and then do something like ./run.py > out to write out the records. 10and then do something like ./run.py > out to write out the records.
11 11
12 12
13############################
14Gotchas
15############################
16Remember that a StReleaseData record has 'release_time', not 'when', as a field.
17
18
19############################# 13#############################
20Development Notes 14Development Notes
21############################# 15#############################
22 16
23EDF tester seems to be working, but does not account for this scenario: 17Need to account for situation where there is a tie in deadline which spans the
24-release 18topN category.
25-switch_to 19
26-switch_away 20Might think about adding in hooks, so you do the trace, then add in the hook to
27-switch_to 21see the state at the place you're curious about.
28Rather, it finds the release and the first switch_to, leaving the second
29switch_to in the queue of switches, thus upsetting the order of switches. The
30way to solve this is to add switch_aways into the release filter.
diff --git a/run.py b/run.py
index 7ae3f53..42cf27b 100755
--- a/run.py
+++ b/run.py
@@ -6,8 +6,8 @@ import sta
6###################################### 6######################################
7 7
8def main(): 8def 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():
27def myTrace(): 27def 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
diff --git a/sta.py b/sta.py
index 3d76031..3add6ec 100755
--- a/sta.py
+++ b/sta.py
@@ -146,168 +146,118 @@ class Trace:
146################## 146##################
147 147
148class EDF: 148class 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 #