diff options
author | Mac Mollison <mollison@cs.unc.edu> | 2011-01-31 16:40:54 -0500 |
---|---|---|
committer | Mac Mollison <mollison@cs.unc.edu> | 2011-01-31 16:40:54 -0500 |
commit | d2240e7a9b15d18dfd0f3cbe75f3adf1c9e7fabf (patch) | |
tree | f7d164c21716b55f3d9195f055db73505bbf951d /unit_trace/viz/schedule.py | |
parent | 85a089c42749e1394ae12321564109f25fa8154f (diff) |
Added support for visualizing arbitrary actions.
(By Jonathan, cherry-picked by Mac)
Conflicts:
unit_trace/trace_reader.py
unit_trace/viz/canvas.py
unit_trace/viz/graph.py
unit_trace/viz/schedule.py
Diffstat (limited to 'unit_trace/viz/schedule.py')
-rw-r--r-- | unit_trace/viz/schedule.py | 171 |
1 files changed, 149 insertions, 22 deletions
diff --git a/unit_trace/viz/schedule.py b/unit_trace/viz/schedule.py index a44ce8d..2301b0c 100644 --- a/unit_trace/viz/schedule.py +++ b/unit_trace/viz/schedule.py | |||
@@ -138,6 +138,7 @@ class Schedule(object): | |||
138 | self.time_slot_array = None | 138 | self.time_slot_array = None |
139 | self.cur_task_no = 0 | 139 | self.cur_task_no = 0 |
140 | self.num_cpus = num_cpus | 140 | self.num_cpus = num_cpus |
141 | self.jobless = [] | ||
141 | for task in task_list: | 142 | for task in task_list: |
142 | self.add_task(task) | 143 | self.add_task(task) |
143 | 144 | ||
@@ -217,6 +218,23 @@ class Schedule(object): | |||
217 | task.task_no = self.cur_task_no | 218 | task.task_no = self.cur_task_no |
218 | self.cur_task_no += 1 | 219 | self.cur_task_no += 1 |
219 | 220 | ||
221 | def add_jobless(self, event): | ||
222 | self.jobless.append(event) | ||
223 | |||
224 | def sort_task_nos_numeric(self): | ||
225 | # sort task numbers by the numeric value of the task names. | ||
226 | nums = [] | ||
227 | |||
228 | for task_name in self.tasks: | ||
229 | nums.append((int(task_name), task_name)) | ||
230 | |||
231 | nums.sort(key=lambda t: t[0]) | ||
232 | for no, task in enumerate(nums): | ||
233 | self.tasks[task[1]].task_no = no | ||
234 | |||
235 | def get_jobless(self): | ||
236 | return self.jobless | ||
237 | |||
220 | def get_tasks(self): | 238 | def get_tasks(self): |
221 | return self.tasks | 239 | return self.tasks |
222 | 240 | ||
@@ -295,12 +313,12 @@ class DummyEvent(object): | |||
295 | event added by the application to speed things up or keep track of | 313 | event added by the application to speed things up or keep track of |
296 | something. Such an event won't be added to the schedule tree, but | 314 | something. Such an event won't be added to the schedule tree, but |
297 | might appear in the time slot array.""" | 315 | might appear in the time slot array.""" |
298 | |||
299 | def __init__(self, time, cpu): | 316 | def __init__(self, time, cpu): |
300 | self.time = time | 317 | self.time = time |
301 | self.cpu = cpu | 318 | self.cpu = cpu |
302 | self.job = None | 319 | self.job = None |
303 | self.layer = None | 320 | self.layer = None |
321 | self.saved_schedule = None | ||
304 | 322 | ||
305 | def __str__(self): | 323 | def __str__(self): |
306 | return '[Dummy Event]' | 324 | return '[Dummy Event]' |
@@ -311,6 +329,25 @@ class DummyEvent(object): | |||
311 | def get_cpu(self): | 329 | def get_cpu(self): |
312 | return self.cpu | 330 | return self.cpu |
313 | 331 | ||
332 | # Refactor, shouldn't depend on job | ||
333 | def get_schedule(self): | ||
334 | if self.saved_schedule is not None: | ||
335 | return self.saved_schedule | ||
336 | elif self.get_task() is not None: | ||
337 | return self.get_task().get_schedule() | ||
338 | else: | ||
339 | return None | ||
340 | |||
341 | # Needed for events not assigned to specific tasks | ||
342 | def set_schedule(self, schedule): | ||
343 | self.saved_schedule = schedule | ||
344 | |||
345 | def get_task(self): | ||
346 | if self.get_job() is not None: | ||
347 | return self.get_job().get_task() | ||
348 | else: | ||
349 | return None | ||
350 | |||
314 | def get_job(self): | 351 | def get_job(self): |
315 | return self.job | 352 | return self.job |
316 | 353 | ||
@@ -342,20 +379,34 @@ class Event(DummyEvent): | |||
342 | def __str__(self): | 379 | def __str__(self): |
343 | return self.get_name() + self._common_str() + ', TIME=' + util.format_float(self.get_time(), Event.NUM_DEC_PLACES) | 380 | return self.get_name() + self._common_str() + ', TIME=' + util.format_float(self.get_time(), Event.NUM_DEC_PLACES) |
344 | 381 | ||
345 | def str_long(self): | 382 | def str_long(self, unit): |
346 | """Prints the event as a string, in ``long'' form.""" | 383 | if self.get_job() is not None: |
347 | return 'Event Type: ' + self.get_name() + \ | 384 | """Prints the event as a string, in ``long'' form.""" |
348 | '\nTask Name: ' + str(self.get_job().get_task().get_name()) + \ | 385 | return 'Event Information\n-----------------\n' + \ |
349 | '\n(Task no., Job no.): ' + str((self.get_job().get_task().get_task_no(), \ | 386 | 'Event Type: ' + self.get_name() + \ |
350 | self.get_job().get_job_no())) + \ | 387 | '\nTask Name: ' + str(self.get_job().get_task().get_name()) + \ |
351 | '\nCPU: ' + str(self.get_cpu()) + \ | 388 | '\n(Task no., Job no.): ' + str((self.get_job().get_task().get_task_no(), \ |
352 | '\nTime: ' + str(self.get_time()) | 389 | self.get_job().get_job_no())) + \ |
390 | '\nCPU: ' + str(self.get_cpu()) + \ | ||
391 | '\nTime: ' + _format_time(self.get_time(), unit) + \ | ||
392 | '\n\n' + self.get_job().str_long(unit) | ||
393 | else: | ||
394 | """Prints the event as a string, in ``long'' form.""" | ||
395 | return 'Event Information\n-----------------\n' + \ | ||
396 | 'Event Type: ' + self.get_name() + \ | ||
397 | '\nTask Name: None' + \ | ||
398 | '\nCPU: ' + str(self.get_cpu()) + \ | ||
399 | '\nTime: ' + _format_time(self.get_time(), unit) | ||
353 | 400 | ||
354 | def _common_str(self): | 401 | def _common_str(self): |
355 | job = self.get_job() | 402 | if self.get_job() is not None: |
356 | task = job.get_task() | 403 | job = self.get_job() |
357 | return ' for task ' + str(task.get_name()) + ': (TASK, JOB)=' + str((task.get_task_no(), \ | 404 | task = job.get_task() |
358 | job.get_job_no())) + ', CPU=' + str(self.get_cpu()) | 405 | return ' for task ' + str(task.get_name()) + ': (TASK, JOB)=' + \ |
406 | str((task.get_task_no(), job.get_job_no())) + \ | ||
407 | ', CPU=' + str(self.get_cpu()) | ||
408 | else: | ||
409 | return ', Cpu=' + str(self.get_cpu()) | ||
359 | 410 | ||
360 | def is_erroneous(self): | 411 | def is_erroneous(self): |
361 | """An erroneous event is where something with the event is not quite right, | 412 | """An erroneous event is where something with the event is not quite right, |
@@ -377,13 +428,56 @@ class Event(DummyEvent): | |||
377 | time in the scan, and ``switches'' gives the last time a certain switch | 428 | time in the scan, and ``switches'' gives the last time a certain switch |
378 | (e.g. SwitchToEvent, InversionStartEvent) occurred""" | 429 | (e.g. SwitchToEvent, InversionStartEvent) occurred""" |
379 | time = self.get_time() | 430 | time = self.get_time() |
380 | sched = self.get_job().get_task().get_schedule() | ||
381 | if sched.start is None or time < sched.start: | ||
382 | sched.start = time | ||
383 | if sched.end is None or time > sched.end: | ||
384 | sched.end = time | ||
385 | 431 | ||
386 | sched.get_time_slot_array().add_event_to_time_slot(self) | 432 | sched = self.get_schedule() |
433 | |||
434 | if sched is not None: | ||
435 | if sched.start is None or time < sched.start: | ||
436 | sched.start = time | ||
437 | if sched.end is None or time > sched.end: | ||
438 | sched.end = time | ||
439 | |||
440 | if item_nos is None: | ||
441 | item_nos = { TimeSlotArray.TASK_LIST : self.get_task().get_task_no(), | ||
442 | TimeSlotArray.CPU_LIST : self.get_cpu() } | ||
443 | sched.get_time_slot_array().add_event_to_time_slot(self, item_nos) | ||
444 | |||
445 | self.fill_span_event_from_end() | ||
446 | |||
447 | def fill_span_event_from_start(self): | ||
448 | """This method exists for events that can ``range'' over a period of time | ||
449 | (e.g. SwitchAway and SwitchTo). In case a start event is not paired with | ||
450 | an end event, or vice versa, we want to fill in dummy events to range all | ||
451 | the way to the beginning or end. Since most events occur only at a specific | ||
452 | time, this is usually a no-op.""" | ||
453 | pass | ||
454 | |||
455 | def fill_span_event_from_end(self): | ||
456 | """The mirror image of the last method.""" | ||
457 | pass | ||
458 | |||
459 | class SpanEvent(Event): | ||
460 | def __init__(self, time, cpu, dummy_class): | ||
461 | super(SpanEvent, self).__init__(time, cpu) | ||
462 | self.dummy_class = dummy_class | ||
463 | |||
464 | class SpanDummy(DummyEvent): | ||
465 | def __init__(self): | ||
466 | super(SpanDummy, self).__init__(None, None) | ||
467 | |||
468 | def get_task(self): | ||
469 | if self.corresp_start_event is not None: | ||
470 | return self.corresp_start_event.get_task() | ||
471 | if self.corresp_end_event is not None: | ||
472 | return self.corresp_end_event.get_task() | ||
473 | return None | ||
474 | |||
475 | def get_schedule(self): | ||
476 | if self.corresp_start_event is not None: | ||
477 | return self.corresp_start_event.get_schedule() | ||
478 | if self.corresp_end_event is not None: | ||
479 | return self.corresp_end_event.get_schedule() | ||
480 | return None | ||
387 | 481 | ||
388 | class ErrorEvent(Event): | 482 | class ErrorEvent(Event): |
389 | pass | 483 | pass |
@@ -631,9 +725,42 @@ class DeadlineEvent(Event): | |||
631 | graph.add_sel_deadline_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(), | 725 | graph.add_sel_deadline_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(), |
632 | self) | 726 | self) |
633 | else: | 727 | else: |
634 | graph.draw_deadline_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(), | 728 | graph.draw_deadline_arrow_at_time(self.get_time(), |
635 | self.get_job().get_job_no(), self.is_selected()) | 729 | self.get_job().get_task().get_task_no(), |
730 | self.get_job().get_job_no(), self.is_selected()) | ||
636 | 731 | ||
732 | class ActionEvent(Event): | ||
733 | def __init__(self, time, cpu, action): | ||
734 | super(ActionEvent, self).__init__(time, cpu) | ||
735 | self.layer = Canvas.TOP_LAYER | ||
736 | self.action = int(action) | ||
737 | |||
738 | def get_name(self): | ||
739 | return 'Action' | ||
740 | |||
741 | def scan(self, cur_cpu, switches): | ||
742 | item_nos = { TimeSlotArray.TASK_LIST : self.get_task().get_task_no(), | ||
743 | TimeSlotArray.CPU_LIST : TimeSlotArray.POST_ITEM_NO } | ||
744 | super(ActionEvent, self).scan(cur_cpu, switches, item_nos) | ||
745 | |||
746 | def render(self, graph, layer, prev_events, selectable=False): | ||
747 | prev_events[self] = None | ||
748 | if layer == Canvas.TOP_LAYER: | ||
749 | |||
750 | # TODO: need a more official way of doing this | ||
751 | task_no = -1 | ||
752 | job_no = -1 | ||
753 | if self.get_job() is not None: | ||
754 | task_no = self.get_job().get_task().get_task_no() | ||
755 | job_no = self.get_job().get_job_no() | ||
756 | |||
757 | if selectable: | ||
758 | graph.add_sel_action_symbol_at_time(self.get_time(), task_no, | ||
759 | self.get_cpu(), self) | ||
760 | else: | ||
761 | graph.draw_action_symbol_at_time(self.get_time(), task_no, | ||
762 | self.get_cpu(), self.action, | ||
763 | job_no, self.is_selected()) | ||
637 | 764 | ||
638 | class InversionStartEvent(ErrorEvent): | 765 | class InversionStartEvent(ErrorEvent): |
639 | def __init__(self, time): | 766 | def __init__(self, time): |
@@ -791,7 +918,7 @@ EVENT_LIST = {SuspendEvent : None, ResumeEvent : None, CompleteEvent : None, | |||
791 | SwitchAwayEvent : None, SwitchToEvent : None, ReleaseEvent : None, | 918 | SwitchAwayEvent : None, SwitchToEvent : None, ReleaseEvent : None, |
792 | DeadlineEvent : None, IsRunningDummy : None, | 919 | DeadlineEvent : None, IsRunningDummy : None, |
793 | InversionStartEvent : None, InversionEndEvent : None, | 920 | InversionStartEvent : None, InversionEndEvent : None, |
794 | InversionDummy : None} | 921 | InversionDummy : None, TaskDummy : None, CPUDummy : None, ActionEvent: None} |
795 | 922 | ||
796 | SPAN_START_EVENTS = { SwitchToEvent : IsRunningDummy, InversionStartEvent : InversionDummy } | 923 | SPAN_START_EVENTS = { SwitchToEvent : IsRunningDummy, InversionStartEvent : InversionDummy } |
797 | SPAN_END_EVENTS = { SwitchAwayEvent : IsRunningDummy, InversionEndEvent : InversionDummy} | 924 | SPAN_END_EVENTS = { SwitchAwayEvent : IsRunningDummy, InversionEndEvent : InversionDummy} |