Skip to content
Snippets Groups Projects
Commit 87268b64 authored by Simon Bjurek's avatar Simon Bjurek
Browse files

seems like its working for execution time 1

parent d5935e9d
No related branches found
No related tags found
1 merge request!461Finalize earliest deadline scheduler
from abc import ABC, abstractmethod
from collections import defaultdict
from typing import TYPE_CHECKING, Optional, cast
from b_asic.port import OutputPort
from b_asic.special_operations import Delay, Output
from b_asic.special_operations import Delay, Input, Output
from b_asic.types import TypeName
if TYPE_CHECKING:
......@@ -21,7 +22,7 @@ class Scheduler(ABC):
"""
pass
def _handle_outputs(self, schedule, non_schedulable_ops) -> None:
def _handle_outputs(self, schedule, non_schedulable_ops=set()) -> None:
for output in schedule.sfg.find_by_type_name(Output.type_name()):
output = cast(Output, output)
source_port = cast(OutputPort, output.inputs[0].signals[0].source)
......@@ -165,8 +166,11 @@ class EarliestDeadlineScheduler(Scheduler):
resource is used.
"""
def __init__(self, max_resources: Optional[dict[TypeName, int]]) -> None:
self._max_resources = max_resources
def __init__(self, max_resources: Optional[dict[TypeName, int]] = None) -> None:
if max_resources:
self._max_resources = max_resources
else:
self._max_resources = {}
def apply_scheduling(self, schedule: "Schedule") -> None:
"""Applies the scheduling algorithm on the given Schedule.
......@@ -176,50 +180,76 @@ class EarliestDeadlineScheduler(Scheduler):
schedule : Schedule
Schedule to apply the scheduling algorithm on.
"""
# ACT BASED ON THE NUMBER OF PEs!
prec_list = schedule.sfg.get_precedence_list()
if len(prec_list) < 2:
raise ValueError("Empty signal flow graph cannot be scheduled.")
# handle the first set in precedence graph (input and delays)
non_schedulable_ops = set()
for outport in prec_list[0]:
operation = outport.operation
if operation.type_name() == Delay.type_name():
non_schedulable_ops.add(operation.graph_id)
elif operation.graph_id not in schedule.start_times:
schedule.start_times[operation.graph_id] = 0
# TODO: Take the execution time into consideration!
ALAPScheduler().apply_scheduling(schedule)
# move all inputs ASAP to ensure correct operation
for input_op in schedule.sfg.find_by_type_name(Input.type_name()):
input_op = cast(Input, input_op)
schedule.move_operation_asap(input_op.graph_id)
remaining_ops = set(schedule.start_times.keys())
remaining_ops = {elem for elem in remaining_ops if not elem.startswith("in")}
remaining_resources = self._max_resources.copy()
current_time = 0
sorted_outports = sorted(
prec_list[1], key=lambda outport: outport.operation.latency
)
for outport in sorted_outports:
op = outport.operation
schedule.start_times[op.graph_id] = current_time
current_time += 1
while remaining_ops:
best_candidate = self._find_best_candidate(
schedule, remaining_ops, remaining_resources, current_time
)
if not best_candidate:
current_time += 1
remaining_resources = self._max_resources.copy()
continue
# update remaining resources
if best_candidate.type_name() in remaining_resources:
remaining_resources[best_candidate.type_name()] -= 1
remaining_ops.remove(best_candidate.graph_id)
schedule.start_times[best_candidate.graph_id] = current_time
# move all inputs and outputs ALAP now that operations have moved
for input_op in schedule.sfg.find_by_type_name(Input.type_name()):
input_op = cast(Input, input_op)
schedule.move_operation_alap(input_op.graph_id)
self._handle_outputs(schedule)
@staticmethod
def _find_best_candidate(
schedule, remaining_ops, remaining_resources, current_time
):
# precompute source end times for faster checks
sfg = schedule.sfg
source_end_times = defaultdict(float)
for op_id in remaining_ops:
operation = sfg.find_by_id(op_id)
for op_input in operation.inputs:
source_op = op_input.signals[0].source.operation
if not isinstance(source_op, Delay):
source_end_times[op_id] = max(
source_end_times[op_id],
schedule.start_times[source_op.graph_id] + source_op.latency,
)
for outports in prec_list[2:]:
current_time -= 1
for outport in outports:
op = outport.operation
candidates = []
while not candidates:
current_time += 1
op_is_ready_to_be_scheduled = True
for op_input in op.inputs:
source_op = op_input.signals[0].source.operation
source_op_time = schedule.start_times[source_op.graph_id]
source_end_time = source_op_time + source_op.latency
if source_end_time > current_time:
op_is_ready_to_be_scheduled = False
if op_is_ready_to_be_scheduled:
candidates.append(op)
sorted_candidates = sorted(
candidates, key=lambda candidate: candidate.latency
)
# schedule the best candidate to current time
schedule.start_times[sorted_candidates[0].graph_id] = current_time
best_candidate = None
best_deadline = float('inf')
for op_id in remaining_ops:
operation = sfg.find_by_id(op_id)
self._handle_outputs(schedule, non_schedulable_ops)
schedule.remove_delays()
# check resource constraints
if operation.type_name() in remaining_resources:
if remaining_resources[operation.type_name()] == 0:
continue
# check if all inputs are available
if source_end_times[op_id] <= current_time:
operation_deadline = schedule.start_times[op_id] + operation.latency
if operation_deadline < best_deadline:
best_candidate = operation
best_deadline = operation_deadline
return best_candidate
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment