Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flowgraph constructions #773

Merged
merged 39 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
a15a4fb
basic flowgraph implementation
bdngo Dec 2, 2022
0f1f305
add visualization test
bdngo Jan 20, 2023
c513c7e
refactor
bdngo Jan 20, 2023
5030e1b
pre-branch
bdngo Jan 27, 2023
93eeac3
new backend
bdngo Jan 27, 2023
b49bf0b
rebase master with pypi packaging
bdngo Jan 27, 2023
f8fc5c5
preliminary run graph algo
bdngo Jan 30, 2023
05a4043
implementing graph running
bdngo Feb 1, 2023
e51170e
passing basic run test
bdngo Feb 3, 2023
4a41864
more cycle reduction tests
bdngo Feb 3, 2023
e81c1a0
better capture of errors
bdngo Feb 3, 2023
f6219f5
add serialization test
bdngo Mar 3, 2023
cbede14
using property decorators
bdngo Mar 3, 2023
62b262d
add step control and custom driver
bdngo Mar 10, 2023
36553c4
small linting fix
bdngo Mar 10, 2023
9465d20
graph runner should not raise exception
bdngo Mar 10, 2023
74685bd
add mermaid support
bdngo Mar 10, 2023
13c9f00
add test for mermaid
bdngo Mar 10, 2023
51bf5ea
implement and test auto-insertion of aux actions
bdngo Mar 23, 2023
3d1be77
update poetry.lock
bdngo Mar 24, 2023
02d0cf2
mermaid generator automatically writes to file
bdngo Mar 24, 2023
f8ae7e2
implement hook test and direct imports
bdngo Mar 24, 2023
1175163
change runner to iteratively run nodes via BFS
bdngo Mar 28, 2023
812b763
add mermaid support to docs
bdngo Mar 28, 2023
673adfa
simplify module imports
bdngo Mar 28, 2023
4fcb13d
rename test
bdngo Mar 28, 2023
1cbdcdd
start documentation
bdngo Mar 28, 2023
689a88a
fix wording
bdngo Apr 7, 2023
2159e63
bump packages
bdngo May 11, 2023
f450aa3
Merge branch 'master' into flowgraph
bdngo May 11, 2023
cf8c550
bump lock file, add typing marker
bdngo May 11, 2023
d326211
fix type-checking for networkx
bdngo May 11, 2023
9896bd2
Merge branch 'master' into flowgraph
bdngo Dec 1, 2023
8dce117
fix CI pipeline
bdngo Dec 1, 2023
842346f
migrate to current step control names
bdngo Jan 4, 2024
bbb047f
reorder sections
bdngo Jan 4, 2024
b75b62a
Merge branch 'master' into flowgraph
bdngo Jan 4, 2024
6ca70a5
make docs consistent
bdngo Jan 4, 2024
4b2a1ae
convert back to legacy names for plugging into backend
bdngo Jan 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,5 @@ jobs:
id: type-checks
run: |
touch .venv/lib/python${{ matrix.python-version }}/site-packages/ruamel/py.typed
touch .venv/lib/python${{ matrix.python-version }}/site-packages/networkx/py.typed
poetry run mypy --namespace-packages -p hammer
157 changes: 157 additions & 0 deletions doc/Hammer-Use/Flowgraphs.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
.. _flowgraphs:

Flowgraphs
==========

Hammer has **experimental** support for flowgraph constructions, similar to tools like `mflowgen <https://github.com/mflowgen/mflowgen>`_.
Their intention is to simplify the way flows are constructed and ran in Hammer.
They can be imported via the ``hammer.flowgraph`` module.

Construction
------------

Flowgraphs are nothing more than a collection of ``Node`` instances linked together via a ``Graph`` instance.
Each ``Node`` "pulls" from a directory to feed in inputs and "pushes" output files to another directory to be used by other nodes.
``Node`` instances are roughly equivalent to a single call to the ``hammer-vlsi`` CLI, so they take in similar attributes:

* The action being called
* The tool used to perform the action
* The pull and push directories
* Any *required* input/output files
* Any *optional* input/output files
* A driver to run the node with; this enables backwards compatibility with :ref:`hooks <hooks>`.
* Options to specify steps within an action; this enables backwards compatibility with :ref:`flow control <flow-control>`.

* ``start_before_step``
* ``start_after_step``
* ``stop_before_step``
* ``stop_after_step``
* ``only_step``

A minimal example of a ``Node``:

.. code-block:: python

from hammer.flowgraph import Node

test = Node(
action="foo",
tool="nop",
pull_dir="foo_dir",
push_dir="/dev/null",
required_inputs=["foo.yml"],
required_outputs=["foo-out.json"],
)

Each ``Node`` has the ability to be "privileged", meaning that a flow *must* start with this node.
This only occurs when a flow is being controlled using any of the steps.

Running a Flowgraph
-------------------

``Node`` instances are linked together using an `adjacency list <https://en.wikipedia.org/wiki/Adjacency_list>`_.
This list can be used to instantiate a ``Graph``:

.. code-block:: python

from hammer.flowgraph import Graph, Node

root = Node(
"foo", "nop", "foo_dir", "",
["foo.yml"],
["foo-out.json"],
)
child1 = Node(
"bar", "nop", "foo_dir", "bar_dir",
["foo-out.json"],
["bar-out.json"],
)
graph = Graph({root: [child1]})

Using the Hammer CLI tool, separate actions are manually linked via an *auxiliary* action, such as ``syn-to-par``.
By using a flowgraph, ``Graph`` instances by default *automatically* insert auxiliary actions.
This means that actions no longer need to be specified in a flow; the necessary nodes are inserted by the flowgraph tool.
This feature can be disabled by setting ``auto_auxiliary=False``.

