From cf6e58082d8cb1b5c595467cbd34ef0be7bebddc Mon Sep 17 00:00:00 2001 From: Oscar Gustafsson <oscar.gustafsson@gmail.com> Date: Thu, 16 Feb 2023 10:15:45 +0100 Subject: [PATCH] Fix resource-related issues --- b_asic/process.py | 62 ++++++++++---- b_asic/research/interleaver.py | 44 ++++++---- b_asic/resources.py | 78 +++++++++++------- .../test_draw_matrix_transposer_4.png | Bin 0 -> 21399 bytes .../baseline/test_draw_process_collection.png | Bin 10292 -> 15052 bytes test/fixtures/resources.py | 9 +- test/test_resources.py | 32 ++++++- 7 files changed, 153 insertions(+), 72 deletions(-) create mode 100644 test/baseline/test_draw_matrix_transposer_4.png diff --git a/b_asic/process.py b/b_asic/process.py index d48fa0ee..8d7e7620 100644 --- a/b_asic/process.py +++ b/b_asic/process.py @@ -20,11 +20,20 @@ class Process: Start time of process. execution_time : int Execution time (lifetime) of process. + name : str, optional + The name of the process. If not provided, generate a name. """ - def __init__(self, start_time: int, execution_time: int): + def __init__( + self, start_time: int, execution_time: int, name: Optional[str] = None + ): self._start_time = start_time self._execution_time = execution_time + if name is None: + self._name = f"Proc. {PlainMemoryVariable._name_cnt}" + PlainMemoryVariable._name_cnt += 1 + else: + self._name = name def __lt__(self, other): return self._start_time < other.start_time or ( @@ -42,6 +51,16 @@ class Process: """Return the execution time.""" return self._execution_time + @property + def name(self) -> str: + return self._name + + def __str__(self) -> str: + return self._name + + # Static counter for default names + _name_cnt = 0 + class OperatorProcess(Process): """ @@ -53,16 +72,27 @@ class OperatorProcess(Process): Start time of process. operation : Operation Operation that the process corresponds to. + name : str, optional + The name of the process. """ - def __init__(self, start_time: int, operation: Operation): + def __init__( + self, + start_time: int, + operation: Operation, + name: Optional[str] = None, + ): execution_time = operation.execution_time if execution_time is None: raise ValueError( "Operation {operation!r} does not have an execution time" " specified!" ) - super().__init__(start_time, execution_time) + super().__init__( + start_time, + execution_time, + name=name, + ) self._operation = operation @@ -80,6 +110,8 @@ class MemoryVariable(Process): reads : {InputPort: int, ...} Dictionary with the InputPorts that reads the memory variable and for how long after the *write_time* they will read. + name : str, optional + The name of the process. """ def __init__( @@ -87,12 +119,15 @@ class MemoryVariable(Process): write_time: int, write_port: OutputPort, reads: Dict[InputPort, int], + name: Optional[str] = None, ): self._read_ports = tuple(reads.keys()) self._life_times = tuple(reads.values()) self._write_port = write_port super().__init__( - start_time=write_time, execution_time=max(self._life_times) + start_time=write_time, + execution_time=max(self._life_times), + name=name, ) @property @@ -123,6 +158,8 @@ class PlainMemoryVariable(Process): reads : {int: int, ...} Dictionary where the key is the destination identifier and the value is the time after *write_time* that the memory variable is read. + name : str, optional + The name of the process. """ def __init__( @@ -135,11 +172,10 @@ class PlainMemoryVariable(Process): self._read_ports = tuple(reads.keys()) self._life_times = tuple(reads.values()) self._write_port = write_port - if name is None: - self._name = str(PlainMemoryVariable._name_cnt) - PlainMemoryVariable._name_cnt += 1 super().__init__( - start_time=write_time, execution_time=max(self._life_times) + start_time=write_time, + execution_time=max(self._life_times), + name=name, ) @property @@ -153,13 +189,3 @@ class PlainMemoryVariable(Process): @property def write_port(self) -> int: return self._write_port - - @property - def name(self) -> str: - return self._name - - def __str__(self) -> str: - return self._name - - # Static counter for default names - _name_cnt = 0 diff --git a/b_asic/research/interleaver.py b/b_asic/research/interleaver.py index 83eb4b3b..b64a79b9 100644 --- a/b_asic/research/interleaver.py +++ b/b_asic/research/interleaver.py @@ -6,6 +6,7 @@ import random from typing import Optional, Set from b_asic.process import PlainMemoryVariable +from b_asic.resources import ProcessCollection def _insert_delays(inputorder, outputorder, min_lifetime, cyclic): @@ -14,9 +15,7 @@ def _insert_delays(inputorder, outputorder, min_lifetime, cyclic): outputorder = [o - maxdiff + min_lifetime for o in outputorder] maxdelay = max(outputorder[i] - inputorder[i] for i in range(size)) if cyclic: - if maxdelay < size: - outputorder = [o % size for o in outputorder] - else: + if maxdelay >= size: inputorder = inputorder + [i + size for i in inputorder] outputorder = outputorder + [o + size for o in outputorder] return inputorder, outputorder @@ -24,7 +23,7 @@ def _insert_delays(inputorder, outputorder, min_lifetime, cyclic): def generate_random_interleaver( size: int, min_lifetime: int = 0, cyclic: bool = True -) -> Set[PlainMemoryVariable]: +) -> ProcessCollection: """ Generate a ProcessCollection with memory variable corresponding to a random interleaver with length *size*. @@ -48,15 +47,19 @@ def generate_random_interleaver( inputorder = list(range(size)) outputorder = inputorder[:] random.shuffle(outputorder) - print(inputorder, outputorder) inputorder, outputorder = _insert_delays( inputorder, outputorder, min_lifetime, cyclic ) - print(inputorder, outputorder) - return { - PlainMemoryVariable(inputorder[i], 0, {0: outputorder[i]}) - for i in range(size) - } + return ProcessCollection( + { + PlainMemoryVariable( + inputorder[i], 0, {0: outputorder[i] - inputorder[i]} + ) + for i in range(len(inputorder)) + }, + len(inputorder), + cyclic, + ) def generate_matrix_transposer( @@ -64,7 +67,7 @@ def generate_matrix_transposer( width: Optional[int] = None, min_lifetime: int = 0, cyclic: bool = True, -) -> Set[PlainMemoryVariable]: +) -> ProcessCollection: r""" Generate a ProcessCollection with memory variable corresponding to transposing a matrix of size *height* :math:`\times` *width*. If *width* is not provided, a @@ -101,12 +104,19 @@ def generate_matrix_transposer( for col in range(height): outputorder.append(col * width + row) - print(inputorder, outputorder) inputorder, outputorder = _insert_delays( inputorder, outputorder, min_lifetime, cyclic ) - print(inputorder, outputorder) - return { - PlainMemoryVariable(inputorder[i], 0, {0: outputorder[i]}) - for i in range(width * height) - } + return ProcessCollection( + { + PlainMemoryVariable( + inputorder[i], + 0, + {0: outputorder[i] - inputorder[i]}, + name=f"{inputorder[i]}", + ) + for i in range(len(inputorder)) + }, + len(inputorder), + cyclic, + ) diff --git a/b_asic/resources.py b/b_asic/resources.py index eaed928f..c91047b2 100644 --- a/b_asic/resources.py +++ b/b_asic/resources.py @@ -1,3 +1,4 @@ +import re from typing import Dict, List, Optional, Set, Tuple, Union import matplotlib.pyplot as plt @@ -8,6 +9,16 @@ from matplotlib.ticker import MaxNLocator from b_asic.process import Process +# From https://stackoverflow.com/questions/2669059/how-to-sort-alpha-numeric-set-in-python +def _sorted_nicely(to_be_sorted): + """Sort the given iterable in the way that humans expect.""" + convert = lambda text: int(text) if text.isdigit() else text + alphanum_key = lambda key: [ + convert(c) for c in re.split('([0-9]+)', str(key)) + ] + return sorted(to_be_sorted, key=alphanum_key) + + def draw_exclusion_graph_coloring( exclusion_graph: nx.Graph, color_dict: Dict[Process, int], @@ -79,14 +90,23 @@ class ProcessCollection: Parameters ---------- - collection : set of :class:`~b_asic.process.Process` objects, optional + collection : set of :class:`~b_asic.process.Process` objects + The Process objects forming this ProcessCollection. + schedule_time : int, default: 0 + Length of the time-axis in the generated graph. + cyclic : bool, default: False + If the processes operates cyclically, i.e., if time 0 == time *schedule_time*. """ - def __init__(self, collection: Optional[Set[Process]] = None): - if collection is None: - self._collection: Set[Process] = set() - else: - self._collection = collection + def __init__( + self, + collection: Set[Process], + schedule_time: int, + cyclic: bool = False, + ): + self._collection = collection + self._schedule_time = schedule_time + self._cyclic = cyclic def add_process(self, process: Process): """ @@ -101,7 +121,6 @@ class ProcessCollection: def draw_lifetime_chart( self, - schedule_time: int = 0, ax: Optional[Axes] = None, show_name: bool = True, ): @@ -110,9 +129,6 @@ class ProcessCollection: Parameters ---------- - schedule_time : int, default: 0 - Length of the time-axis in the generated graph. The time axis will span [0, schedule_time-1]. - If set to zero (which is the default), the ... ax : :class:`matplotlib.axes.Axes`, optional Matplotlib Axes object to draw this lifetime chart onto. If not provided (i.e., set to None), this will return a new axes object on return. @@ -133,26 +149,19 @@ class ProcessCollection: # Draw the lifetime chart PAD_L, PAD_R = 0.05, 0.05 max_execution_time = max( - [process.execution_time for process in self._collection] + process.execution_time for process in self._collection ) - schedule_time = ( - schedule_time - if schedule_time - else max(p.start_time + p.execution_time for p in self._collection) - ) - if max_execution_time > schedule_time: + if max_execution_time > self._schedule_time: # Schedule time needs to be greater than or equal to the maximum process life time raise KeyError( - f'Error: Schedule time: {schedule_time} < Max execution time:' - f' {max_execution_time}' + f'Error: Schedule time: {self._schedule_time} < Max execution' + f' time: {max_execution_time}' ) - for i, process in enumerate( - sorted(self._collection, key=lambda p: str(p)) - ): - bar_start = process.start_time % schedule_time + for i, process in enumerate(_sorted_nicely(self._collection)): + bar_start = process.start_time % self._schedule_time bar_end = ( process.start_time + process.execution_time - ) % schedule_time + ) % self._schedule_time if bar_end > bar_start: _ax.broken_barh( [(PAD_L + bar_start, bar_end - bar_start - PAD_L - PAD_R)], @@ -164,7 +173,7 @@ class ProcessCollection: [ ( PAD_L + bar_start, - schedule_time - bar_start - PAD_L, + self._schedule_time - bar_start - PAD_L, ) ], (i + 0.55, 0.9), @@ -175,7 +184,10 @@ class ProcessCollection: [ ( PAD_L + bar_start, - schedule_time - bar_start - PAD_L - PAD_R, + self._schedule_time + - bar_start + - PAD_L + - PAD_R, ) ], (i + 0.55, 0.9), @@ -190,6 +202,8 @@ class ProcessCollection: _ax.xaxis.set_major_locator(MaxNLocator(integer=True)) _ax.yaxis.set_major_locator(MaxNLocator(integer=True)) + _ax.set_xlim(0, self._schedule_time) + _ax.set_ylim(0.25, len(self._collection) + 0.75) return _ax def create_exclusion_graph_from_overlap( @@ -332,12 +346,14 @@ class ProcessCollection: coloring = nx.coloring.greedy_color(exclusion_graph) draw_exclusion_graph_coloring(exclusion_graph, coloring) # process_collection_list = [ProcessCollection()]*(max(coloring.values()) + 1) - process_collection_list = [ - ProcessCollection() for _ in range(max(coloring.values()) + 1) + process_collection_set_list = [ + set() for _ in range(max(coloring.values()) + 1) ] for process, color in coloring.items(): - process_collection_list[color].add_process(process) + process_collection_set_list[color].add(process) return { - process_collection - for process_collection in process_collection_list + ProcessCollection( + process_collection_set, self._schedule_time, self._cyclic + ) + for process_collection_set in process_collection_set_list } diff --git a/test/baseline/test_draw_matrix_transposer_4.png b/test/baseline/test_draw_matrix_transposer_4.png new file mode 100644 index 0000000000000000000000000000000000000000..962fc776b73b1096b8d6080fce8d88a380f52c60 GIT binary patch literal 21399 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 P>?PJ7c3`#t!IS?01KyKd literal 0 HcmV?d00001 diff --git a/test/baseline/test_draw_process_collection.png b/test/baseline/test_draw_process_collection.png index 0ab1996784015b6d0bc3e5bc68e0f3ae21c64d94..87a5bf7fd1ce3055f5cc993ab684c560ef06e4b5 100644 GIT binary patch literal 15052 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 literal 10292 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 diff --git a/test/fixtures/resources.py b/test/fixtures/resources.py index 6317e4cb..61c8db25 100644 --- a/test/fixtures/resources.py +++ b/test/fixtures/resources.py @@ -16,12 +16,13 @@ def simple_collection(): PlainMemoryVariable(0, NO_PORT, {NO_PORT: 3}), PlainMemoryVariable(0, NO_PORT, {NO_PORT: 2}), PlainMemoryVariable(0, NO_PORT, {NO_PORT: 6}), - } + }, + 8, ) @pytest.fixture() -def collection(): +def cyclic_simple_collection(): NO_PORT = 0 return ProcessCollection( { @@ -32,5 +33,7 @@ def collection(): PlainMemoryVariable(0, NO_PORT, {NO_PORT: 3}), PlainMemoryVariable(0, NO_PORT, {NO_PORT: 2}), PlainMemoryVariable(0, NO_PORT, {NO_PORT: 6}), - } + }, + 6, + True, ) diff --git a/test/test_resources.py b/test/test_resources.py index 67f20cc9..10e401ad 100644 --- a/test/test_resources.py +++ b/test/test_resources.py @@ -2,8 +2,11 @@ import matplotlib.pyplot as plt import networkx as nx import pytest -from b_asic.process import PlainMemoryVariable -from b_asic.resources import ProcessCollection, draw_exclusion_graph_coloring +from b_asic.research.interleaver import ( + generate_matrix_transposer, + generate_random_interleaver, +) +from b_asic.resources import draw_exclusion_graph_coloring class TestProcessCollectionPlainMemoryVariable: @@ -15,7 +18,7 @@ class TestProcessCollectionPlainMemoryVariable: def test_draw_proces_collection(self, simple_collection): _, ax = plt.subplots(1, 2) - simple_collection.draw_lifetime_chart(schedule_time=8, ax=ax[0]) + simple_collection.draw_lifetime_chart(ax=ax[0]) exclusion_graph = ( simple_collection.create_exclusion_graph_from_overlap() ) @@ -27,3 +30,26 @@ class TestProcessCollectionPlainMemoryVariable: read_ports=1, write_ports=1, total_ports=2 ) assert len(collection_split) == 3 + + @pytest.mark.mpl_image_compare(style='mpl20') + def test_draw_matrix_transposer_4(self): + fig, ax = plt.subplots() + generate_matrix_transposer(4).draw_lifetime_chart(ax=ax) + return fig + + def test_generate_random_interleaver(self): + return + for _ in range(10): + for size in range(5, 20, 5): + assert ( + len( + generate_random_interleaver(size).split( + read_ports=1, write_ports=1 + ) + ) + == 1 + ) + assert ( + len(generate_random_interleaver(size).split(total_ports=1)) + == 2 + ) -- GitLab