summaryrefslogtreecommitdiffstats
path: root/viz/schedule.py
diff options
context:
space:
mode:
authorGary Bressler <garybressler@nc.rr.com>2010-03-09 13:33:54 -0500
committerGary Bressler <garybressler@nc.rr.com>2010-03-09 13:33:54 -0500
commit883f9dfe38ab081025220aafbf47f722b540d003 (patch)
tree6ab638add46bfd8e622301c2d704b3d6dfdba9b5 /viz/schedule.py
parentb97f0447b302746ab054aba0fd7417224ba73d86 (diff)
Preliminary, fairly workable version of unit_trace, including the visualizer.
Diffstat (limited to 'viz/schedule.py')
-rw-r--r--viz/schedule.py210
1 files changed, 137 insertions, 73 deletions
diff --git a/viz/schedule.py b/viz/schedule.py
index f842c8d..e525b17 100644
--- a/viz/schedule.py
+++ b/viz/schedule.py
@@ -8,6 +8,10 @@ graphic."""
8from draw import * 8from draw import *
9import util 9import util
10 10
11import copy
12
13EVENT_LIST = None
14
11class TimeSlotArray(object): 15class TimeSlotArray(object):
12 """Represents another way of organizing the events. This structure organizes events by 16 """Represents another way of organizing the events. This structure organizes events by
13 the (approximate) time at which they occur. Events that occur at approximately the same 17 the (approximate) time at which they occur. Events that occur at approximately the same
@@ -17,14 +21,28 @@ class TimeSlotArray(object):
17 TASK_LIST = 0 21 TASK_LIST = 0
18 CPU_LIST = 1 22 CPU_LIST = 1
19 23
20 def __init__(self, start, end, time_per_maj, num_tasks, num_cpus): 24 def __init__(self, start=None, end=None, time_per_maj=1, num_tasks=0, num_cpus=0):
25 if start is None or end is None:
26 self.array = None
27 return
28
21 self.start = start 29 self.start = start
22 self.end = end 30 self.end = end
23 self.time_per_maj = time_per_maj 31 self.time_per_maj = time_per_maj
24 self.list_sizes = { TimeSlotArray.TASK_LIST : num_tasks, TimeSlotArray.CPU_LIST : num_cpus } 32 self.list_sizes = { TimeSlotArray.TASK_LIST : num_tasks, TimeSlotArray.CPU_LIST : num_cpus }
25 self.array = [{TimeSlotArray.TASK_LIST : [{} for i in range(0, num_tasks)], \ 33 self.array = {}
26 TimeSlotArray.CPU_LIST : [{} for i in range (0, num_cpus)]} \ 34
27 for i in range(0, (end - start) // self.time_per_maj + 1)] 35 for type in self.list_sizes:
36 num = self.list_sizes[type]
37 self.array[type] = []
38 for i in range(0, int((end - start) // self.time_per_maj + 1)):
39 # for each slot in the array, we need a list of all events under this type
40 # (for example, a list of all events that occur in this time slot, indexed
41 # by task).
42 self.array[type].append([])
43 for j in range(0, num):
44 self.array[type][i].append(dict(zip(EVENT_LIST, \
45 [[] for j in range(0, len(EVENT_LIST))])))
28 46
29 def get_time_slot(self, time): 47 def get_time_slot(self, time):
30 return int((time - self.start) // self.time_per_maj) 48 return int((time - self.start) // self.time_per_maj)
@@ -34,29 +52,32 @@ class TimeSlotArray(object):
34 cpu = event.get_cpu() 52 cpu = event.get_cpu()
35 time_slot = self.get_time_slot(event.get_time()) 53 time_slot = self.get_time_slot(event.get_time())
36 54
37 self.array[time_slot][TimeSlotArray.TASK_LIST][task_no][event.__class__] = event 55 self.array[TimeSlotArray.TASK_LIST][time_slot][task_no][event.__class__].append(event)
38 self.array[time_slot][TimeSlotArray.CPU_LIST][cpu][event.__class__] = event 56 self.array[TimeSlotArray.CPU_LIST][time_slot][cpu][event.__class__].append(event)
39 57
40 span_events = { SwitchAwayEvent : IsRunningDummy, InversionEndEvent : InversionDummy} 58 span_events = { SwitchAwayEvent : IsRunningDummy, InversionEndEvent : InversionDummy}
41 59
42 for span_event in span_events: 60 for span_event in span_events:
43 if isinstance(event, span_event) and not event.is_erroneous(): 61 if isinstance(event, span_event) and event.corresp_start_event is not None:
44 start_slot = self.get_time_slot(event.corresp_start_event.get_time()) 62 start_slot = self.get_time_slot(event.corresp_start_event.get_time())
45 end_slot = self.get_time_slot(event.get_time()) 63 end_slot = time_slot
46 for slot in range(start_slot + 1, end_slot): 64 for slot in range(start_slot + 1, end_slot):
47 dummy = span_events[span_event](task_no, cpu) 65 dummy = span_events[span_event](task_no, cpu)
48 dummy.corresp_start_event = event.corresp_start_event 66 dummy.corresp_start_event = event.corresp_start_event
49 self.array[slot][TimeSlotArray.TASK_LIST][task_no][dummy.__class__] = dummy 67 self.array[TimeSlotArray.TASK_LIST][slot][task_no][dummy.__class__].append(dummy)
50 self.array[slot][TimeSlotArray.CPU_LIST][cpu][dummy.__class__] = dummy 68 self.array[TimeSlotArray.CPU_LIST][slot][cpu][dummy.__class__].append(dummy)
51 69
52 def iter_over_period(self, start, end, start_no, end_no, list_type, event_types): 70 def iter_over_period(self, start, end, start_no, end_no, list_type, event_types):
71 if self.array is None:
72 return # empty schedule
73
53 if start > end: 74 if start > end:
54 raise ValueError('Litmus is not a time machine') 75 raise ValueError('Litmus is not a time machine')
55 if start_no > end_no: 76 if start_no > end_no:
56 raise ValueError('start no should be less than end no') 77 raise ValueError('start no should be less than end no')
57 78
58 start_slot = max(0, self.get_time_slot(start)) 79 start_slot = max(0, self.get_time_slot(start))
59 end_slot = min(len(self.array), self.get_time_slot(end) + 2) 80 end_slot = min(len(self.array[list_type]), self.get_time_slot(end) + 2)
60 81
61 start_no = max(0, start_no) 82 start_no = max(0, start_no)
62 end_no = min(self.list_sizes[list_type] - 1, end_no) 83 end_no = min(self.list_sizes[list_type] - 1, end_no)
@@ -64,8 +85,8 @@ class TimeSlotArray(object):
64 for slot in range(start_slot, end_slot): 85 for slot in range(start_slot, end_slot):
65 for no in range(start_no, end_no + 1): 86 for no in range(start_no, end_no + 1):
66 for type in event_types: 87 for type in event_types:
67 if type in self.array[slot][list_type][no]: 88 for event in self.array[list_type][slot][no][type]:
68 yield self.array[slot][list_type][no][type] 89 yield event
69 90
70class Schedule(object): 91class Schedule(object):
71 """The total schedule (task system), consisting of a certain number of 92 """The total schedule (task system), consisting of a certain number of
@@ -75,36 +96,47 @@ class Schedule(object):
75 self.name = name 96 self.name = name
76 self.tasks = {} 97 self.tasks = {}
77 self.task_list = [] 98 self.task_list = []
99 self.selected = {}
78 self.time_slot_array = None 100 self.time_slot_array = None
79 self.cur_task_no = 0 101 self.cur_task_no = 0
80 self.num_cpus = num_cpus 102 self.num_cpus = num_cpus
81 for task in task_list: 103 for task in task_list:
82 self.add_task(task) 104 self.add_task(task)
83 105
84 def set_time_params(self, time_per_maj=None): 106 def get_selected(self):
85 if self.get_task_list() is None: 107 return self.selected
86 return (0, 0)
87 108
109 def set_selected(self, new_selected):
110 for event in self.selected:
111 event.selected = False
112 for event in new_selected:
113 event.selected = True
114 self.selected = new_selected
115
116 def get_selected(self):
117 return copy.copy(self.selected)
118
119 def set_time_params(self, time_per_maj=None, max_num_slots=None):
88 def find_extreme_time_sched(sched, cmp): 120 def find_extreme_time_sched(sched, cmp):
89 def find_extreme_time_task(task, cmp): 121 def find_extreme_time_task(task, cmp):
90 def find_extreme_time_job(job, cmp): 122 def find_extreme_time_job(job, cmp):
91 extreme_time = None 123 extreme_time = None
92 for time in job.get_events(): 124 for time in job.get_events():
93 if extreme_time is None or cmp(time, extreme_time) < 0: 125 if (extreme_time is None) or cmp(time, extreme_time) < 0:
94 extreme_time = time 126 extreme_time = time
95 return extreme_time 127 return extreme_time
96 128
97 extreme_time = None 129 extreme_time = None
98 for job_no in task.get_jobs(): 130 for job_no in task.get_jobs():
99 time = find_extreme_time_job(task.get_jobs()[job_no], cmp) 131 time = find_extreme_time_job(task.get_jobs()[job_no], cmp)
100 if time is not None and (extreme_time is None or cmp(time, extreme_time) < 0): 132 if (time is not None) and ((extreme_time is None) or cmp(time, extreme_time) < 0):
101 extreme_time = time 133 extreme_time = time
102 return extreme_time 134 return extreme_time
103 135
104 extreme_time = None 136 extreme_time = None
105 for task in sched.get_task_list(): 137 for task in sched.get_task_list():
106 time = find_extreme_time_task(task, cmp) 138 time = find_extreme_time_task(task, cmp)
107 if time is not None and (extreme_time is None or cmp(time, extreme_time) < 0): 139 if (time is not None) and ((extreme_time is None) or cmp(time, extreme_time) < 0):
108 extreme_time = time 140 extreme_time = time
109 141
110 return extreme_time 142 return extreme_time
@@ -129,20 +161,32 @@ class Schedule(object):
129 161
130 self.start = find_extreme_time_sched(self, earliest_cmp) 162 self.start = find_extreme_time_sched(self, earliest_cmp)
131 self.end = find_extreme_time_sched(self, latest_cmp) 163 self.end = find_extreme_time_sched(self, latest_cmp)
132 self.time_per_maj = time_per_maj 164 if self.start is None or self.end is None:
165 self.time_slot_array = TimeSlotArray()
166 return
167
168 min_time_per_maj = (self.end - self.start) * 1.0 / max_num_slots
169 if max_num_slots is not None and time_per_maj is not None:
170 if time_per_maj < min_time_per_maj:
171 self.time_per_maj = min_time_per_maj
172 else:
173 self.time_per_maj = time_per_maj
174 else:
175 self.time_per_maj = time_per_maj
133 self.time_slot_array = None 176 self.time_slot_array = None
134 if self.time_per_maj is not None: 177 if self.time_per_maj is not None:
135 self.time_slot_array = TimeSlotArray(self.start, self.end, time_per_maj, \ 178 self.time_slot_array = TimeSlotArray(self.start, self.end, self.time_per_maj, \
136 len(self.task_list), self.num_cpus) 179 len(self.task_list), self.num_cpus)
137 180
181
138 def get_time_slot_array(self): 182 def get_time_slot_array(self):
139 return self.time_slot_array 183 return self.time_slot_array
140 184
141 def get_time_bounds(self): 185 def get_time_bounds(self):
142 return (self.start, self.end) 186 return (self.start, self.end)
143 187
144 def scan(self, time_per_maj): 188 def scan(self, time_per_maj, max_num_slots):
145 self.set_time_params(time_per_maj) 189 self.set_time_params(time_per_maj, max_num_slots)
146 190
147 # we scan the graph task by task, and job by job 191 # we scan the graph task by task, and job by job
148 switches = {} 192 switches = {}
@@ -261,9 +305,13 @@ class DummyEvent(object):
261 def get_layer(self): 305 def get_layer(self):
262 return self.layer 306 return self.layer
263 307
264 def render(self, graph, layer, prev_events): 308 def render(self, graph, layer, prev_events, selectable=False):
265 """Method that the visualizer calls to tell the event to render itself 309 """Method that the visualizer calls to tell the event to render itself
266 Obviously only implemented by subclasses (actual event types)""" 310 Obviously only implemented by subclasses (actual event types)
311
312 ``Rendering'' can mean either actually drawing the event or just
313 adding it as a selectable region. This is controlled by the
314 ``selectable'' parameter"""
267 raise NotImplementdError 315 raise NotImplementdError
268 316
269class Event(DummyEvent): 317class Event(DummyEvent):
@@ -295,10 +343,6 @@ class Event(DummyEvent):
295 def is_selected(self): 343 def is_selected(self):
296 """Returns whether the event has been selected by the user. (needed for rendering)""" 344 """Returns whether the event has been selected by the user. (needed for rendering)"""
297 return self.selected 345 return self.selected
298
299 def set_selected(self, sel):
300 """Sets the event's state to selected."""
301 self.selected = sel
302 346
303 def scan(self, cur_cpu, switches): 347 def scan(self, cur_cpu, switches):
304 """Part of the procedure that walks through all the events and sets 348 """Part of the procedure that walks through all the events and sets
@@ -328,13 +372,16 @@ class SuspendEvent(Event):
328 print "suspending on a CPU different from the CPU we are on!" 372 print "suspending on a CPU different from the CPU we are on!"
329 super(SuspendEvent, self).scan(cur_cpu, switches) 373 super(SuspendEvent, self).scan(cur_cpu, switches)
330 374
331 def render(self, graph, layer, prev_events): 375 def render(self, graph, layer, prev_events, selectable=False):
332 if layer == self.layer: 376 if layer == self.layer:
333 prev_events[self] = None 377 prev_events[self] = None
334 graph.draw_suspend_triangle_at_time(self.get_time(), self.get_job().get_task().get_task_no(), 378 if selectable:
335 self.get_cpu(), self.is_selected()) 379 graph.add_sel_suspend_triangle_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
336 graph.add_sel_suspend_triangle_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
337 self.get_cpu(), self) 380 self.get_cpu(), self)
381 else:
382 graph.draw_suspend_triangle_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
383 self.get_cpu(), self.is_selected())
384
338 385
339class ResumeEvent(Event): 386class ResumeEvent(Event):
340 def __init__(self, time, cpu): 387 def __init__(self, time, cpu):
@@ -350,13 +397,16 @@ class ResumeEvent(Event):
350 print "Resuming when currently scheduled on a CPU, but on a different CPU from the current CPU!" 397 print "Resuming when currently scheduled on a CPU, but on a different CPU from the current CPU!"
351 super(ResumeEvent, self).scan(cur_cpu, switches) 398 super(ResumeEvent, self).scan(cur_cpu, switches)
352 399
353 def render(self, graph, layer, prev_events): 400 def render(self, graph, layer, prev_events, selectable=False):
354 if layer == self.layer: 401 if layer == self.layer:
355 prev_events[self] = None 402 prev_events[self] = None
356 graph.draw_resume_triangle_at_time(self.get_time(), self.get_job().get_task().get_task_no(), 403 if selectable:
357 self.get_cpu(), self.is_selected()) 404 graph.add_sel_resume_triangle_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
358 graph.add_sel_resume_triangle_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
359 self.get_cpu(), self) 405 self.get_cpu(), self)
406 else:
407 graph.draw_resume_triangle_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
408 self.get_cpu(), self.is_selected())
409
360 410
361class CompleteEvent(Event): 411class CompleteEvent(Event):
362 def __init__(self, time, cpu): 412 def __init__(self, time, cpu):
@@ -369,14 +419,15 @@ class CompleteEvent(Event):
369 def scan(self, cur_cpu, switches): 419 def scan(self, cur_cpu, switches):
370 super(CompleteEvent, self).scan(cur_cpu, switches) 420 super(CompleteEvent, self).scan(cur_cpu, switches)
371 421
372 def render(self, graph, layer, prev_events): 422 def render(self, graph, layer, prev_events, selectable=False):
373 if layer == Canvas.TOP_LAYER: 423 if layer == Canvas.TOP_LAYER:
374 prev_events[self] = None 424 prev_events[self] = None
375 graph.draw_completion_marker_at_time(self.get_time(), self.get_job().get_task().get_task_no(), 425 if selectable:
376 self.get_cpu(), self.is_selected()) 426 graph.add_sel_completion_marker_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
377 graph.add_sel_completion_marker_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
378 self.get_cpu(), self) 427 self.get_cpu(), self)
379 428 else:
429 graph.draw_completion_marker_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
430 self.get_cpu(), self.is_selected())
380 431
381class SwitchAwayEvent(Event): 432class SwitchAwayEvent(Event):
382 def __init__(self, time, cpu): 433 def __init__(self, time, cpu):
@@ -412,10 +463,10 @@ class SwitchAwayEvent(Event):
412 463
413 super(SwitchAwayEvent, self).scan(cur_cpu, switches) 464 super(SwitchAwayEvent, self).scan(cur_cpu, switches)
414 465
415 def render(self, graph, layer, prev_events): 466 def render(self, graph, layer, prev_events, selectable=False):
416 if self.corresp_start_event is None or self.corresp_start_event in prev_events: 467 if self.corresp_start_event is None or self.corresp_start_event in prev_events:
417 return # erroneous switch away or already rendered 468 return # erroneous switch away or already rendered
418 self.corresp_start_event.render(graph, layer, prev_events) 469 self.corresp_start_event.render(graph, layer, prev_events, selectable)
419 470
420class SwitchToEvent(Event): 471class SwitchToEvent(Event):
421 def __init__(self, time, cpu): 472 def __init__(self, time, cpu):
@@ -442,17 +493,19 @@ class SwitchToEvent(Event):
442 493
443 super(SwitchToEvent, self).scan(cur_cpu, switches) 494 super(SwitchToEvent, self).scan(cur_cpu, switches)
444 495
445 def render(self, graph, layer, prev_events): 496 def render(self, graph, layer, prev_events, selectable=False):
446 if self.is_erroneous(): 497 if self.corresp_end_event is None:
447 return # erroneous switch to 498 return # fatally erroneous switch to
448 if layer == Canvas.BOTTOM_LAYER: 499 if layer == Canvas.BOTTOM_LAYER:
449 prev_events[self] = None 500 prev_events[self] = None
450 cpu = self.get_cpu() 501 cpu = self.get_cpu()
451 task_no = self.get_job().get_task().get_task_no() 502 task_no = self.get_job().get_task().get_task_no()
452 graph.draw_bar_at_time(self.get_time(), self.corresp_end_event.get_time(), 503 if selectable:
453 task_no, cpu, self.get_job().get_job_no(), self.is_selected()) 504 graph.add_sel_bar_at_time(self.get_time(), self.corresp_end_event.get_time(),
454 graph.add_sel_bar_at_time(self.get_time(), self.corresp_end_event.get_time(),
455 task_no, cpu, self) 505 task_no, cpu, self)
506 else:
507 graph.draw_bar_at_time(self.get_time(), self.corresp_end_event.get_time(),
508 task_no, cpu, self.get_job().get_job_no(), self.is_selected())
456 509
457class ReleaseEvent(Event): 510class ReleaseEvent(Event):
458 def __init__(self, time, cpu): 511 def __init__(self, time, cpu):
@@ -465,13 +518,16 @@ class ReleaseEvent(Event):
465 def scan(self, cur_cpu, switches): 518 def scan(self, cur_cpu, switches):
466 super(ReleaseEvent, self).scan(cur_cpu, switches) 519 super(ReleaseEvent, self).scan(cur_cpu, switches)
467 520
468 def render(self, graph, layer, prev_events): 521 def render(self, graph, layer, prev_events, selectable=False):
469 prev_events[self] = None 522 prev_events[self] = None
470 if layer == Canvas.TOP_LAYER: 523 if layer == Canvas.TOP_LAYER:
471 graph.draw_release_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(), 524 if selectable:
525 graph.add_sel_release_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
526 self)
527 else:
528 graph.draw_release_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
472 self.get_job().get_job_no(), self.is_selected()) 529 self.get_job().get_job_no(), self.is_selected())
473 graph.add_sel_release_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(), 530
474 self)
475 531
476class DeadlineEvent(Event): 532class DeadlineEvent(Event):
477 def __init__(self, time, cpu): 533 def __init__(self, time, cpu):
@@ -484,13 +540,16 @@ class DeadlineEvent(Event):
484 def scan(self, cur_cpu, switches): 540 def scan(self, cur_cpu, switches):
485 super(DeadlineEvent, self).scan(cur_cpu, switches) 541 super(DeadlineEvent, self).scan(cur_cpu, switches)
486 542
487 def render(self, graph, layer, prev_events): 543 def render(self, graph, layer, prev_events, selectable=False):
488 prev_events[self] = None 544 prev_events[self] = None
489 if layer == Canvas.TOP_LAYER: 545 if layer == Canvas.TOP_LAYER:
490 graph.draw_deadline_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(), 546 if selectable:
491 self.get_job().get_job_no(), self.is_selected()) 547 graph.add_sel_deadline_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
492 graph.add_sel_deadline_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
493 self) 548 self)
549 else:
550 graph.draw_deadline_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
551 self.get_job().get_job_no(), self.is_selected())
552
494 553
495class InversionStartEvent(ErrorEvent): 554class InversionStartEvent(ErrorEvent):
496 def __init__(self, time): 555 def __init__(self, time):
@@ -512,15 +571,18 @@ class InversionStartEvent(ErrorEvent):
512 # the corresp_end_event should already be set 571 # the corresp_end_event should already be set
513 super(InversionStartEvent, self).scan(cur_cpu, switches) 572 super(InversionStartEvent, self).scan(cur_cpu, switches)
514 573
515 def render(self, graph, layer, prev_events): 574 def render(self, graph, layer, prev_events, selectable=False):
516 if layer == Canvas.BOTTOM_LAYER: 575 if layer == Canvas.BOTTOM_LAYER:
517 prev_events[self] = None 576 prev_events[self] = None
518 cpu = self.get_cpu() 577 cpu = self.get_cpu()
519 task_no = self.get_job().get_task().get_task_no() 578 task_no = self.get_job().get_task().get_task_no()
520 graph.draw_mini_bar_at_time(self.get_time(), self.corresp_end_event.get_time(), 579 if selectable:
521 task_no, cpu, self.get_job().get_job_no(), self.is_selected()) 580 graph.add_sel_mini_bar_at_time(self.get_time(), self.corresp_end_event.get_time(),
522 graph.add_sel_mini_bar_at_time(self.get_time(), self.corresp_end_event.get_time(),
523 task_no, cpu, self) 581 task_no, cpu, self)
582 else:
583 graph.draw_mini_bar_at_time(self.get_time(), self.corresp_end_event.get_time(),
584 task_no, cpu, self.get_job().get_job_no(), self.is_selected())
585
524 586
525class InversionEndEvent(ErrorEvent): 587class InversionEndEvent(ErrorEvent):
526 def __init__(self, time): 588 def __init__(self, time):
@@ -549,23 +611,25 @@ class InversionEndEvent(ErrorEvent):
549 611
550 super(InversionEndEvent, self).scan(cur_cpu, switches) 612 super(InversionEndEvent, self).scan(cur_cpu, switches)
551 613
552 def render(self, graph, layer, prev_events): 614 def render(self, graph, layer, prev_events, selectable=False):
553 if self.corresp_start_event is None or self.corresp_start_event in prev_events: 615 if self.corresp_start_event is None or self.corresp_start_event in prev_events:
554 return # erroneous inversion end or already rendered 616 return # erroneous inversion end or already rendered
555 self.corresp_start_event.render(graph, layer, prev_events) 617 self.corresp_start_event.render(graph, layer, prev_events, selectable)
556 618
557class InversionDummy(DummyEvent): 619class InversionDummy(DummyEvent):
558 def render(self, graph, layer, prev_events): 620 def render(self, graph, layer, prev_events, selectable=False):
559 if self.corresp_start_event in prev_events: 621 if self.corresp_start_event in prev_events:
560 return # we have already been rendered 622 return # we have already been rendered
561 self.corresp_start_event.render(graph, layer, prev_events) 623 self.corresp_start_event.render(graph, layer, prev_events, selectable)
562 624
563class IsRunningDummy(DummyEvent): 625class IsRunningDummy(DummyEvent):
564 def render(self, graph, layer, prev_events): 626 def render(self, graph, layer, prev_events, selectable=False):
565 if self.corresp_start_event in prev_events: 627 if self.corresp_start_event in prev_events:
566 return # we have already been rendered 628 return # we have already been rendered
567 self.corresp_start_event.render(graph, layer, prev_events) 629 self.corresp_start_event.render(graph, layer, prev_events, selectable)
568 630
569EVENT_LIST = {SuspendEvent : None, ResumeEvent : None, CompleteEvent : None, SwitchAwayEvent : None, 631EVENT_LIST = {SuspendEvent : None, ResumeEvent : None, CompleteEvent : None,
570 SwitchToEvent : None, ReleaseEvent : None, DeadlineEvent : None, IsRunningDummy : None, 632 SwitchAwayEvent : None, SwitchToEvent : None, ReleaseEvent : None,
571 InversionStartEvent : None, InversionEndEvent : None, InversionDummy : None} 633 DeadlineEvent : None, IsRunningDummy : None,
634 InversionStartEvent : None, InversionEndEvent : None,
635 InversionDummy : None}