Newer
Older
Angus Lothian
committed
Contains the schedule class for scheduling operations in an SFG.
from collections import defaultdict
from typing import Dict, List, Optional, Sequence, Tuple, cast
from matplotlib.axes import Axes
from matplotlib.figure import Figure
from matplotlib.patches import PathPatch, Polygon
from matplotlib.path import Path
Angus Lothian
committed
from b_asic._preferences import (
EXECUTION_TIME_COLOR,
LATENCY_COLOR,
SIGNAL_COLOR,
SIGNAL_LINEWIDTH,
Angus Lothian
committed
from b_asic.graph_component import GraphID
from b_asic.operation import Operation
from b_asic.port import InputPort, OutputPort
from b_asic.process import MemoryVariable, OperatorProcess
from b_asic.resources import ProcessCollection
from b_asic.scheduler import Scheduler
from b_asic.special_operations import Delay, Input, Output
_EXECUTION_TIME_COLOR: Tuple[float, ...] = tuple(
float(c / 255) for c in EXECUTION_TIME_COLOR
_LATENCY_COLOR: Tuple[float, ...] = tuple(float(c / 255) for c in LATENCY_COLOR)
_SIGNAL_COLOR: Tuple[float, ...] = tuple(float(c / 255) for c in SIGNAL_COLOR)
def _laps_default():
"""Default value for _laps. Cannot use lambda."""
return 0
def _y_locations_default():
"""Default value for _y_locations. Cannot use lambda."""
return None
"""
Schedule of an SFG with scheduled Operations.
Parameters
----------
sfg : :class:`~b_asic.signal_flow_graph.SFG`
scheduler : Scheduler, default: None
The automatic scheduler to be used.
The schedule time. If not provided, it will be determined by the scheduling
algorithm.
cyclic : bool, default: False
If the schedule is cyclic.
start_times : dict, optional
Dictionary with GraphIDs as keys and start times as values.
Used when *algorithm* is 'provided'.
laps : dict, optional
Dictionary with GraphIDs as keys and laps as values.
Used when *algorithm* is 'provided'.
Angus Lothian
committed
_sfg: SFG
_start_times: Dict[GraphID, int]
Angus Lothian
committed
_schedule_time: int
_cyclic: bool
_y_locations: Dict[GraphID, Optional[int]]
Angus Lothian
committed
scheduler: Optional[Scheduler] = None,
schedule_time: Optional[int] = None,
cyclic: bool = False,
start_times: Optional[Dict[GraphID, int]] = None,
laps: Optional[Dict[GraphID, int]] = None,
if not isinstance(sfg, SFG):
raise TypeError("An SFG must be provided")
Angus Lothian
committed
self._sfg = sfg
Angus Lothian
committed
self._cyclic = cyclic
self._y_locations = defaultdict(_y_locations_default)
self._schedule_time = schedule_time
if scheduler:
self._scheduler = scheduler
self._scheduler.apply_scheduling(self)
else:
if start_times is None:
raise ValueError("Must provide start_times when using 'provided'")
if laps is None:
raise ValueError("Must provide laps when using 'provided'")
self._start_times = start_times
self._laps.update(laps)
self._remove_delays_no_laps()
Angus Lothian
committed
if schedule_time is None:
self._schedule_time = max_end_time
elif schedule_time < max_end_time:
raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.")
Angus Lothian
committed
def start_time_of_operation(self, graph_id: GraphID) -> int:
Return the start time of the operation with the specified by *graph_id*.
Parameters
----------
graph_id : GraphID
The graph id of the operation to get the start time for.
if graph_id not in self._start_times:
raise ValueError(f"No operation with graph_id {graph_id!r} in schedule")
return self._start_times[graph_id]
Angus Lothian
committed
"""Return the current maximum end time among all operations."""
for graph_id, op_start_time in self._start_times.items():
operation = cast(Operation, self._sfg.find_by_id(graph_id))
for outport in operation.outputs:
max_end_time,
op_start_time + cast(int, outport.latency_offset),
def forward_slack(self, graph_id: GraphID) -> int:
Return how much an operation can be moved forward in time.
graph_id : GraphID
The graph id of the operation.
The number of time steps the operation with *graph_id* can be moved
if graph_id not in self._start_times:
raise ValueError(f"No operation with graph_id {graph_id!r} in schedule")
output_slacks = self._forward_slacks(graph_id)
return cast(
int,
min(
sum(
(
list(signal_slacks.values())
for signal_slacks in output_slacks.values()
),
[sys.maxsize],
)
),
self, graph_id: GraphID
start_time = self._start_times[graph_id]
operation = cast(Operation, self._sfg.find_by_id(graph_id))
for output_port in operation.outputs:
ret[output_port] = self._output_slacks(output_port, start_time)
Angus Lothian
committed
def _output_slacks(
self, output_port: "OutputPort", start_time: Optional[int] = None
) -> Dict[Signal, int]:
Loading
Loading full blame...