A ``Graph`` can be run by calling the ``run`` method and passing in a starting node.
When running a flow, each ``Node`` keeps an internal status based on the status of the action being run:

* ``NOT_RUN``: The action has yet to be run.
* ``RUNNING``: The action is currently running.
* ``COMPLETE``: The action has finished.
* ``INCOMPLETE``: The action ran into an error while being run.
* ``INVALID``: The action's outputs have been invalidated (e.g. inputs or attributes have changed).

The interactions between the statuses are described in the diagram:

.. mermaid::

stateDiagram-v2
[*] --> NOT_RUN
NOT_RUN --> RUNNING
RUNNING --> INCOMPLETE
RUNNING --> COMPLETE
INCOMPLETE --> NOT_RUN
COMPLETE --> INVALID
INVALID --> NOT_RUN

Regardless of whether a flow completes with or without errors, the graph at the time of completion or error is returned, allowing for a graph to be "resumed" once any errors have been fixed.

Visualization
-------------

A flowgraph can be visualized in Markdown files via the `Mermaid <https://mermaid.js.org/>`_ tool.
Calling a ``Graph`` instance's ``to_mermaid`` method outputs a file named ``graph-viz.md``.
The file can be viewed in a site like `Mermaid's live editor <https://mermaid.live/>`_ or using Github's native support.

The flowgraph below would appear like this:

.. code-block:: python

from hammer.flowgraph import Graph, Node

syn = Node(
"syn", "nop",
os.path.join(td, "syn_dir"), os.path.join(td, "s2p_dir"),
["syn-in.yml"],
["syn-out.json"],
)
s2p = Node(
"syn-to-par", "nop",
os.path.join(td, "s2p_dir"), os.path.join(td, "par_dir"),
["syn-out.json"],
["s2p-out.json"],
)
par = Node(
"par", "nop",
os.path.join(td, "par_dir"), os.path.join(td, "out_dir"),
["s2p-out.json"],
["par-out.json"],
)
g = Graph({
syn: [s2p],
s2p: [par],
par: []
})


Here are the contents of ``graph-viz.md`` after calling ``g.to_mermaid()``:

.. code-block:: markdown

```mermaid

stateDiagram-v2
syn --> syn_to_par
syn_to_par --> par
```

Which would render like this:

.. mermaid::

stateDiagram-v2
syn --> syn_to_par
syn_to_par --> par

Note that the separators have been changed to comply with Mermaid syntax.
1 change: 1 addition & 0 deletions doc/Hammer-Use/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ This documentation will walk through more advanced features of the Hammer infras
Hammer-APIs
Flow-Control
Hooks
Flowgraphs
Buildfile
Hierarchical
23 changes: 12 additions & 11 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@

# -- Project information -----------------------------------------------------

project = 'Hammer'
copyright = '2023, Berkeley Architecture Research'
author = 'Berkeley Architecture Research'
project = "Hammer"
copyright = "2023, Berkeley Architecture Research"
author = "Berkeley Architecture Research"

# The full version, including alpha/beta/rc tags
release = '1.0.0'
release = "1.0.0"


# -- General configuration ---------------------------------------------------
Expand All @@ -33,30 +33,31 @@
extensions = [
"myst_parser",
"sphinx-jsonschema",
"sphinx_rtd_size"
"sphinx_rtd_size",
"sphinxcontrib.mermaid",
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

source_suffix = '.rst'
source_suffix = ".rst"

master_doc = 'index'
master_doc = "index"

# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
html_theme = "sphinx_rtd_theme"

html_theme_options = {
'collapse_navigation': False,
"collapse_navigation": False,
}

sphinx_rtd_size_width = "1200px"
Expand Down
11 changes: 6 additions & 5 deletions hammer/config/config_src.py
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,7 @@ def get_config(self) -> dict:
self.__config_cache_dirty = False
return self.__config_cache

@property
def get_config_types(self) -> dict:
"""
Get the types for the configuration of a database.
Expand Down Expand Up @@ -906,9 +907,9 @@ def get_setting_type(self, key: str, nullvalue: Any = None) -> Any:
:param nullvalue: Value to return for nulls.
:return: Data type of key.
"""
if key not in self.get_config_types():
if key not in self.get_config_types:
raise KeyError(f"Key type {key} is missing")
value = self.get_config_types()[key]
value = self.get_config_types[key]
return nullvalue if value is None else value

def set_setting_type(self, key: str, value: Any) -> None:
Expand All @@ -928,7 +929,7 @@ def has_setting_type(self, key: str) -> bool:
:param key: Desired key.
:return: True if the given setting exists.
"""
return key in self.get_config_types()
return key in self.get_config_types

def check_setting(self, key: str, cfg: Optional[dict] = None) -> bool:
"""
Expand All @@ -940,12 +941,12 @@ def check_setting(self, key: str, cfg: Optional[dict] = None) -> bool:

if cfg is None:
cfg = self.get_config()
if key not in self.get_config_types():
if key not in self.get_config_types:
#TODO: compile this at the beginning instead of emitting every instance
#self.logger.warning(f"Key {key} is not associated with a type")
return True
try:
exp_value_type = parse_setting_type(self.get_config_types()[key])
exp_value_type = parse_setting_type(self.get_config_types[key])
except ValueError as ve:
raise ValueError(f'Key {key} has an invalid outer type: perhaps you have "List" instead of "list" or "Dict" instead of "dict"?') from ve

Expand Down
5 changes: 5 additions & 0 deletions hammer/flowgraph/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Hammer logging code.
#
# See LICENSE for licence details.

from .flowgraph import *
Loading