diff options
author | Gary Bressler <garybressler@nc.rr.com> | 2010-03-20 12:47:31 -0400 |
---|---|---|
committer | Gary Bressler <garybressler@nc.rr.com> | 2010-03-20 12:47:31 -0400 |
commit | c712c699126e16003ee69e2d82e51007ab2f58ea (patch) | |
tree | 724913e93a6c2fb0dbe689a8664b552830399329 /unit_trace/viz/schedule.py | |
parent | ee7ae82ae6df1378203957b7fa77066153e13c36 (diff) |
Significant performance improvements in the graphical rendering, as
well as the eradication of several bugs
Also, visualizer is now integrated into the main unit-trace command line tool
(use -v option)
Note that files are now taken in from the command line, no longer from the
GUI
Diffstat (limited to 'unit_trace/viz/schedule.py')
-rw-r--r-- | unit_trace/viz/schedule.py | 236 |
1 files changed, 148 insertions, 88 deletions
diff --git a/unit_trace/viz/schedule.py b/unit_trace/viz/schedule.py index 4277f1a..5efee7d 100644 --- a/unit_trace/viz/schedule.py +++ b/unit_trace/viz/schedule.py | |||
@@ -11,6 +11,7 @@ import util | |||
11 | import copy | 11 | import copy |
12 | 12 | ||
13 | EVENT_LIST = None | 13 | EVENT_LIST = None |
14 | SPAN_EVENTS = None | ||
14 | 15 | ||
15 | class TimeSlotArray(object): | 16 | class TimeSlotArray(object): |
16 | """Represents another way of organizing the events. This structure organizes events by | 17 | """Represents another way of organizing the events. This structure organizes events by |
@@ -55,20 +56,47 @@ class TimeSlotArray(object): | |||
55 | 56 | ||
56 | self._put_event_in_slot(TimeSlotArray.TASK_LIST, task_no, event.__class__, time_slot, event) | 57 | self._put_event_in_slot(TimeSlotArray.TASK_LIST, task_no, event.__class__, time_slot, event) |
57 | self._put_event_in_slot(TimeSlotArray.CPU_LIST, cpu, event.__class__, time_slot, event) | 58 | self._put_event_in_slot(TimeSlotArray.CPU_LIST, cpu, event.__class__, time_slot, event) |
59 | |||
60 | if event.__class__ in SPAN_END_EVENTS: | ||
61 | self.fill_span_event_from_end(event) | ||
62 | |||
63 | def fill_span_event_from_end(self, event): | ||
64 | start_slot = None | ||
65 | if event.corresp_start_event is None: | ||
66 | start_slot = self.get_time_slot(event.get_job().get_task().get_schedule().start) - 1 | ||
67 | else: | ||
68 | start_slot = self.get_time_slot(event.corresp_start_event.get_time()) | ||
69 | end_slot = self.get_time_slot(event.get_time()) | ||
70 | |||
71 | for slot in range(start_slot + 1, end_slot): | ||
72 | task_no = event.get_job().get_task().get_task_no() | ||
73 | cpu = event.get_cpu() | ||
58 | 74 | ||
59 | span_events = { SwitchAwayEvent : IsRunningDummy, InversionEndEvent : InversionDummy} | 75 | dummy = SPAN_END_EVENTS[event.__class__](task_no, cpu) |
60 | 76 | dummy.corresp_start_event = event.corresp_start_event | |
61 | for span_event in span_events: | 77 | dummy.corresp_end_event = event |
62 | if isinstance(event, span_event) and event.corresp_start_event is not None: | ||
63 | start_slot = self.get_time_slot(event.corresp_start_event.get_time()) | ||
64 | end_slot = time_slot | ||
65 | for slot in range(start_slot + 1, end_slot): | ||
66 | dummy = span_events[span_event](task_no, cpu) | ||
67 | dummy.corresp_start_event = event.corresp_start_event | ||
68 | dummy.corresp_end_event = event | ||
69 | 78 | ||
70 | self._put_event_in_slot(TimeSlotArray.TASK_LIST, task_no, dummy.__class__, slot, dummy) | 79 | self._put_event_in_slot(TimeSlotArray.TASK_LIST, task_no, dummy.__class__, slot, dummy) |
71 | self._put_event_in_slot(TimeSlotArray.CPU_LIST, cpu, dummy.__class__, slot, dummy) | 80 | self._put_event_in_slot(TimeSlotArray.CPU_LIST, cpu, dummy.__class__, slot, dummy) |
81 | |||
82 | def fill_span_event_from_start(self, event): | ||
83 | end_slot = None | ||
84 | if event.corresp_end_event is None: | ||
85 | end_slot = self.get_time_slot(event.get_job().get_task().get_schedule().end) + 1 | ||
86 | else: | ||
87 | end_slot = self.get_time_slot(event.corresp_end_event.get_time()) | ||
88 | start_slot = self.get_time_slot(event.get_time()) | ||
89 | |||
90 | for slot in range(start_slot + 1, end_slot): | ||
91 | task_no = event.get_job().get_task().get_task_no() | ||
92 | cpu = event.get_cpu() | ||
93 | |||
94 | dummy = SPAN_START_EVENTS[event.__class__](task_no, cpu) | ||
95 | dummy.corresp_start_event = event | ||
96 | dummy.corresp_end_event = event.corresp_end_event | ||
97 | |||
98 | self._put_event_in_slot(TimeSlotArray.TASK_LIST, task_no, dummy.__class__, slot, dummy) | ||
99 | self._put_event_in_slot(TimeSlotArray.CPU_LIST, cpu, dummy.__class__, slot, dummy) | ||
72 | 100 | ||
73 | def iter_over_period(self, start, end, start_no, end_no, list_type, event_types): | 101 | def iter_over_period(self, start, end, start_no, end_no, list_type, event_types): |
74 | if self.array is None: | 102 | if self.array is None: |
@@ -142,18 +170,28 @@ class Schedule(object): | |||
142 | self.set_time_params(time_per_maj) | 170 | self.set_time_params(time_per_maj) |
143 | 171 | ||
144 | # we scan the graph task by task, and job by job | 172 | # we scan the graph task by task, and job by job |
145 | switches = {} | ||
146 | for event in EVENT_LIST: | ||
147 | switches[event] = None | ||
148 | for task_no, task in enumerate(self.get_task_list()): | 173 | for task_no, task in enumerate(self.get_task_list()): |
174 | switches = {} | ||
175 | for event in EVENT_LIST: | ||
176 | switches[event] = None | ||
149 | cur_cpu = [Event.NO_CPU] | 177 | cur_cpu = [Event.NO_CPU] |
150 | for job_no in sorted(task.get_jobs().keys()): | 178 | for job_no in sorted(task.get_jobs().keys()): |
151 | job = task.get_jobs()[job_no] | 179 | job = task.get_jobs()[job_no] |
152 | for event_time in sorted(job.get_events().keys()): | 180 | for event_time in sorted(job.get_events().keys()): |
153 | # could have multiple events at the same time (unlikely but possible) | 181 | # could have multiple events at the same time (unlikely but possible) |
154 | for event in job.get_events()[event_time]: | 182 | for event in job.get_events()[event_time]: |
155 | #print 'task, job, event:', task.name, job.job_no, event.__class__.__name__ | 183 | print 'task, job, event:', task.name, job.job_no, event.__class__.__name__ |
156 | event.scan(cur_cpu, switches) | 184 | event.scan(cur_cpu, switches) |
185 | |||
186 | # What if one of the initial "span events" (switch to or inversion starting) never got a | ||
187 | # corresponding end event? Well, then we assume that the end event was simply outside of | ||
188 | # the range of whatever we read in. So we need to fill dummies starting from the initial | ||
189 | # event all the way to the end of the graph, so that the renderer can see the event no matter | ||
190 | # how far the user scrolls to the right. | ||
191 | for span_event in SPAN_START_EVENTS: | ||
192 | event = switches[span_event] | ||
193 | if event is not None: | ||
194 | self.time_slot_array.fill_span_event_from_start(event) | ||
157 | 195 | ||
158 | def add_task(self, task): | 196 | def add_task(self, task): |
159 | if task.name in self.tasks: | 197 | if task.name in self.tasks: |
@@ -311,7 +349,7 @@ class Event(DummyEvent): | |||
311 | sched.start = time | 349 | sched.start = time |
312 | if sched.end is None or time > sched.end: | 350 | if sched.end is None or time > sched.end: |
313 | sched.end = time | 351 | sched.end = time |
314 | 352 | ||
315 | sched.get_time_slot_array().add_event_to_time_slot(self) | 353 | sched.get_time_slot_array().add_event_to_time_slot(self) |
316 | 354 | ||
317 | class ErrorEvent(Event): | 355 | class ErrorEvent(Event): |
@@ -387,11 +425,59 @@ class CompleteEvent(Event): | |||
387 | else: | 425 | else: |
388 | graph.draw_completion_marker_at_time(self.get_time(), self.get_job().get_task().get_task_no(), | 426 | graph.draw_completion_marker_at_time(self.get_time(), self.get_job().get_task().get_task_no(), |
389 | self.get_cpu(), self.is_selected()) | 427 | self.get_cpu(), self.is_selected()) |
428 | |||
429 | class SwitchToEvent(Event): | ||
430 | def __init__(self, time, cpu): | ||
431 | super(SwitchToEvent, self).__init__(time, cpu) | ||
432 | self.layer = Canvas.BOTTOM_LAYER | ||
433 | self.corresp_end_event = None | ||
434 | |||
435 | def __str__(self): | ||
436 | if self.corresp_end_event is None: | ||
437 | return 'Switch To (w/o Switch Away)' + self._common_str() + ', TIME=' \ | ||
438 | + str(self.get_time()) | ||
439 | return 'Scheduled' + self._common_str() + ', START=' \ | ||
440 | + util.format_float(self.get_time(), Event.NUM_DEC_PLACES) \ | ||
441 | + ', END=' + util.format_float(self.corresp_end_event.get_time(), Event.NUM_DEC_PLACES) | ||
442 | |||
443 | def scan(self, cur_cpu, switches): | ||
444 | old_cur_cpu = cur_cpu[0] | ||
445 | cur_cpu[0] = self.get_cpu() | ||
446 | switches[SwitchToEvent] = self | ||
447 | self.corresp_end_event = None | ||
390 | 448 | ||
449 | if old_cur_cpu != Event.NO_CPU: | ||
450 | self.erroneous = True | ||
451 | print "currently scheduled somewhere, can't switch to a CPU" | ||
452 | |||
453 | super(SwitchToEvent, self).scan(cur_cpu, switches) | ||
454 | |||
455 | def render(self, graph, layer, prev_events, selectable=False): | ||
456 | if layer == self.layer: | ||
457 | end_time = None | ||
458 | clip = None | ||
459 | if self.corresp_end_event is None: | ||
460 | end_time = self.get_job().get_task().get_schedule().end | ||
461 | clip = AlignMode.RIGHT | ||
462 | else: | ||
463 | end_time = self.corresp_end_event.get_time() | ||
464 | |||
465 | prev_events[self] = None | ||
466 | cpu = self.get_cpu() | ||
467 | task_no = self.get_job().get_task().get_task_no() | ||
468 | if selectable: | ||
469 | graph.add_sel_bar_at_time(self.get_time(), end_time, | ||
470 | task_no, cpu, self) | ||
471 | else: | ||
472 | graph.draw_bar_at_time(self.get_time(), end_time, | ||
473 | task_no, cpu, self.get_job().get_job_no(), | ||
474 | clip, self.is_selected()) | ||
475 | |||
391 | class SwitchAwayEvent(Event): | 476 | class SwitchAwayEvent(Event): |
392 | def __init__(self, time, cpu): | 477 | def __init__(self, time, cpu): |
393 | super(SwitchAwayEvent, self).__init__(time, cpu) | 478 | super(SwitchAwayEvent, self).__init__(time, cpu) |
394 | self.layer = Canvas.BOTTOM_LAYER | 479 | self.layer = Canvas.BOTTOM_LAYER |
480 | self.corresp_start_event = None | ||
395 | 481 | ||
396 | def __str__(self): | 482 | def __str__(self): |
397 | if self.corresp_start_event is None: | 483 | if self.corresp_start_event is None: |
@@ -431,63 +517,19 @@ class SwitchAwayEvent(Event): | |||
431 | prev_events[self] = None | 517 | prev_events[self] = None |
432 | cpu = self.get_cpu() | 518 | cpu = self.get_cpu() |
433 | task_no = self.get_job().get_task().get_task_no() | 519 | task_no = self.get_job().get_task().get_task_no() |
520 | start = self.get_job().get_task().get_schedule().start | ||
434 | if selectable: | 521 | if selectable: |
435 | start = self.get_job().get_task().get_schedule().start | ||
436 | graph.add_sel_bar_at_time(start, self.get_time(), | 522 | graph.add_sel_bar_at_time(start, self.get_time(), |
437 | task_no, cpu, self) | 523 | task_no, cpu, self) |
438 | else: | 524 | else: |
439 | graph.draw_bar_at_time(start, self.get_time(), | 525 | graph.draw_bar_at_time(start, self.get_time(), |
440 | task_no, cpu, self.get_job().get_job_no(), self.is_selected()) | 526 | task_no, cpu, self.get_job().get_job_no(), |
527 | AlignMode.LEFT, self.is_selected()) | ||
441 | else: | 528 | else: |
442 | if self.corresp_start_event in prev_events: | 529 | if self.corresp_start_event in prev_events: |
443 | return # already rendered the bar | 530 | return # already rendered the bar |
444 | self.corresp_start_event.render(graph, layer, prev_events, selectable) | 531 | self.corresp_start_event.render(graph, layer, prev_events, selectable) |
445 | 532 | ||
446 | class SwitchToEvent(Event): | ||
447 | def __init__(self, time, cpu): | ||
448 | super(SwitchToEvent, self).__init__(time, cpu) | ||
449 | self.layer = Canvas.BOTTOM_LAYER | ||
450 | |||
451 | def __str__(self): | ||
452 | if self.corresp_end_event is None: | ||
453 | return 'Switch To (w/o Switch Away)' + self._common_str() + ', TIME=' \ | ||
454 | + str(self.get_time()) | ||
455 | return 'Scheduled' + self._common_str() + ', START=' \ | ||
456 | + util.format_float(self.get_time(), Event.NUM_DEC_PLACES) \ | ||
457 | + ', END=' + util.format_float(self.corresp_end_event.get_time(), Event.NUM_DEC_PLACES) | ||
458 | |||
459 | def scan(self, cur_cpu, switches): | ||
460 | old_cur_cpu = cur_cpu[0] | ||
461 | cur_cpu[0] = self.get_cpu() | ||
462 | switches[SwitchToEvent] = self | ||
463 | self.corresp_end_event = None | ||
464 | |||
465 | if old_cur_cpu != Event.NO_CPU: | ||
466 | self.erroneous = True | ||
467 | print "currently scheduled somewhere, can't switch to a CPU" | ||
468 | |||
469 | super(SwitchToEvent, self).scan(cur_cpu, switches) | ||
470 | |||
471 | def render(self, graph, layer, prev_events, selectable=False): | ||
472 | if self.corresp_end_event is None: | ||
473 | return # fatally erroneous switch to | ||
474 | if layer == self.layer: | ||
475 | end_time = None | ||
476 | if self.corresp_end_event is None: | ||
477 | end_time = self.get_job().get_task().get_schedule().end | ||
478 | else: | ||
479 | end_time = self.corresp_end_event.get_time() | ||
480 | |||
481 | prev_events[self] = None | ||
482 | cpu = self.get_cpu() | ||
483 | task_no = self.get_job().get_task().get_task_no() | ||
484 | if selectable: | ||
485 | graph.add_sel_bar_at_time(self.get_time(), end_time, | ||
486 | task_no, cpu, self) | ||
487 | else: | ||
488 | graph.draw_bar_at_time(self.get_time(), end_time, | ||
489 | task_no, cpu, self.get_job().get_job_no(), self.is_selected()) | ||
490 | |||
491 | class ReleaseEvent(Event): | 533 | class ReleaseEvent(Event): |
492 | def __init__(self, time, cpu): | 534 | def __init__(self, time, cpu): |
493 | super(ReleaseEvent, self).__init__(time, cpu) | 535 | super(ReleaseEvent, self).__init__(time, cpu) |
@@ -536,6 +578,7 @@ class InversionStartEvent(ErrorEvent): | |||
536 | def __init__(self, time): | 578 | def __init__(self, time): |
537 | super(InversionStartEvent, self).__init__(time, Event.NO_CPU) | 579 | super(InversionStartEvent, self).__init__(time, Event.NO_CPU) |
538 | self.layer = Canvas.BOTTOM_LAYER | 580 | self.layer = Canvas.BOTTOM_LAYER |
581 | self.corresp_end_event = None | ||
539 | 582 | ||
540 | def __str__(self): | 583 | def __str__(self): |
541 | if self.corresp_end_event is None: | 584 | if self.corresp_end_event is None: |
@@ -553,28 +596,33 @@ class InversionStartEvent(ErrorEvent): | |||
553 | super(InversionStartEvent, self).scan(cur_cpu, switches) | 596 | super(InversionStartEvent, self).scan(cur_cpu, switches) |
554 | 597 | ||
555 | def render(self, graph, layer, prev_events, selectable=False): | 598 | def render(self, graph, layer, prev_events, selectable=False): |
556 | end_time = None | ||
557 | if self.corresp_end_event is None: | ||
558 | end_time = self.get_job().get_task().get_schedule().end | ||
559 | else: | ||
560 | end_time = self.corresp_end_event.get_time() | ||
561 | |||
562 | if layer == self.layer: | 599 | if layer == self.layer: |
563 | prev_events[self] = None | 600 | end_time = None |
564 | cpu = self.get_cpu() | 601 | clip = None |
565 | task_no = self.get_job().get_task().get_task_no() | 602 | if self.corresp_end_event is None: |
566 | if selectable: | 603 | end_time = self.get_job().get_task().get_schedule().end |
567 | graph.add_sel_mini_bar_at_time(self.get_time(), end_time, | 604 | clip = AlignMode.RIGHT |
568 | task_no, cpu, self) | ||
569 | else: | 605 | else: |
570 | graph.draw_mini_bar_at_time(self.get_time(), end_time, | 606 | end_time = self.corresp_end_event.get_time() |
571 | task_no, cpu, self.get_job().get_job_no(), self.is_selected()) | 607 | |
608 | if layer == self.layer: | ||
609 | prev_events[self] = None | ||
610 | cpu = self.get_cpu() | ||
611 | task_no = self.get_job().get_task().get_task_no() | ||
612 | if selectable: | ||
613 | graph.add_sel_mini_bar_at_time(self.get_time(), end_time, | ||
614 | task_no, cpu, self) | ||
615 | else: | ||
616 | graph.draw_mini_bar_at_time(self.get_time(), end_time, | ||
617 | task_no, cpu, self.get_job().get_job_no(), | ||
618 | clip, self.is_selected()) | ||
572 | 619 | ||
573 | 620 | ||
574 | class InversionEndEvent(ErrorEvent): | 621 | class InversionEndEvent(ErrorEvent): |
575 | def __init__(self, time): | 622 | def __init__(self, time): |
576 | super(InversionEndEvent, self).__init__(time, Event.NO_CPU) | 623 | super(InversionEndEvent, self).__init__(time, Event.NO_CPU) |
577 | self.layer = Canvas.BOTTOM_LAYER | 624 | self.layer = Canvas.BOTTOM_LAYER |
625 | self.corresp_start_event = None | ||
578 | 626 | ||
579 | def __str__(self): | 627 | def __str__(self): |
580 | if self.corresp_start_event is None: | 628 | if self.corresp_start_event is None: |
@@ -607,13 +655,14 @@ class InversionEndEvent(ErrorEvent): | |||
607 | prev_events[self] = None | 655 | prev_events[self] = None |
608 | cpu = self.get_cpu() | 656 | cpu = self.get_cpu() |
609 | task_no = self.get_job().get_task().get_task_no() | 657 | task_no = self.get_job().get_task().get_task_no() |
658 | start = self.get_job().get_task().get_schedule().start | ||
610 | if selectable: | 659 | if selectable: |
611 | start = self.get_job().get_task().get_schedule().start | ||
612 | graph.add_sel_mini_bar_at_time(start, self.get_time(), | 660 | graph.add_sel_mini_bar_at_time(start, self.get_time(), |
613 | task_no, cpu, self) | 661 | task_no, cpu, self) |
614 | else: | 662 | else: |
615 | graph.draw_mini_bar_at_time(start, self.get_time(), | 663 | graph.draw_mini_bar_at_time(start, self.get_time(), |
616 | task_no, cpu, self.get_job().get_job_no(), self.is_selected()) | 664 | task_no, cpu, self.get_job().get_job_no(), |
665 | AlignMode.LEFT, self.is_selected()) | ||
617 | else: | 666 | else: |
618 | if self.corresp_start_event in prev_events: | 667 | if self.corresp_start_event in prev_events: |
619 | return # already rendered the bar | 668 | return # already rendered the bar |
@@ -625,11 +674,14 @@ class InversionDummy(DummyEvent): | |||
625 | self.layer = Canvas.BOTTOM_LAYER | 674 | self.layer = Canvas.BOTTOM_LAYER |
626 | 675 | ||
627 | def render(self, graph, layer, prev_events, selectable=False): | 676 | def render(self, graph, layer, prev_events, selectable=False): |
628 | if self.corresp_start_event is not None and self.corresp_start_event in prev_events: | 677 | if self.corresp_start_event is None: |
629 | return # we have already been rendered | 678 | if self.corresp_end_event in prev_events: |
630 | if self.corresp_end_event is not None and self.corresp_end_event in prev_events: | 679 | return # we have already been rendered |
631 | return | 680 | self.corresp_end_event.render(graph, layer, prev_events, selectable) |
632 | self.corresp_start_event.render(graph, layer, prev_events, selectable) | 681 | else: |
682 | if self.corresp_start_event in prev_events: | ||
683 | return # we have already been rendered | ||
684 | self.corresp_start_event.render(graph, layer, prev_events, selectable) | ||
633 | 685 | ||
634 | class IsRunningDummy(DummyEvent): | 686 | class IsRunningDummy(DummyEvent): |
635 | def __init__(self, time, cpu): | 687 | def __init__(self, time, cpu): |
@@ -637,12 +689,20 @@ class IsRunningDummy(DummyEvent): | |||
637 | self.layer = Canvas.BOTTOM_LAYER | 689 | self.layer = Canvas.BOTTOM_LAYER |
638 | 690 | ||
639 | def render(self, graph, layer, prev_events, selectable=False): | 691 | def render(self, graph, layer, prev_events, selectable=False): |
640 | if self.corresp_start_event is None or self.corresp_start_event in prev_events: | 692 | if self.corresp_start_event is None: |
641 | return # we have already been rendered | 693 | if self.corresp_end_event in prev_events: |
642 | self.corresp_start_event.render(graph, layer, prev_events, selectable) | 694 | return # we have already been rendered |
695 | self.corresp_end_event.render(graph, layer, prev_events, selectable) | ||
696 | else: | ||
697 | if self.corresp_start_event in prev_events: | ||
698 | return # we have already been rendered | ||
699 | self.corresp_start_event.render(graph, layer, prev_events, selectable) | ||
643 | 700 | ||
644 | EVENT_LIST = {SuspendEvent : None, ResumeEvent : None, CompleteEvent : None, | 701 | EVENT_LIST = {SuspendEvent : None, ResumeEvent : None, CompleteEvent : None, |
645 | SwitchAwayEvent : None, SwitchToEvent : None, ReleaseEvent : None, | 702 | SwitchAwayEvent : None, SwitchToEvent : None, ReleaseEvent : None, |
646 | DeadlineEvent : None, IsRunningDummy : None, | 703 | DeadlineEvent : None, IsRunningDummy : None, |
647 | InversionStartEvent : None, InversionEndEvent : None, | 704 | InversionStartEvent : None, InversionEndEvent : None, |
648 | InversionDummy : None} | 705 | InversionDummy : None} |
706 | |||
707 | SPAN_START_EVENTS = { SwitchToEvent : IsRunningDummy, InversionStartEvent : InversionDummy } | ||
708 | SPAN_END_EVENTS = { SwitchAwayEvent : IsRunningDummy, InversionEndEvent : InversionDummy} | ||