From d2240e7a9b15d18dfd0f3cbe75f3adf1c9e7fabf Mon Sep 17 00:00:00 2001 From: Mac Mollison Date: Mon, 31 Jan 2011 16:40:54 -0500 Subject: 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 --- unit_trace/viz/schedule.py | 171 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 149 insertions(+), 22 deletions(-) (limited to 'unit_trace/viz/schedule.py') 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): self.time_slot_array = None self.cur_task_no = 0 self.num_cpus = num_cpus + self.jobless = [] for task in task_list: self.add_task(task) @@ -217,6 +218,23 @@ class Schedule(object): task.task_no = self.cur_task_no self.cur_task_no += 1 + def add_jobless(self, event): + self.jobless.append(event) + + def sort_task_nos_numeric(self): + # sort task numbers by the numeric value of the task names. + nums = [] + + for task_name in self.tasks: + nums.append((int(task_name), task_name)) + + nums.sort(key=lambda t: t[0]) + for no, task in enumerate(nums): + self.tasks[task[1]].task_no = no + + def get_jobless(self): + return self.jobless + def get_tasks(self): return self.tasks @@ -295,12 +313,12 @@ class DummyEvent(object): event added by the application to speed things up or keep track of something. Such an event won't be added to the schedule tree, but might appear in the time slot array.""" - def __init__(self, time, cpu): self.time = time self.cpu = cpu self.job = None self.layer = None + self.saved_schedule = None def __str__(self): return '[Dummy Event]' @@ -311,6 +329,25 @@ class DummyEvent(object): def get_cpu(self): return self.cpu + # Refactor, shouldn't depend on job + def get_schedule(self): + if self.saved_schedule is not None: + return self.saved_schedule + elif self.get_task() is not None: + return self.get_task().get_schedule() + else: + return None + + # Needed for events not assigned to specific tasks + def set_schedule(self, schedule): + self.saved_schedule = schedule + + def get_task(self): + if self.get_job() is not None: + return self.get_job().get_task() + else: + return None + def get_job(self): return self.job @@ -342,20 +379,34 @@ class Event(DummyEvent): def __str__(self): return self.get_name() + self._common_str() + ', TIME=' + util.format_float(self.get_time(), Event.NUM_DEC_PLACES) - def str_long(self): - """Prints the event as a string, in ``long'' form.""" - return 'Event Type: ' + self.get_name() + \ - '\nTask Name: ' + str(self.get_job().get_task().get_name()) + \ - '\n(Task no., Job no.): ' + str((self.get_job().get_task().get_task_no(), \ - self.get_job().get_job_no())) + \ - '\nCPU: ' + str(self.get_cpu()) + \ - '\nTime: ' + str(self.get_time()) + def str_long(self, unit): + if self.get_job() is not None: + """Prints the event as a string, in ``long'' form.""" + return 'Event Information\n-----------------\n' + \ + 'Event Type: ' + self.get_name() + \ + '\nTask Name: ' + str(self.get_job().get_task().get_name()) + \ + '\n(Task no., Job no.): ' + str((self.get_job().get_task().get_task_no(), \ + self.get_job().get_job_no())) + \ + '\nCPU: ' + str(self.get_cpu()) + \ + '\nTime: ' + _format_time(self.get_time(), unit) + \ + '\n\n' + self.get_job().str_long(unit) + else: + """Prints the event as a string, in ``long'' form.""" + return 'Event Information\n-----------------\n' + \ + 'Event Type: ' + self.get_name() + \ + '\nTask Name: None' + \ + '\nCPU: ' + str(self.get_cpu()) + \ + '\nTime: ' + _format_time(self.get_time(), unit) def _common_str(self): - job = self.get_job() - task = job.get_task() - return ' for task ' + str(task.get_name()) + ': (TASK, JOB)=' + str((task.get_task_no(), \ - job.get_job_no())) + ', CPU=' + str(self.get_cpu()) + if self.get_job() is not None: + job = self.get_job() + task = job.get_task() + return ' for task ' + str(task.get_name()) + ': (TASK, JOB)=' + \ + str((task.get_task_no(), job.get_job_no())) + \ + ', CPU=' + str(self.get_cpu()) + else: + return ', Cpu=' + str(self.get_cpu()) def is_erroneous(self): """An erroneous event is where something with the event is not quite right, @@ -377,13 +428,56 @@ class Event(DummyEvent): time in the scan, and ``switches'' gives the last time a certain switch (e.g. SwitchToEvent, InversionStartEvent) occurred""" time = self.get_time() - sched = self.get_job().get_task().get_schedule() - if sched.start is None or time < sched.start: - sched.start = time - if sched.end is None or time > sched.end: - sched.end = time - sched.get_time_slot_array().add_event_to_time_slot(self) + sched = self.get_schedule() + + if sched is not None: + if sched.start is None or time < sched.start: + sched.start = time + if sched.end is None or time > sched.end: + sched.end = time + + if item_nos is None: + item_nos = { TimeSlotArray.TASK_LIST : self.get_task().get_task_no(), + TimeSlotArray.CPU_LIST : self.get_cpu() } + sched.get_time_slot_array().add_event_to_time_slot(self, item_nos) + + self.fill_span_event_from_end() + + def fill_span_event_from_start(self): + """This method exists for events that can ``range'' over a period of time + (e.g. SwitchAway and SwitchTo). In case a start event is not paired with + an end event, or vice versa, we want to fill in dummy events to range all + the way to the beginning or end. Since most events occur only at a specific + time, this is usually a no-op.""" + pass + + def fill_span_event_from_end(self): + """The mirror image of the last method.""" + pass + +class SpanEvent(Event): + def __init__(self, time, cpu, dummy_class): + super(SpanEvent, self).__init__(time, cpu) + self.dummy_class = dummy_class + +class SpanDummy(DummyEvent): + def __init__(self): + super(SpanDummy, self).__init__(None, None) + + def get_task(self): + if self.corresp_start_event is not None: + return self.corresp_start_event.get_task() + if self.corresp_end_event is not None: + return self.corresp_end_event.get_task() + return None + + def get_schedule(self): + if self.corresp_start_event is not None: + return self.corresp_start_event.get_schedule() + if self.corresp_end_event is not None: + return self.corresp_end_event.get_schedule() + return None class ErrorEvent(Event): pass @@ -631,9 +725,42 @@ class DeadlineEvent(Event): graph.add_sel_deadline_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(), self) else: - graph.draw_deadline_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(), - self.get_job().get_job_no(), self.is_selected()) + graph.draw_deadline_arrow_at_time(self.get_time(), + self.get_job().get_task().get_task_no(), + self.get_job().get_job_no(), self.is_selected()) +class ActionEvent(Event): + def __init__(self, time, cpu, action): + super(ActionEvent, self).__init__(time, cpu) + self.layer = Canvas.TOP_LAYER + self.action = int(action) + + def get_name(self): + return 'Action' + + def scan(self, cur_cpu, switches): + item_nos = { TimeSlotArray.TASK_LIST : self.get_task().get_task_no(), + TimeSlotArray.CPU_LIST : TimeSlotArray.POST_ITEM_NO } + super(ActionEvent, self).scan(cur_cpu, switches, item_nos) + + def render(self, graph, layer, prev_events, selectable=False): + prev_events[self] = None + if layer == Canvas.TOP_LAYER: + + # TODO: need a more official way of doing this + task_no = -1 + job_no = -1 + if self.get_job() is not None: + task_no = self.get_job().get_task().get_task_no() + job_no = self.get_job().get_job_no() + + if selectable: + graph.add_sel_action_symbol_at_time(self.get_time(), task_no, + self.get_cpu(), self) + else: + graph.draw_action_symbol_at_time(self.get_time(), task_no, + self.get_cpu(), self.action, + job_no, self.is_selected()) class InversionStartEvent(ErrorEvent): def __init__(self, time): @@ -791,7 +918,7 @@ EVENT_LIST = {SuspendEvent : None, ResumeEvent : None, CompleteEvent : None, SwitchAwayEvent : None, SwitchToEvent : None, ReleaseEvent : None, DeadlineEvent : None, IsRunningDummy : None, InversionStartEvent : None, InversionEndEvent : None, - InversionDummy : None} + InversionDummy : None, TaskDummy : None, CPUDummy : None, ActionEvent: None} SPAN_START_EVENTS = { SwitchToEvent : IsRunningDummy, InversionStartEvent : InversionDummy } SPAN_END_EVENTS = { SwitchAwayEvent : IsRunningDummy, InversionEndEvent : InversionDummy} -- cgit v1.2.2