Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
B-ASIC - Better ASIC Toolbox
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Computer Engineering
B-ASIC - Better ASIC Toolbox
Commits
97342c36
Commit
97342c36
authored
4 months ago
by
Simon Bjurek
Browse files
Options
Downloads
Patches
Plain Diff
moved alap and asap to seperate class and changed some of the code
parent
6fd1f5f9
No related branches found
No related tags found
2 merge requests
!461
Finalize earliest deadline scheduler
,
!459
Qt6 fixes and scheduler class started
Pipeline
#154511
failed
4 months ago
Stage: test
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
b_asic/schedule.py
+266
-120
266 additions, 120 deletions
b_asic/schedule.py
b_asic/scheduling_algorithm.py
+8
-0
8 additions, 0 deletions
b_asic/scheduling_algorithm.py
with
274 additions
and
120 deletions
b_asic/schedule.py
+
266
−
120
View file @
97342c36
...
...
@@ -36,6 +36,7 @@ from b_asic.resources import ProcessCollection
from
b_asic.signal_flow_graph
import
SFG
from
b_asic.special_operations
import
Delay
,
Input
,
Output
from
b_asic.types
import
TypeName
from
b_asic.scheduling_algorithm
import
SchedAlg
# Need RGB from 0 to 1
_EXECUTION_TIME_COLOR
:
Tuple
[
float
,
...]
=
tuple
(
...
...
@@ -68,13 +69,8 @@ class Schedule:
algorithm.
cyclic : bool, default: False
If the schedule is cyclic.
algorithm : {
'
ASAP
'
,
'
ALAP
'
,
'
provided
'
}, default:
'
ASAP
'
The scheduling algorithm to use. The following algorithm are available:
* ``
'
ASAP
'
``: As-soon-as-possible scheduling.
* ``
'
ALAP
'
``: As-late-as-possible scheduling.
If
'
provided
'
, use provided *start_times* and *laps* dictionaries.
algorithm : SchedulingAlgorithm, default:
'
ASAP
'
The scheduling algorithm to use.
start_times : dict, optional
Dictionary with GraphIDs as keys and start times as values.
Used when *algorithm* is
'
provided
'
.
...
...
@@ -100,7 +96,7 @@ class Schedule:
sfg
:
SFG
,
schedule_time
:
Optional
[
int
]
=
None
,
cyclic
:
bool
=
False
,
algorithm
:
Literal
[
"
ASAP
"
,
"
ALAP
"
,
"
provided
"
]
=
"
ASAP
"
,
algorithm
:
SchedAlg
=
"
ASAP
"
,
start_times
:
Optional
[
Dict
[
GraphID
,
int
]]
=
None
,
laps
:
Optional
[
Dict
[
GraphID
,
int
]]
=
None
,
max_resources
:
Optional
[
Dict
[
TypeName
,
int
]]
=
None
,
...
...
@@ -115,10 +111,14 @@ class Schedule:
self
.
_cyclic
=
cyclic
self
.
_y_locations
=
defaultdict
(
_y_locations_default
)
self
.
_schedule_time
=
schedule_time
self
.
scheduler
=
Scheduler
(
self
)
if
algorithm
==
"
ASAP
"
:
self
.
_
schedule_asap
()
self
.
scheduler
.
schedule_asap
()
elif
algorithm
==
"
ALAP
"
:
self
.
_schedule_alap
()
self
.
scheduler
.
schedule_alap
()
elif
algorithm
==
"
earliest_deadline
"
:
self
.
scheduler
.
schedule_earliest_deadline
()
elif
algorithm
==
"
provided
"
:
if
start_times
is
None
:
raise
ValueError
(
"
Must provide start_times when using
'
provided
'"
)
...
...
@@ -797,116 +797,116 @@ class Schedule:
new_sfg
=
new_sfg
.
insert_operation_before
(
op
,
Delay
(),
port
)
return
new_sfg
()
def
_schedule_alap
(
self
)
->
None
:
"""
Schedule the operations using as-late-as-possible scheduling.
"""
precedence_list
=
self
.
_sfg
.
get_precedence_list
()
self
.
_schedule_asap
()
max_end_time
=
self
.
get_max_end_time
()
if
self
.
schedule_time
is
None
:
self
.
_schedule_time
=
max_end_time
elif
self
.
schedule_time
<
max_end_time
:
raise
ValueError
(
f
"
Too short schedule time. Minimum is
{
max_end_time
}
.
"
)
for
output
in
self
.
_sfg
.
find_by_type_name
(
Output
.
type_name
()):
output
=
cast
(
Output
,
output
)
self
.
move_operation_alap
(
output
.
graph_id
)
for
step
in
reversed
(
precedence_list
):
graph_ids
=
{
outport
.
operation
.
graph_id
for
outport
in
step
if
not
isinstance
(
outport
.
operation
,
Delay
)
}
for
graph_id
in
graph_ids
:
self
.
move_operation_alap
(
graph_id
)
def
_schedule_asap
(
self
)
->
None
:
"""
Schedule the operations using as-soon-as-possible scheduling.
"""
precedence_list
=
self
.
_sfg
.
get_precedence_list
()
if
len
(
precedence_list
)
<
2
:
raise
ValueError
(
"
Empty signal flow graph cannot be scheduled.
"
)
non_schedulable_ops
=
set
()
for
outport
in
precedence_list
[
0
]:
operation
=
outport
.
operation
if
operation
.
type_name
()
not
in
[
Delay
.
type_name
()]:
if
operation
.
graph_id
not
in
self
.
_start_times
:
# Set start time of all operations in the first iter to 0
self
.
_start_times
[
operation
.
graph_id
]
=
0
else
:
non_schedulable_ops
.
add
(
operation
.
graph_id
)
for
outport
in
precedence_list
[
1
]:
operation
=
outport
.
operation
if
operation
.
graph_id
not
in
self
.
_start_times
:
# Set start time of all operations in the first iter to 0
self
.
_start_times
[
operation
.
graph_id
]
=
0
for
outports
in
precedence_list
[
2
:]:
for
outport
in
outports
:
operation
=
outport
.
operation
if
operation
.
graph_id
not
in
self
.
_start_times
:
# Schedule the operation if it does not have a start time yet.
op_start_time
=
0
for
current_input
in
operation
.
inputs
:
if
len
(
current_input
.
signals
)
!=
1
:
raise
ValueError
(
"
Error in scheduling, dangling input port detected.
"
)
if
current_input
.
signals
[
0
].
source
is
None
:
raise
ValueError
(
"
Error in scheduling, signal with no source detected.
"
)
source_port
=
current_input
.
signals
[
0
].
source
if
source_port
.
operation
.
graph_id
in
non_schedulable_ops
:
source_end_time
=
0
else
:
source_op_time
=
self
.
_start_times
[
source_port
.
operation
.
graph_id
]
if
source_port
.
latency_offset
is
None
:
raise
ValueError
(
f
"
Output port
{
source_port
.
index
}
of
"
"
operation
"
f
"
{
source_port
.
operation
.
graph_id
}
has no
"
"
latency-offset.
"
)
source_end_time
=
(
source_op_time
+
source_port
.
latency_offset
)
if
current_input
.
latency_offset
is
None
:
raise
ValueError
(
f
"
Input port
{
current_input
.
index
}
of operation
"
f
"
{
current_input
.
operation
.
graph_id
}
has no
"
"
latency-offset.
"
)
op_start_time_from_in
=
(
source_end_time
-
current_input
.
latency_offset
)
op_start_time
=
max
(
op_start_time
,
op_start_time_from_in
)
self
.
_start_times
[
operation
.
graph_id
]
=
op_start_time
for
output
in
self
.
_sfg
.
find_by_type_name
(
Output
.
type_name
()):
output
=
cast
(
Output
,
output
)
source_port
=
cast
(
OutputPort
,
output
.
inputs
[
0
].
signals
[
0
].
source
)
if
source_port
.
operation
.
graph_id
in
non_schedulable_ops
:
self
.
_start_times
[
output
.
graph_id
]
=
0
else
:
if
source_port
.
latency_offset
is
None
:
raise
ValueError
(
f
"
Output port
{
source_port
.
index
}
of operation
"
f
"
{
source_port
.
operation
.
graph_id
}
has no
"
"
latency-offset.
"
)
self
.
_start_times
[
output
.
graph_id
]
=
self
.
_start_times
[
source_port
.
operation
.
graph_id
]
+
cast
(
int
,
source_port
.
latency_offset
)
self
.
_remove_delays
()
#
def _schedule_alap(self) -> None:
#
"""Schedule the operations using as-late-as-possible scheduling."""
#
precedence_list = self._sfg.get_precedence_list()
#
self._schedule_asap()
#
max_end_time = self.get_max_end_time()
#
if self.schedule_time is None:
#
self._schedule_time = max_end_time
#
elif self.schedule_time < max_end_time:
#
raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.")
#
for output in self._sfg.find_by_type_name(Output.type_name()):
#
output = cast(Output, output)
#
self.move_operation_alap(output.graph_id)
#
for step in reversed(precedence_list):
#
graph_ids = {
#
outport.operation.graph_id
#
for outport in step
#
if not isinstance(outport.operation, Delay)
#
}
#
for graph_id in graph_ids:
#
self.move_operation_alap(graph_id)
#
def _schedule_asap(self) -> None:
#
"""Schedule the operations using as-soon-as-possible scheduling."""
#
precedence_list = self._sfg.get_precedence_list()
#
if len(precedence_list) < 2:
#
raise ValueError("Empty signal flow graph cannot be scheduled.")
#
non_schedulable_ops = set()
#
for outport in precedence_list[0]:
#
operation = outport.operation
#
if operation.type_name() not in [Delay.type_name()]:
#
if operation.graph_id not in self._start_times:
#
# Set start time of all operations in the first iter to 0
#
self._start_times[operation.graph_id] = 0
#
else:
#
non_schedulable_ops.add(operation.graph_id)
#
for outport in precedence_list[1]:
#
operation = outport.operation
#
if operation.graph_id not in self._start_times:
#
# Set start time of all operations in the first iter to 0
#
self._start_times[operation.graph_id] = 0
#
for outports in precedence_list[2:]:
#
for outport in outports:
#
operation = outport.operation
#
if operation.graph_id not in self._start_times:
#
# Schedule the operation if it does not have a start time yet.
#
op_start_time = 0
#
for current_input in operation.inputs:
#
if len(current_input.signals) != 1:
#
raise ValueError(
#
"Error in scheduling, dangling input port detected."
#
)
#
if current_input.signals[0].source is None:
#
raise ValueError(
#
"Error in scheduling, signal with no source detected."
#
)
#
source_port = current_input.signals[0].source
#
if source_port.operation.graph_id in non_schedulable_ops:
#
source_end_time = 0
#
else:
#
source_op_time = self._start_times[
#
source_port.operation.graph_id
#
]
#
if source_port.latency_offset is None:
#
raise ValueError(
#
f"Output port {source_port.index} of"
#
" operation"
#
f" {source_port.operation.graph_id} has no"
#
" latency-offset."
#
)
#
source_end_time = (
#
source_op_time + source_port.latency_offset
#
)
#
if current_input.latency_offset is None:
#
raise ValueError(
#
f"Input port {current_input.index} of operation"
#
f" {current_input.operation.graph_id} has no"
#
" latency-offset."
#
)
#
op_start_time_from_in = (
#
source_end_time - current_input.latency_offset
#
)
#
op_start_time = max(op_start_time, op_start_time_from_in)
#
self._start_times[operation.graph_id] = op_start_time
#
for output in self._sfg.find_by_type_name(Output.type_name()):
#
output = cast(Output, output)
#
source_port = cast(OutputPort, output.inputs[0].signals[0].source)
#
if source_port.operation.graph_id in non_schedulable_ops:
#
self._start_times[output.graph_id] = 0
#
else:
#
if source_port.latency_offset is None:
#
raise ValueError(
#
f"Output port {source_port.index} of operation"
#
f" {source_port.operation.graph_id} has no"
#
" latency-offset."
#
)
#
self._start_times[output.graph_id] = self._start_times[
#
source_port.operation.graph_id
#
] + cast(int, source_port.latency_offset)
#
self._remove_delays()
def
_get_memory_variables_list
(
self
)
->
List
[
MemoryVariable
]:
ret
:
List
[
MemoryVariable
]
=
[]
...
...
@@ -1227,3 +1227,149 @@ class Schedule:
# SVG is valid HTML. This is useful for e.g. sphinx-gallery
_repr_html_
=
_repr_svg_
class
Scheduler
():
def
__init__
(
self
,
schedule
:
Schedule
)
->
None
:
self
.
schedule
=
schedule
def
schedule_asap
(
self
)
->
None
:
"""
Schedule the operations using as-soon-as-possible scheduling.
"""
sched
=
self
.
schedule
prec_list
=
sched
.
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
sched
.
_start_times
:
sched
.
_start_times
[
operation
.
graph_id
]
=
0
# handle second set in precedence graph (first operations)
for
outport
in
prec_list
[
1
]:
operation
=
outport
.
operation
if
operation
.
graph_id
not
in
sched
.
_start_times
:
sched
.
_start_times
[
operation
.
graph_id
]
=
0
# handle the remaining sets
for
outports
in
prec_list
[
2
:]:
for
outport
in
outports
:
operation
=
outport
.
operation
if
operation
.
graph_id
not
in
sched
.
_start_times
:
op_start_time
=
0
for
current_input
in
operation
.
inputs
:
if
len
(
current_input
.
signals
)
!=
1
:
raise
ValueError
(
"
Error in scheduling, dangling input port detected.
"
)
if
current_input
.
signals
[
0
].
source
is
None
:
raise
ValueError
(
"
Error in scheduling, signal with no source detected.
"
)
source_port
=
current_input
.
signals
[
0
].
source
if
source_port
.
operation
.
graph_id
in
non_schedulable_ops
:
source_end_time
=
0
else
:
source_op_time
=
sched
.
_start_times
[
source_port
.
operation
.
graph_id
]
if
source_port
.
latency_offset
is
None
:
raise
ValueError
(
f
"
Output port
{
source_port
.
index
}
of
"
"
operation
"
f
"
{
source_port
.
operation
.
graph_id
}
has no
"
"
latency-offset.
"
)
source_end_time
=
(
source_op_time
+
source_port
.
latency_offset
)
if
current_input
.
latency_offset
is
None
:
raise
ValueError
(
f
"
Input port
{
current_input
.
index
}
of operation
"
f
"
{
current_input
.
operation
.
graph_id
}
has no
"
"
latency-offset.
"
)
op_start_time_from_in
=
(
source_end_time
-
current_input
.
latency_offset
)
op_start_time
=
max
(
op_start_time
,
op_start_time_from_in
)
sched
.
_start_times
[
operation
.
graph_id
]
=
op_start_time
# handle output and remove delays
for
output
in
sched
.
_sfg
.
find_by_type_name
(
Output
.
type_name
()):
output
=
cast
(
Output
,
output
)
source_port
=
cast
(
OutputPort
,
output
.
inputs
[
0
].
signals
[
0
].
source
)
if
source_port
.
operation
.
graph_id
in
non_schedulable_ops
:
sched
.
_start_times
[
output
.
graph_id
]
=
0
else
:
if
source_port
.
latency_offset
is
None
:
raise
ValueError
(
f
"
Output port
{
source_port
.
index
}
of operation
"
f
"
{
source_port
.
operation
.
graph_id
}
has no
"
"
latency-offset.
"
)
sched
.
_start_times
[
output
.
graph_id
]
=
sched
.
_start_times
[
source_port
.
operation
.
graph_id
]
+
cast
(
int
,
source_port
.
latency_offset
)
sched
.
_remove_delays
()
def
schedule_alap
(
self
)
->
None
:
"""
Schedule the operations using as-late-as-possible scheduling.
"""
self
.
schedule_asap
()
sched
=
self
.
schedule
max_end_time
=
sched
.
get_max_end_time
()
if
sched
.
schedule_time
is
None
:
sched
.
set_schedule_time
(
max_end_time
)
elif
sched
.
schedule_time
<
max_end_time
:
raise
ValueError
(
f
"
Too short schedule time. Minimum is
{
max_end_time
}
.
"
)
# move all outputs ALAP before operations
for
output
in
sched
.
sfg
.
find_by_type_name
(
Output
.
type_name
()):
output
=
cast
(
Output
,
output
)
sched
.
move_operation_alap
(
output
.
graph_id
)
# move all operations ALAP
for
step
in
reversed
(
sched
.
sfg
.
get_precedence_list
()):
for
outport
in
step
:
if
not
isinstance
(
outport
.
operation
,
Delay
):
sched
.
move_operation_alap
(
outport
.
operation
.
graph_id
)
def
schedule_earliest_deadline
(
self
)
->
None
:
"""
Schedule the operations using earliest deadline scheduling.
"""
pass
# sched = self.schedule
# prec_list = sched.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 sched._start_times:
# sched._start_times[operation.graph_id] = 0
# # handle second set in precedence graph (first operations)
# for outport in prec_list[1]:
# operation = outport.operation
# if operation.graph_id not in sched._start_times:
# sched._start_times[operation.graph_id] = 0
# # handle the remaining sets
# for outports in prec_list[2:]:
# for outport in outports:
# operation = outport.operation
# if operation.graph_id not in sched._start_times:
# pass
\ No newline at end of file
This diff is collapsed.
Click to expand it.
b_asic/scheduling_algorithm.py
0 → 100644
+
8
−
0
View file @
97342c36
from
enum
import
Enum
class
SchedAlg
(
Enum
):
ASAP
=
"
ASAP
"
ALAP
=
"
ALAP
"
EARLIEST_DEADLINE
=
"
earliest_deadline
"
LEAST_SLACK
=
"
least_slack
"
PROVIDED
=
"
provided
"
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment