From 276856f0f9d3b9a2522a8a90612e7e3b22bd917e Mon Sep 17 00:00:00 2001 From: Oscar Gustafsson <oscar.gustafsson@gmail.com> Date: Sat, 15 Mar 2025 13:09:36 +0100 Subject: [PATCH] Better drawing and ordering of cyclic schedules with latency offsets --- b_asic/schedule.py | 55 +++++++++++++++++++++++++++++--------- test/unit/test_schedule.py | 4 +-- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/b_asic/schedule.py b/b_asic/schedule.py index 013925cd..a20410d4 100644 --- a/b_asic/schedule.py +++ b/b_asic/schedule.py @@ -18,6 +18,7 @@ from matplotlib.lines import Line2D from matplotlib.patches import PathPatch, Polygon from matplotlib.path import Path from matplotlib.ticker import MaxNLocator +from matplotlib.transforms import Bbox, TransformedBbox from b_asic import Signal from b_asic._preferences import ( @@ -358,9 +359,7 @@ class Schedule: usage_time = start_time + cast(int, input_port.latency_offset) for signal in input_port.signals: source = cast(OutputPort, signal.source) - if isinstance(source.operation, DontCare): - available_time = 0 - elif isinstance(source.operation, Delay): + if isinstance(source.operation, (DontCare, Delay)): available_time = 0 else: if self._schedule_time is not None: @@ -770,9 +769,7 @@ class Schedule: source_port = source_op = input_port.signals[0].source source_op = source_port.operation - if not isinstance(source_op, Delay) and not isinstance( - source_op, DontCare - ): + if not isinstance(source_op, (Delay, DontCare)): if op_laps[source_op.graph_id] < current_lap: laps += current_lap - op_laps[source_op.graph_id] source_available_time = ( @@ -802,7 +799,7 @@ class Schedule: and isinstance(op, DontCare) and self._laps[op.output(0).signals[0].graph_id] == 0 ): - start = time + start = time % self._schedule_time self._start_times[op.graph_id] = start @@ -1074,6 +1071,20 @@ class Schedule: sorted(self._start_times, key=self._start_times.get) ): self.set_y_location(graph_id, i) + for graph_id in self._start_times: + op = cast(Operation, self._sfg.find_by_id(graph_id)) + if isinstance(op, Output): + self.move_y_location( + graph_id, + self.get_y_location(op.preceding_operations[0].graph_id) + 1, + True, + ) + if isinstance(op, DontCare): + self.move_y_location( + graph_id, + self.get_y_location(op.subsequent_operations[0].graph_id), + True, + ) def _plot_schedule(self, ax: Axes, operation_gap: float = OPERATION_GAP) -> None: """Draw the schedule.""" @@ -1083,6 +1094,10 @@ class Schedule: start: Sequence[float], end: Sequence[float], name: str = "", laps: int = 0 ) -> None: """Draw an arrow from *start* to *end*.""" + if end[0] > self.schedule_time: + end[0] %= self.schedule_time + if start[0] > self.schedule_time: + start[0] %= self.schedule_time if end[0] < start[0] or laps > 0: # Wrap around if start not in line_cache: line = Line2D( @@ -1175,10 +1190,15 @@ class Schedule: _x, _y = zip(*latency_coordinates) x = np.array(_x) y = np.array(_y) - xy = np.stack((x + op_start_time, y + y_pos)) - ax.add_patch(Polygon(xy.T, fc=_LATENCY_COLOR)) - - if 'in' in str(graph_id): + xvalues = x + op_start_time + xy = np.stack((xvalues, y + y_pos)) + p = ax.add_patch(Polygon(xy.T, fc=_LATENCY_COLOR)) + p.set_clip_box(TransformedBbox(Bbox([[0, 0], [1, 1]]), ax.transAxes)) + if any(xvalues > self.schedule_time) and not isinstance(operation, Output): + xy = np.stack((xvalues - self.schedule_time, y + y_pos)) + p = ax.add_patch(Polygon(xy.T, fc=_LATENCY_COLOR)) + p.set_clip_box(TransformedBbox(Bbox([[0, 0], [1, 1]]), ax.transAxes)) + if isinstance(operation, Input): ax.annotate( graph_id, xy=(op_start_time - 0.48, y_pos + 0.7), @@ -1196,12 +1216,23 @@ class Schedule: _x, _y = zip(*execution_time_coordinates) x = np.array(_x) y = np.array(_y) + xvalues = x + op_start_time ax.plot( - x + op_start_time, + xvalues, y + y_pos, color=_EXECUTION_TIME_COLOR, linewidth=3, ) + if any(xvalues > self.schedule_time) and not isinstance( + operation, Output + ): + ax.plot( + xvalues - self.schedule_time, + y + y_pos, + color=_EXECUTION_TIME_COLOR, + linewidth=3, + ) + ytickpositions.append(y_pos + 0.5) yticklabels.append(cast(Operation, self._sfg.find_by_id(graph_id)).name) diff --git a/test/unit/test_schedule.py b/test/unit/test_schedule.py index 357e3cb4..6b499bd7 100644 --- a/test/unit/test_schedule.py +++ b/test/unit/test_schedule.py @@ -843,7 +843,7 @@ class TestYLocations: sfg_simple_filter.set_latency_of_type(ConstantMultiplication.type_name(), 2) schedule = Schedule(sfg_simple_filter, ASAPScheduler()) - assert schedule._y_locations == {"in0": 0, "cmul0": 1, "add0": 3, "out0": 2} + assert schedule._y_locations == {"in0": 0, "cmul0": 1, "add0": 2, "out0": 3} schedule.move_y_location("add0", 1, insert=True) assert schedule._y_locations == {"in0": 0, "cmul0": 2, "add0": 1, "out0": 3} schedule.move_y_location("out0", 1) @@ -854,7 +854,7 @@ class TestYLocations: sfg_simple_filter.set_latency_of_type(ConstantMultiplication.type_name(), 2) schedule = Schedule(sfg_simple_filter, ASAPScheduler()) - assert schedule._y_locations == {"in0": 0, "cmul0": 1, "add0": 3, "out0": 2} + assert schedule._y_locations == {"in0": 0, "cmul0": 1, "add0": 2, "out0": 3} schedule.reset_y_locations() assert schedule._y_locations["in0"] is None assert schedule._y_locations["cmul0"] is None -- GitLab