From 2c60ea049270ac24a6e404de28a837e8efc668a2 Mon Sep 17 00:00:00 2001 From: Oscar Gustafsson <oscar.gustafsson@gmail.com> Date: Mon, 8 Jun 2020 23:41:53 +0200 Subject: [PATCH] Better rescheduling --- b_asic/schema.py | 93 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 14 deletions(-) diff --git a/b_asic/schema.py b/b_asic/schema.py index 4c68e86d..63829e83 100644 --- a/b_asic/schema.py +++ b/b_asic/schema.py @@ -68,33 +68,56 @@ class Schema: def forward_slack(self, op_id: GraphID) -> int: assert op_id in self._start_times, "No operation with the specified op_id in this schema." + slack = sys.maxsize + output_slacks = self._forward_slacks(op_id) + # Make more pythonic + for signal_slacks in output_slacks.values(): + for signal_slack in signal_slacks.values(): + slack = min(slack, signal_slack) + return slack + + def _forward_slacks(self, op_id: GraphID) -> Dict["OutputPort", Dict["Signal", int]]: + ret = dict() start_time = self._start_times[op_id] op = self._sfg.find_by_id(op_id) - slack = sys.maxsize for output_port in op.outputs: + output_slacks = dict() available_time = start_time + output_port.latency_offset for signal in output_port.signals: usage_time = (signal.destination.latency_offset + self._start_times[signal.destination.operation.graph_id] + self._schedule_time*self._laps[signal.graph_id]) - slack = min(slack, usage_time - available_time) - return slack + output_slacks[signal] = usage_time - available_time + ret[output_port] = output_slacks + return ret def backward_slack(self, op_id: GraphID) -> int: assert op_id in self._start_times, "No operation with the specified op_id in this schema." + slack = sys.maxsize + input_slacks = self._backward_slacks(op_id) + # Make more pythonic + for signal_slacks in input_slacks.values(): + for signal_slack in signal_slacks.values(): + slack = min(slack, signal_slack) + return slack + + def _backward_slacks(self, op_id: GraphID) -> Dict["OutputPort", Dict["Signal", int]]: + ret = dict() start_time = self._start_times[op_id] op = self._sfg.find_by_id(op_id) - slack = sys.maxsize for input_port in op.inputs: + input_slacks = dict() usage_time = start_time + input_port.latency_offset for signal in input_port.signals: available_time = (signal.source.latency_offset + self._start_times[signal.source.operation.graph_id] - self._schedule_time*self._laps[signal.graph_id]) - slack = min(slack, usage_time - available_time) - return slack + input_slacks[signal] = usage_time - available_time + ret[input_port] = input_slacks + return ret + def slacks(self, op_id: GraphID) -> Tuple[int, int]: assert op_id in self._start_times, "No operation with the specified op_id in this schema." @@ -103,29 +126,71 @@ class Schema: def print_slacks(self) -> None: raise NotImplementedError - def set_schedule_time(self, time: int) -> None: + def set_schedule_time(self, time: int) -> "Schema": assert self._get_max_end_time() < time, "New schedule time to short." self._schedule_time = time + return self @property def schedule_time(self) -> int: return self._schedule_time - def increase_time_resolution(self, factor: int) -> None: + def increase_time_resolution(self, factor: int) -> "Schema": raise NotImplementedError - def decrease_time_resolution(self, factor: int) -> None: + def decrease_time_resolution(self, factor: int) -> "Schema": raise NotImplementedError - def move_operation(self, op_id: GraphID, time: int) -> None: + def move_operation(self, op_id: GraphID, time: int) -> "Schema": assert op_id in self._start_times, "No operation with the specified op_id in this schema." + + (backward_slack, forward_slack) = self.slacks(op_id) if time < 0: - if -time > self.backward_slack(op_id): + if -time > backward_slack: raise ValueError else: - if time > self.forward_slack(op_id): + if time > forward_slack: raise ValueError - self._start_times[op_id] += time + + tmp_start = self._start_times[op_id] + time + new_start = tmp_start % self._schedule_time + + # Update input laps + input_slacks = self._backward_slacks(op_id) + for in_port, signal_slacks in input_slacks.items(): + tmp_usage = tmp_start + in_port.latency_offset + new_usage = tmp_usage % self._schedule_time + for signal, signal_slack in signal_slacks.items(): + new_slack = signal_slack + time + old_laps = self._laps[signal.graph_id] + tmp_prev_available = tmp_usage - new_slack + prev_available = tmp_prev_available % self._schedule_time + laps = new_slack // self._schedule_time + if new_usage < prev_available: + laps += 1 + print([signal_slack, new_slack, old_laps, laps, new_usage, prev_available, tmp_usage, tmp_prev_available]) + self._laps[signal.graph_id] = laps + + # Update output laps + output_slacks = self._forward_slacks(op_id) + for out_port, signal_slacks in output_slacks.items(): + tmp_available = tmp_start + out_port.latency_offset + new_available = tmp_available % self._schedule_time + for signal, signal_slack in signal_slacks.items(): + new_slack = signal_slack - time + tmp_next_usage = tmp_available + new_slack + next_usage = tmp_next_usage % self._schedule_time + laps = new_slack // self._schedule_time + if next_usage < new_available: + laps += 1 + if new_available == 0 and new_slack > 0: + laps += 1 + self._laps[signal.graph_id] = laps + + + # Set new start time + self._start_times[op_id] = new_start + return self def _remove_delays(self) -> None: delay_list = self._sfg.find_by_type_name(Delay.type_name()) @@ -223,7 +288,7 @@ class Schema: plt.plot(out[0], out[1], color='black') def _draw_arrow(start, end, name="", laps=0): - if end[0] < start[0]: # Wrap around + if end[0] < start[0] or laps > 0: # Wrap around plt.plot([start[0], self._schedule_time + 0.2], [start[1], start[1]], color='black') plt.plot([-0.2, end[0]], [end[1], end[1]], color='black') plt.text(self._schedule_time + 0.2, start[1], name, verticalalignment='center') -- GitLab