summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan <hermanjl@hermanjl-Aspire-5553G.(none)>2011-01-27 00:51:17 -0500
committerJonathan <hermanjl@hermanjl-Aspire-5553G.(none)>2011-01-27 00:51:17 -0500
commitc4edd95d28b9212e09e8caca0d6b11937f453995 (patch)
tree7237b64d71c9e9856e13a687eab336691a1a26f6
parent27f0b6ca2baac29c1b61001306caf4186f5c108a (diff)
Added support for visualizing arbitrary actions.wip-events
-rw-r--r--unit_trace/sanitizer.py10
-rw-r--r--unit_trace/trace_reader.py14
-rw-r--r--unit_trace/viz/canvas.py63
-rw-r--r--unit_trace/viz/convert.py31
-rw-r--r--unit_trace/viz/graph.py72
-rw-r--r--unit_trace/viz/schedule.py125
6 files changed, 263 insertions, 52 deletions
diff --git a/unit_trace/sanitizer.py b/unit_trace/sanitizer.py
index 598379a..fc66170 100644
--- a/unit_trace/sanitizer.py
+++ b/unit_trace/sanitizer.py
@@ -14,6 +14,8 @@ def sanitizer(stream):
14 job_2s_released = [] # list of tasks which have released their job 2s 14 job_2s_released = [] # list of tasks which have released their job 2s
15 jobs_switched_to = [] 15 jobs_switched_to = []
16 16
17 released = False
18
17 for record in stream: 19 for record in stream:
18 20
19 # Ignore records which are not events (e.g. the num_cpus record) 21 # Ignore records which are not events (e.g. the num_cpus record)
@@ -21,6 +23,13 @@ def sanitizer(stream):
21 yield record 23 yield record
22 continue 24 continue
23 25
26 if record.type_name == 'release':
27 released = released or True
28
29 if record.type_name == 'action' and released:
30 yield record
31 continue
32
24 # All records with job < 2 are garbage 33 # All records with job < 2 are garbage
25 if record.job < 2: 34 if record.job < 2:
26 continue 35 continue
@@ -50,4 +59,5 @@ def sanitizer(stream):
50 if (record.pid,record.job) not in jobs_switched_to: 59 if (record.pid,record.job) not in jobs_switched_to:
51 record.job -= 1 60 record.job -= 1
52 61
62
53 yield record 63 yield record
diff --git a/unit_trace/trace_reader.py b/unit_trace/trace_reader.py
index a4c3c05..fe5c03c 100644
--- a/unit_trace/trace_reader.py
+++ b/unit_trace/trace_reader.py
@@ -93,7 +93,6 @@ def trace_reader(files):
93 93
94 # Keep pulling records as long as we have a buffer 94 # Keep pulling records as long as we have a buffer
95 while len(file_iter_buff) > 0: 95 while len(file_iter_buff) > 0:
96
97 # Select the earliest record from those at the heads of the buffers 96 # Select the earliest record from those at the heads of the buffers
98 earliest = -1 97 earliest = -1
99 buff_to_refill = -1 98 buff_to_refill = -1
@@ -120,7 +119,8 @@ def trace_reader(files):
120 del file_iters[buff_to_refill] 119 del file_iters[buff_to_refill]
121 120
122 # Check for monotonically increasing time 121 # Check for monotonically increasing time
123 if last_time is not None and earliest.when < last_time: 122 if last_time is not None and earliest.when != 0 and earliest.when < last_time:
123 print("FATAL Old: %s, New: %s" % (last_time, earliest.when))
124 exit("FATAL ERROR: trace_reader.py: out-of-order record produced") 124 exit("FATAL ERROR: trace_reader.py: out-of-order record produced")
125 else: 125 else:
126 last_time = earliest.when 126 last_time = earliest.when
@@ -203,6 +203,12 @@ class StHeader:
203 keys = ['type','cpu','pid','job'] 203 keys = ['type','cpu','pid','job']
204 message = 'The header.' 204 message = 'The header.'
205 205
206class StActionData:
207 format = 'Qb'
208 formatStr = struct.Struct(StHeader.format + format)
209 keys = StHeader.keys + ['when','action']
210 message = 'An action was performed.'
211
206class StNameData: 212class StNameData:
207 format = '16s' 213 format = '16s'
208 formatStr = struct.Struct(StHeader.format + format) 214 formatStr = struct.Struct(StHeader.format + format)
@@ -269,7 +275,7 @@ class StSysReleaseData:
269def _get_type(type_num): 275def _get_type(type_num):
270 types = [None,StNameData,StParamData,StReleaseData,StAssignedData, 276 types = [None,StNameData,StParamData,StReleaseData,StAssignedData,
271 StSwitchToData,StSwitchAwayData,StCompletionData,StBlockData, 277 StSwitchToData,StSwitchAwayData,StCompletionData,StBlockData,
272 StResumeData,StSysReleaseData] 278 StResumeData,StActionData,StSysReleaseData]
273 if type_num > len(types)-1 or type_num < 1: 279 if type_num > len(types)-1 or type_num < 1:
274 raise Exception 280 raise Exception
275 return types[type_num] 281 return types[type_num]
@@ -278,5 +284,5 @@ def _get_type(type_num):
278# programmers of other modules) 284# programmers of other modules)
279def _get_type_name(type_num): 285def _get_type_name(type_num):
280 type_names = [None,"name","params","release","assign","switch_to", 286 type_names = [None,"name","params","release","assign","switch_to",
281 "switch_away","completion","block","resume","sys_release"] 287 "switch_away","completion","block","resume","action","sys_release"]
282 return type_names[type_num] 288 return type_names[type_num]
diff --git a/unit_trace/viz/canvas.py b/unit_trace/viz/canvas.py
index badebe9..2c977ae 100644
--- a/unit_trace/viz/canvas.py
+++ b/unit_trace/viz/canvas.py
@@ -521,14 +521,44 @@ class Canvas(object):
521 self.add_sel_region(SelectableRegion(x - big_arrowhead_height / Canvas.SQRT3, 521 self.add_sel_region(SelectableRegion(x - big_arrowhead_height / Canvas.SQRT3,
522 y, 2.0 * big_arrowhead_height / Canvas.SQRT3, height, event)) 522 y, 2.0 * big_arrowhead_height / Canvas.SQRT3, height, event))
523 523
524 def draw_action_symbol(self, item, action, x, y, height, selected):
525 """Draws a release arrow: x, y should give the top (northernmost
526 point) of the arrow. The height includes the arrowhead."""
527
528 color = {False : GraphFormat.BORDER_COLOR,
529 True : GraphFormat.HIGHLIGHT_COLOR}[selected]
530
531 colors = [self.get_bar_pattern(item).get_color_list()[0], color]
532 draw_funcs = [self.__class__.fill_polyline, self.__class__.draw_polyline]
533
534 for i in range(0, 2):
535 color = colors[i]
536 draw_func = draw_funcs[i]
537
538 draw_func(self, [(x, y), (x - height / Canvas.SQRT3, \
539 y - height), \
540 (x + height / Canvas.SQRT3, \
541 y - height), \
542 (x, y)], color, GraphFormat.BORDER_THICKNESS)
543
544 self.draw_label(str(action), x, y - height / 2 - .1 * height,
545 GraphFormat.DEF_FOPTS_LABEL,
546 AlignMode.CENTER, AlignMode.CENTER, True)
547
548 def add_sel_action_symbol(self, x, y, height, event):
549 self.add_sel_region(SelectableRegion(x - height / Canvas.SQRT3,
550 y - height, 2.0 * height / Canvas.SQRT3, height, event))
551
524 def draw_release_arrow_small(self, x, y, height, selected): 552 def draw_release_arrow_small(self, x, y, height, selected):
525 """Draws a small release arrow (most likely coming off the x-axis, although 553 """Draws a small release arrow (most likely coming off the x-axis, although
526 this method doesn't enforce this): x, y should give the top of the arrow""" 554 this method doesn't enforce this): x, y should give the top of the arrow"""
527 small_arrowhead_height = GraphFormat.SMALL_ARROWHEAD_FACTOR * height 555 small_arrowhead_height = GraphFormat.SMALL_ARROWHEAD_FACTOR * height
528 556
529 color = {False : GraphFormat.BORDER_COLOR, True : GraphFormat.HIGHLIGHT_COLOR}[selected] 557 color = {False : GraphFormat.BORDER_COLOR,
558 True : GraphFormat.HIGHLIGHT_COLOR}[selected]
530 559
531 self.draw_line((x, y), (x - small_arrowhead_height, y + small_arrowhead_height), \ 560 self.draw_line((x, y),
561 (x - small_arrowhead_height, y + small_arrowhead_height),
532 color, GraphFormat.BORDER_THICKNESS) 562 color, GraphFormat.BORDER_THICKNESS)
533 self.draw_line((x, y), (x + small_arrowhead_height, y + small_arrowhead_height), \ 563 self.draw_line((x, y), (x + small_arrowhead_height, y + small_arrowhead_height), \
534 color, GraphFormat.BORDER_THICKNESS) 564 color, GraphFormat.BORDER_THICKNESS)
@@ -754,13 +784,35 @@ class CairoCanvas(Canvas):
754 self.surface.ctx.set_line_width(thickness * self.scale) 784 self.surface.ctx.set_line_width(thickness * self.scale)
755 self.surface.ctx.stroke() 785 self.surface.ctx.stroke()
756 786
787 def draw_circle(self, x, y, radius, fill_color, border_color,
788 thickness, do_snap=True):
789 p = self.surface.get_real_coor(x, y)
790 if do_snap:
791 p = (snap(p[0]), snap(p[1]))
792
793 self.surface.ctx.save()
794 self.surface.ctx.arc(p[0], p[1], radius, 0.0, 2 * math.pi)
795 self.surface.ctx.set_source_rgb(border_color[0],
796 border_color[1],
797 border_color[2])
798 self.surface.ctx.set_line_width(thickness * self.scale)
799 self.surface.ctx.stroke()
800 self.surface.ctx.arc(p[0], p[1], radius, 0.0, 2 * math.pi)
801 self.surface.ctx.set_source_rgb(fill_color[0],
802 fill_color[1],
803 fill_color[2])
804 self.surface.ctx.fill()
805 self.surface.ctx.restore()
806
757 def _polyline_common(self, coor_list, color, thickness, do_snap=True): 807 def _polyline_common(self, coor_list, color, thickness, do_snap=True):
758 real_coor_list = [self.surface.get_real_coor(coor[0], coor[1]) for coor in coor_list] 808 real_coor_list = [self.surface.get_real_coor(coor[0], coor[1]) \
809 for coor in coor_list]
759 810
760 self.surface.ctx.move_to(real_coor_list[0][0], real_coor_list[0][1]) 811 self.surface.ctx.move_to(real_coor_list[0][0], real_coor_list[0][1])
761 if do_snap: 812 if do_snap:
762 for i in range(0, len(real_coor_list)): 813 for i in range(0, len(real_coor_list)):
763 real_coor_list[i] = (snap(real_coor_list[i][0]), snap(real_coor_list[i][1])) 814 real_coor_list[i] = (snap(real_coor_list[i][0]),
815 snap(real_coor_list[i][1]))
764 816
765 for coor in real_coor_list[1:]: 817 for coor in real_coor_list[1:]:
766 self.surface.ctx.line_to(coor[0], coor[1]) 818 self.surface.ctx.line_to(coor[0], coor[1])
@@ -830,7 +882,8 @@ class CairoCanvas(Canvas):
830 f_descent_factor, width_factor, f_height_factor, 882 f_descent_factor, width_factor, f_height_factor,
831 do_snap) 883 do_snap)
832 884
833 def draw_label(self, text, x, y, fopts=GraphFormat.DEF_FOPTS_LABEL, halign=AlignMode.LEFT, valign=AlignMode.BOTTOM, do_snap=True): 885 def draw_label(self, text, x, y, fopts=GraphFormat.DEF_FOPTS_LABEL,
886 halign=AlignMode.LEFT, valign=AlignMode.BOTTOM, do_snap=True):
834 """Draws a label with the given parameters, with the given horizontal and vertical justification.""" 887 """Draws a label with the given parameters, with the given horizontal and vertical justification."""
835 888
836 actual_x, actual_y, width, height, f_height = self.get_label_dim(text, x, y, fopts, halign, valign, do_snap) 889 actual_x, actual_y, width, height, f_height = self.get_label_dim(text, x, y, fopts, halign, valign, do_snap)
diff --git a/unit_trace/viz/convert.py b/unit_trace/viz/convert.py
index d19bc73..278a541 100644
--- a/unit_trace/viz/convert.py
+++ b/unit_trace/viz/convert.py
@@ -16,14 +16,17 @@ def get_type_num(type):
16 return nums[type] 16 return nums[type]
17 17
18def _get_job_from_record(sched, record): 18def _get_job_from_record(sched, record):
19 tname = _pid_to_task_name(record.pid) 19 if record.pid == 0:
20 job_no = record.job 20 return None
21 if tname not in sched.get_tasks(): 21 else:
22 sched.add_task(Task(tname, [])) 22 tname = _pid_to_task_name(record.pid)
23 if job_no not in sched.get_tasks()[tname].get_jobs(): 23 job_no = record.job
24 sched.get_tasks()[tname].add_job(Job(job_no, [])) 24 if tname not in sched.get_tasks():
25 job = sched.get_tasks()[tname].get_jobs()[job_no] 25 sched.add_task(Task(tname, []))
26 return job 26 if job_no not in sched.get_tasks()[tname].get_jobs():
27 sched.get_tasks()[tname].add_job(Job(job_no, []))
28 job = sched.get_tasks()[tname].get_jobs()[job_no]
29 return job
27 30
28def convert_trace_to_schedule(stream): 31def convert_trace_to_schedule(stream):
29 """The main function of interest in this module. Coverts a stream of records 32 """The main function of interest in this module. Coverts a stream of records
@@ -45,12 +48,20 @@ def convert_trace_to_schedule(stream):
45 if not hasattr(record, 'deadline'): 48 if not hasattr(record, 'deadline'):
46 record.deadline = None 49 record.deadline = None
47 50
51 # This whole method should be refactored for this posibility
52 if job is None:
53 if record.type_name == "action":
54 event = ActionEvent(record.when, cpu, record.action)
55 event.set_schedule(sched)
56 sched.add_jobless(event)
57 continue
58
48 actions = { 59 actions = {
49 'name' : (noop), 60 'name' : (noop),
50 'params' : (noop), 61 'params' : (noop),
51 'release' : (lambda : 62 'release' : (lambda :
52 (job.add_event(ReleaseEvent(record.when, cpu)), 63 (job.add_event(ReleaseEvent(record.when, cpu)),
53 job.add_event(DeadlineEvent(record.deadline, cpu)))), 64 job.add_event(DeadlineEvent(record.deadline, cpu)))),
54 'switch_to' : (lambda : 65 'switch_to' : (lambda :
55 job.add_event(SwitchToEvent(record.when, cpu))), 66 job.add_event(SwitchToEvent(record.when, cpu))),
56 'switch_away' : (lambda : 67 'switch_away' : (lambda :
@@ -62,6 +73,8 @@ def convert_trace_to_schedule(stream):
62 job.add_event(SuspendEvent(record.when, cpu))), 73 job.add_event(SuspendEvent(record.when, cpu))),
63 'resume' : (lambda : 74 'resume' : (lambda :
64 job.add_event(ResumeEvent(record.when, cpu))), 75 job.add_event(ResumeEvent(record.when, cpu))),
76 'action' : (lambda :
77 job.add_event(ActionEvent(record.when, cpu, record.action))),
65 'sys_release' : (noop) 78 'sys_release' : (noop)
66 } 79 }
67 80
diff --git a/unit_trace/viz/graph.py b/unit_trace/viz/graph.py
index 73c4ce4..e157335 100644
--- a/unit_trace/viz/graph.py
+++ b/unit_trace/viz/graph.py
@@ -8,11 +8,12 @@ than the canvas classes (time and task/cpu number rather than plain coordinates)
8update themselves, unlike the Canvas which can only overwrite itself.""" 8update themselves, unlike the Canvas which can only overwrite itself."""
9 9
10class Graph(object): 10class Graph(object):
11 DEF_BAR_PLIST = [Pattern([(0.0, 0.9, 0.9)]), Pattern([(0.9, 0.3, 0.0)]), Pattern([(0.9, 0.7, 0.0)]), 11 DEF_BAR_PLIST = [Pattern([(0.0, 0.9, 0.9)]), Pattern([(0.9, 0.3, 0.0)]),
12 Pattern([(0.0, 0.0, 0.8)]), Pattern([(0.0, 0.2, 0.9)]), Pattern([(0.0, 0.6, 0.6)]), 12 Pattern([(0.9, 0.7, 0.0)]), Pattern([(0.0, 0.0, 0.8)]),
13 Pattern([(0.0, 0.2, 0.9)]), Pattern([(0.0, 0.6, 0.6)]),
13 Pattern([(0.75, 0.75, 0.75)])] 14 Pattern([(0.75, 0.75, 0.75)])]
14 DEF_ITEM_CLIST = [(0.3, 0.0, 0.0), (0.0, 0.3, 0.0), (0.0, 0.0, 0.3), (0.3, 0.3, 0.0), (0.0, 0.3, 0.3), 15 DEF_ITEM_CLIST = [(0.3, 0.0, 0.0), (0.0, 0.3, 0.0), (0.0, 0.0, 0.3),
15 (0.3, 0.0, 0.3)] 16 (0.3, 0.3, 0.0), (0.0, 0.3, 0.3), (0.3, 0.0, 0.3)]
16 17
17 def __init__(self, CanvasType, surface, start_time, end_time, y_item_list, top_item_list, attrs=GraphFormat(), 18 def __init__(self, CanvasType, surface, start_time, end_time, y_item_list, top_item_list, attrs=GraphFormat(),
18 item_clist=DEF_ITEM_CLIST, bar_plist=DEF_BAR_PLIST): 19 item_clist=DEF_ITEM_CLIST, bar_plist=DEF_BAR_PLIST):
@@ -166,9 +167,12 @@ class Graph(object):
166 """get x so that x is at instant ``time'' on the graph""" 167 """get x so that x is at instant ``time'' on the graph"""
167 return self.origin[0] + GraphFormat.X_AXIS_MEASURE_OFS + 1.0 * (time - self.start_time) / self.attrs.time_per_maj * self.attrs.maj_sep 168 return self.origin[0] + GraphFormat.X_AXIS_MEASURE_OFS + 1.0 * (time - self.start_time) / self.attrs.time_per_maj * self.attrs.maj_sep
168 169
170 def get_item_yorigin(self, item_no):
171 return self.origin[1] - self._get_y_axis_height() + self.attrs.y_item_size * item_no;
172
169 def get_item_ypos(self, item_no): 173 def get_item_ypos(self, item_no):
170 """get y so that y is where the top of a bar would be in item #n's area""" 174 """get y so that y is where the top of a bar would be in item #n's area"""
171 return self.origin[1] - self._get_y_axis_height() + self.attrs.y_item_size * (item_no + 0.5 - GraphFormat.BAR_SIZE_FACTOR / 2.0) 175 return self.get_item_yorigin(item_no) + self.attrs.y_item_size * (0.5 - GraphFormat.BAR_SIZE_FACTOR / 2.0)
172 176
173 def _get_bar_width(self, start_time, end_time): 177 def _get_bar_width(self, start_time, end_time):
174 return 1.0 * (end_time - start_time) / self.attrs.time_per_maj * self.attrs.maj_sep 178 return 1.0 * (end_time - start_time) / self.attrs.time_per_maj * self.attrs.maj_sep
@@ -256,6 +260,8 @@ class Graph(object):
256 for event in sched.get_time_slot_array().get_events(slots, 260 for event in sched.get_time_slot_array().get_events(slots,
257 self.list_type, schedule.EVENT_LIST): 261 self.list_type, schedule.EVENT_LIST):
258 events_to_render[event.get_layer()][event] = None 262 events_to_render[event.get_layer()][event] = None
263 for event in sched.get_jobless():
264 events_to_render[event.get_layer()][event] = None
259 265
260 return events_to_render 266 return events_to_render
261 267
@@ -403,6 +409,16 @@ class Graph(object):
403 a certain time.""" 409 a certain time."""
404 raise NotImplementedError 410 raise NotImplementedError
405 411
412 def draw_action_symbol_at_time(self, time, task_no, cpu_no, action,
413 job_no, selected=False):
414 """Draws an action symbol at a certain time for some task and job"""
415 raise NotImplementedError
416
417 def add_sel_action_symbol_at_time(self, time, task_no, cpu_no, event):
418 """Same as above, except instead of drawing adds a selectable region at
419 a certain time."""
420 raise NotImplementedError
421
406 def draw_bar_at_time(self, start_time, end_time, task_no, cpu_no, job_no=None, clip_side=None): 422 def draw_bar_at_time(self, start_time, end_time, task_no, cpu_no, job_no=None, clip_side=None):
407 """Draws a bar over a certain time period for some task, optionally labelling it.""" 423 """Draws a bar over a certain time period for some task, optionally labelling it."""
408 raise NotImplementedError 424 raise NotImplementedError
@@ -526,6 +542,33 @@ class TaskGraph(Graph):
526 542
527 self.canvas.add_sel_deadline_arrow_big(x, y, height, event) 543 self.canvas.add_sel_deadline_arrow_big(x, y, height, event)
528 544
545 def draw_action_symbol_at_time(self, time, task_no, cpu_no, action,
546 job_no=None, selected=False):
547 x = self.get_time_xpos(time)
548 y = None
549
550 if task_no != -1:
551 y = self.get_item_ypos(task_no)
552 else:
553 y = self.origin[1]
554
555 height = 1.5 * (self.get_item_ypos(0) - self.get_item_yorigin(0))
556
557 self.canvas.draw_action_symbol(cpu_no, action, x, y, height, selected)
558
559 def add_sel_action_symbol_at_time(self, time, task_no, cpu_no, event):
560 x = self.get_time_xpos(time)
561 y = None
562
563 if task_no != -1:
564 y = self.get_item_ypos(task_no)
565 else:
566 y = self.origin[1]
567
568 height = 1.5 * (self.get_item_ypos(0) - self.get_item_yorigin(0))
569
570 self.canvas.add_sel_action_symbol(x, y, height, event)
571
529 def draw_bar_at_time(self, start_time, end_time, task_no, cpu_no, job_no=None, clip_side=None, selected=False): 572 def draw_bar_at_time(self, start_time, end_time, task_no, cpu_no, job_no=None, clip_side=None, selected=False):
530 if start_time > end_time: 573 if start_time > end_time:
531 raise ValueError("Litmus is not a time machine") 574 raise ValueError("Litmus is not a time machine")
@@ -699,10 +742,27 @@ class CpuGraph(Graph):
699 height = self._get_bar_height() * GraphFormat.SMALL_ARROW_FACTOR 742 height = self._get_bar_height() * GraphFormat.SMALL_ARROW_FACTOR
700 743
701 x = self.get_time_xpos(time) 744 x = self.get_time_xpos(time)
702 y = self.origin[1] - height 745 y = self.get_item_ypos(task_no)
703 746
704 self.canvas.add_sel_deadline_arrow_small(x, y, height, event) 747 self.canvas.add_sel_deadline_arrow_small(x, y, height, event)
705 748
749 def draw_action_symbol_at_time(self, time, task_no, cpu_no, action,
750 job_no=None, selected=False):
751 x = self.get_time_xpos(time)
752 y = self.get_item_ypos(cpu_no)
753
754 height = 1.5 * (y - self.get_item_yorigin(cpu_no))
755
756 self.canvas.draw_action_symbol(task_no, action, x, y, height, selected)
757
758 def add_sel_action_symbol_at_time(self, time, task_no, cpu_no, event):
759 x = self.get_time_xpos(time)
760 y = self.get_item_ypos(cpu_no)
761
762 height = 1.5 * (y - self.get_item_yorigin(cpu_no))
763
764 self.canvas.add_sel_action_symbol(x, y, height, event)
765
706 def draw_bar_at_time(self, start_time, end_time, task_no, cpu_no, job_no=None, clip_side=None, selected=False): 766 def draw_bar_at_time(self, start_time, end_time, task_no, cpu_no, job_no=None, clip_side=None, selected=False):
707 if start_time > end_time: 767 if start_time > end_time:
708 raise ValueError("Litmus is not a time machine") 768 raise ValueError("Litmus is not a time machine")
diff --git a/unit_trace/viz/schedule.py b/unit_trace/viz/schedule.py
index 542524b..fcce10d 100644
--- a/unit_trace/viz/schedule.py
+++ b/unit_trace/viz/schedule.py
@@ -181,6 +181,7 @@ class Schedule(object):
181 self.time_slot_array = None 181 self.time_slot_array = None
182 self.cur_task_no = 0 182 self.cur_task_no = 0
183 self.num_cpus = num_cpus 183 self.num_cpus = num_cpus
184 self.jobless = []
184 for task in task_list: 185 for task in task_list:
185 self.add_task(task) 186 self.add_task(task)
186 187
@@ -264,6 +265,9 @@ class Schedule(object):
264 task.task_no = self.cur_task_no 265 task.task_no = self.cur_task_no
265 self.cur_task_no += 1 266 self.cur_task_no += 1
266 267
268 def add_jobless(self, event):
269 self.jobless.append(event)
270
267 def sort_task_nos_numeric(self): 271 def sort_task_nos_numeric(self):
268 # sort task numbers by the numeric value of the task names. 272 # sort task numbers by the numeric value of the task names.
269 nums = [] 273 nums = []
@@ -275,6 +279,9 @@ class Schedule(object):
275 for no, task in enumerate(nums): 279 for no, task in enumerate(nums):
276 self.tasks[task[1]].task_no = no 280 self.tasks[task[1]].task_no = no
277 281
282 def get_jobless(self):
283 return self.jobless
284
278 def get_tasks(self): 285 def get_tasks(self):
279 return self.tasks 286 return self.tasks
280 287
@@ -418,12 +425,12 @@ class DummyEvent(object):
418 event added by the application to speed things up or keep track of 425 event added by the application to speed things up or keep track of
419 something. Such an event won't be added to the schedule tree, but 426 something. Such an event won't be added to the schedule tree, but
420 might appear in the time slot array.""" 427 might appear in the time slot array."""
421
422 def __init__(self, time, cpu): 428 def __init__(self, time, cpu):
423 self.time = time 429 self.time = time
424 self.cpu = cpu 430 self.cpu = cpu
425 self.job = None 431 self.job = None
426 self.layer = None 432 self.layer = None
433 self.saved_schedule = None
427 434
428 def get_time(self): 435 def get_time(self):
429 return self.time 436 return self.time
@@ -431,11 +438,24 @@ class DummyEvent(object):
431 def get_cpu(self): 438 def get_cpu(self):
432 return self.cpu 439 return self.cpu
433 440
441 # Refactor, shouldn't depend on job
434 def get_schedule(self): 442 def get_schedule(self):
435 return self.get_task().get_schedule() 443 if self.saved_schedule is not None:
444 return self.saved_schedule
445 elif self.get_task() is not None:
446 return self.get_task().get_schedule()
447 else:
448 return None
449
450 # Needed for events not assigned to specific tasks
451 def set_schedule(self, schedule):
452 self.saved_schedule = schedule
436 453
437 def get_task(self): 454 def get_task(self):
438 return self.get_job().get_task() 455 if self.get_job() is not None:
456 return self.get_job().get_task()
457 else:
458 return None
439 459
440 def get_job(self): 460 def get_job(self):
441 return self.job 461 return self.job
@@ -476,21 +496,33 @@ class Event(DummyEvent):
476 ' ' + str(unit) 496 ' ' + str(unit)
477 497
478 def str_long(self, unit): 498 def str_long(self, unit):
479 """Prints the event as a string, in ``long'' form.""" 499 if self.get_job() is not None:
480 return 'Event Information\n-----------------\n' + \ 500 """Prints the event as a string, in ``long'' form."""
481 'Event Type: ' + self.get_name() + \ 501 return 'Event Information\n-----------------\n' + \
482 '\nTask Name: ' + str(self.get_job().get_task().get_name()) + \ 502 'Event Type: ' + self.get_name() + \
483 '\n(Task no., Job no.): ' + str((self.get_job().get_task().get_task_no(), \ 503 '\nTask Name: ' + str(self.get_job().get_task().get_name()) + \
484 self.get_job().get_job_no())) + \ 504 '\n(Task no., Job no.): ' + str((self.get_job().get_task().get_task_no(), \
485 '\nCPU: ' + str(self.get_cpu()) + \ 505 self.get_job().get_job_no())) + \
486 '\nTime: ' + _format_time(self.get_time(), unit) + \ 506 '\nCPU: ' + str(self.get_cpu()) + \
487 '\n\n' + self.get_job().str_long(unit) 507 '\nTime: ' + _format_time(self.get_time(), unit) + \
508 '\n\n' + self.get_job().str_long(unit)
509 else:
510 """Prints the event as a string, in ``long'' form."""
511 return 'Event Information\n-----------------\n' + \
512 'Event Type: ' + self.get_name() + \
513 '\nTask Name: None' + \
514 '\nCPU: ' + str(self.get_cpu()) + \
515 '\nTime: ' + _format_time(self.get_time(), unit)
488 516
489 def _common_str(self): 517 def _common_str(self):
490 job = self.get_job() 518 if self.get_job() is not None:
491 task = job.get_task() 519 job = self.get_job()
492 return ' for task ' + str(task.get_name()) + ': (TASK, JOB)=' + str((task.get_task_no(), \ 520 task = job.get_task()
493 job.get_job_no())) + ', CPU=' + str(self.get_cpu()) 521 return ' for task ' + str(task.get_name()) + ': (TASK, JOB)=' + \
522 str((task.get_task_no(), job.get_job_no())) + \
523 ', CPU=' + str(self.get_cpu())
524 else:
525 return ', Cpu=' + str(self.get_cpu())
494 526
495 def is_erroneous(self): 527 def is_erroneous(self):
496 """An erroneous event is where something with the event is not quite right, 528 """An erroneous event is where something with the event is not quite right,
@@ -507,16 +539,20 @@ class Event(DummyEvent):
507 time in the scan, and ``switches'' gives the last time a certain switch 539 time in the scan, and ``switches'' gives the last time a certain switch
508 (e.g. SwitchToEvent, InversionStartEvent) occurred""" 540 (e.g. SwitchToEvent, InversionStartEvent) occurred"""
509 time = self.get_time() 541 time = self.get_time()
542
510 sched = self.get_schedule() 543 sched = self.get_schedule()
511 if sched.start is None or time < sched.start: 544
512 sched.start = time 545 if sched is not None:
513 if sched.end is None or time > sched.end: 546 if sched.start is None or time < sched.start:
514 sched.end = time 547 sched.start = time
515 548 if sched.end is None or time > sched.end:
516 if item_nos is None: 549 sched.end = time
517 item_nos = { TimeSlotArray.TASK_LIST : self.get_task().get_task_no(), 550
518 TimeSlotArray.CPU_LIST : self.get_cpu() } 551 if item_nos is None:
519 sched.get_time_slot_array().add_event_to_time_slot(self, item_nos) 552 item_nos = { TimeSlotArray.TASK_LIST : self.get_task().get_task_no(),
553 TimeSlotArray.CPU_LIST : self.get_cpu() }
554 sched.get_time_slot_array().add_event_to_time_slot(self, item_nos)
555
520 self.fill_span_event_from_end() 556 self.fill_span_event_from_end()
521 557
522 def fill_span_event_from_start(self): 558 def fill_span_event_from_start(self):
@@ -843,9 +879,42 @@ class DeadlineEvent(Event):
843 graph.add_sel_deadline_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(), 879 graph.add_sel_deadline_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
844 self) 880 self)
845 else: 881 else:
846 graph.draw_deadline_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(), 882 graph.draw_deadline_arrow_at_time(self.get_time(),
847 self.get_job().get_job_no(), self.is_selected()) 883 self.get_job().get_task().get_task_no(),
884 self.get_job().get_job_no(), self.is_selected())
848 885
886class ActionEvent(Event):
887 def __init__(self, time, cpu, action):
888 super(ActionEvent, self).__init__(time, cpu)
889 self.layer = Canvas.TOP_LAYER
890 self.action = int(action)
891
892 def get_name(self):
893 return 'Action'
894
895 def scan(self, cur_cpu, switches):
896 item_nos = { TimeSlotArray.TASK_LIST : self.get_task().get_task_no(),
897 TimeSlotArray.CPU_LIST : TimeSlotArray.POST_ITEM_NO }
898 super(ActionEvent, self).scan(cur_cpu, switches, item_nos)
899
900 def render(self, graph, layer, prev_events, selectable=False):
901 prev_events[self] = None
902 if layer == Canvas.TOP_LAYER:
903
904 # TODO: need a more official way of doing this
905 task_no = -1
906 job_no = -1
907 if self.get_job() is not None:
908 task_no = self.get_job().get_task().get_task_no()
909 job_no = self.get_job().get_job_no()
910
911 if selectable:
912 graph.add_sel_action_symbol_at_time(self.get_time(), task_no,
913 self.get_cpu(), self)
914 else:
915 graph.draw_action_symbol_at_time(self.get_time(), task_no,
916 self.get_cpu(), self.action,
917 job_no, self.is_selected())
849 918
850class InversionStartEvent(StartSpanEvent): 919class InversionStartEvent(StartSpanEvent):
851 def __init__(self, time): 920 def __init__(self, time):
@@ -1041,7 +1110,7 @@ EVENT_LIST = {SuspendEvent : None, ResumeEvent : None, CompleteEvent : None,
1041 SwitchAwayEvent : None, SwitchToEvent : None, ReleaseEvent : None, 1110 SwitchAwayEvent : None, SwitchToEvent : None, ReleaseEvent : None,
1042 DeadlineEvent : None, IsRunningDummy : None, 1111 DeadlineEvent : None, IsRunningDummy : None,
1043 InversionStartEvent : None, InversionEndEvent : None, 1112 InversionStartEvent : None, InversionEndEvent : None,
1044 InversionDummy : None, TaskDummy : None, CPUDummy : None} 1113 InversionDummy : None, TaskDummy : None, CPUDummy : None, ActionEvent: None}
1045 1114
1046SPAN_START_EVENTS = { SwitchToEvent : IsRunningDummy, InversionStartEvent : InversionDummy } 1115SPAN_START_EVENTS = { SwitchToEvent : IsRunningDummy, InversionStartEvent : InversionDummy }
1047SPAN_END_EVENTS = { SwitchAwayEvent : IsRunningDummy, InversionEndEvent : InversionDummy} 1116SPAN_END_EVENTS = { SwitchAwayEvent : IsRunningDummy, InversionEndEvent : InversionDummy}