diff options
author | Mac Mollison <mollison@cs.unc.edu> | 2010-03-13 12:12:37 -0500 |
---|---|---|
committer | Mac Mollison <mollison@cs.unc.edu> | 2010-03-13 12:12:37 -0500 |
commit | 122f457226f54ad23b7cd138512502e430e704dc (patch) | |
tree | fee0690936c3ae95255e559cd0fd09f0fa8c2ad4 /unit_trace/gedf_test.py | |
parent | 14a40b99735f09f6e70b8e897acbb622f9115ca3 (diff) |
Further restructuring to create 'unit_trace' pkg
The unit_trace folder should be placed in
/usr/local/lib/pythonX.Y/site-packages.
This makes unit-trace submodules available from anywhere
on the system.
Diffstat (limited to 'unit_trace/gedf_test.py')
-rw-r--r-- | unit_trace/gedf_test.py | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/unit_trace/gedf_test.py b/unit_trace/gedf_test.py new file mode 100644 index 0000000..8457901 --- /dev/null +++ b/unit_trace/gedf_test.py | |||
@@ -0,0 +1,163 @@ | |||
1 | ############################################################################### | ||
2 | # Description | ||
3 | ############################################################################### | ||
4 | |||
5 | # G-EDF Test | ||
6 | |||
7 | ############################################################################### | ||
8 | # Imports | ||
9 | ############################################################################### | ||
10 | |||
11 | import copy | ||
12 | |||
13 | |||
14 | ############################################################################### | ||
15 | # Public Functions | ||
16 | ############################################################################### | ||
17 | |||
18 | def gedf_test(stream): | ||
19 | |||
20 | # Two lists to model the system: tasks occupying a CPU and tasks eligible | ||
21 | # to do so. Also, m = the number of CPUs. | ||
22 | eligible = [] | ||
23 | on_cpu = [] | ||
24 | m = None | ||
25 | |||
26 | # Time of the last record we saw. Only run the G-EDF test when the time | ||
27 | # is updated. | ||
28 | last_time = None | ||
29 | |||
30 | for record in stream: | ||
31 | if record.record_type != "event": | ||
32 | if record.record_type == "meta" and record.type_name == "num_cpus": | ||
33 | m = record.num_cpus | ||
34 | continue | ||
35 | |||
36 | # Check for inversion starts and ends and yield them. | ||
37 | # Only to the check when time has moved forward. | ||
38 | # (It is common to have records with simultaneous timestamps.) | ||
39 | if last_time is not None and last_time != record.when: | ||
40 | errors = _gedf_check(eligible,on_cpu,record.when,m) | ||
41 | for error in errors: | ||
42 | yield error | ||
43 | |||
44 | # Add a newly-released Job to the eligible queue | ||
45 | if record.type_name == 'release': | ||
46 | eligible.append(Job(record)) | ||
47 | |||
48 | # Move a Job from the eligible queue to on_cpu | ||
49 | elif record.type_name == 'switch_to': | ||
50 | pos = _find_job(record,eligible) | ||
51 | job = eligible[pos] | ||
52 | del eligible[pos] | ||
53 | on_cpu.append(job) | ||
54 | |||
55 | # Mark a Job as completed. | ||
56 | # The only time a Job completes when it is not on a | ||
57 | # CPU is when it is the last job of the task. | ||
58 | elif record.type_name == 'completion': | ||
59 | pos = _find_job(record,on_cpu) | ||
60 | if pos is not None: | ||
61 | on_cpu[pos].is_complete = True | ||
62 | else: | ||
63 | pos = _find_job(record,eligible) | ||
64 | del eligible[pos] | ||
65 | |||
66 | # A job is switched away from a CPU. If it has | ||
67 | # been marked as complete, remove it from the model. | ||
68 | elif record.type_name == 'switch_away': | ||
69 | pos = _find_job(record,on_cpu) | ||
70 | job = on_cpu[pos] | ||
71 | del on_cpu[pos] | ||
72 | if job.is_complete == False: | ||
73 | eligible.append(job) | ||
74 | |||
75 | last_time = record.when | ||
76 | yield record | ||
77 | |||
78 | ############################################################################### | ||
79 | # Private Functions | ||
80 | ############################################################################### | ||
81 | |||
82 | # Internal representation of a Job | ||
83 | class Job(object): | ||
84 | def __init__(self, record): | ||
85 | self.pid = record.pid | ||
86 | self.job = record.job | ||
87 | self.deadline = record.deadline | ||
88 | self.is_complete = False | ||
89 | self.inversion_start = None | ||
90 | self.inversion_end = None | ||
91 | def __str__(self): | ||
92 | return "(%d.%d:%d)" % (self.pid,self.job,self.deadline) | ||
93 | |||
94 | # G-EDF errors: the start or end of an inversion | ||
95 | class Error(object): | ||
96 | def __init__(self, job, eligible, on_cpu): | ||
97 | self.job = copy.copy(job) | ||
98 | self.eligible = copy.copy(eligible) | ||
99 | self.on_cpu = copy.copy(on_cpu) | ||
100 | self.record_type = 'error' | ||
101 | if job.inversion_end is None: | ||
102 | self.type_name = 'inversion_start' | ||
103 | else: | ||
104 | self.type_name = 'inversion_end' | ||
105 | |||
106 | # Returns the position of a Job in a list, or None | ||
107 | def _find_job(record,list): | ||
108 | for i in range(0,len(list)): | ||
109 | if list[i].pid == record.pid and list[i].job == record.job: | ||
110 | return i | ||
111 | return None | ||
112 | |||
113 | # Return records for any inversion_starts and inversion_ends | ||
114 | def _gedf_check(eligible,on_cpu,when,m): | ||
115 | |||
116 | # List of error records to be returned | ||
117 | errors = [] | ||
118 | |||
119 | # List of all jobs that are not complete | ||
120 | all = [] | ||
121 | for x in on_cpu: | ||
122 | if x.is_complete is not True: | ||
123 | all.append(x) | ||
124 | all += eligible | ||
125 | |||
126 | # Sort by on_cpu and then by deadline. sort() is guaranteed to be stable. | ||
127 | # Thus, this gives us jobs ordered by deadline with preference to those | ||
128 | # actually running. | ||
129 | all.sort(key=lambda x: 0 if (x in on_cpu) else 1) | ||
130 | all.sort(key=lambda x: x.deadline) | ||
131 | |||
132 | # Check those that actually should be running | ||
133 | for x in range(0,min(m,len(all))): | ||
134 | job = all[x] | ||
135 | |||
136 | # It's not running and an inversion_start has not been recorded | ||
137 | if job not in on_cpu and job.inversion_start is None: | ||
138 | job.inversion_start = when | ||
139 | errors.append(Error(job, eligible, on_cpu)) | ||
140 | |||
141 | # It is running and an inversion_start exists (i.e. it it still | ||
142 | # marked as being inverted) | ||
143 | elif job in on_cpu and job.inversion_start is not None: | ||
144 | job.inversion_end = when | ||
145 | errors.append(Error(job, eligible, on_cpu)) | ||
146 | job.inversion_start = None | ||
147 | job.inversion_end = None | ||
148 | |||
149 | # Check those that actually should not be running | ||
150 | for x in range(m,len(all)): | ||
151 | job = all[x] | ||
152 | |||
153 | # It actually is running. We don't care. | ||
154 | |||
155 | # It isn't running, but an inversion_start exists (i.e. it is still | ||
156 | # marked as being inverted) | ||
157 | if job not in on_cpu and job.inversion_start is not None: | ||
158 | job.inversion_end = when | ||
159 | errors.append(Error(job, eligible, on_cpu)) | ||
160 | job.inversion_start = None | ||
161 | job.inversion_end = None | ||
162 | |||
163 | return errors | ||