Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion ymmsl/v0_2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from ymmsl.v0_2.settings import Settings, SettingValue
from ymmsl.v0_2.supported_settings import (
SettingType, SupportedSetting, SupportedSettings)
from ymmsl.v0_2.timelines import TimelineNode, TimelineTree


__all__ = [
Expand All @@ -26,4 +27,4 @@
'MPICoresResReq', 'MPINodesResReq', 'Operator', 'Port', 'Ports', 'Program',
'Reference', 'ReferencePart', 'resolve', 'ResourceRequirements', 'Settings',
'SettingType', 'SettingValue', 'SupportedSetting', 'SupportedSettings',
'ThreadedResReq', 'Timeline']
'ThreadedResReq', 'Timeline', "TimelineNode", "TimelineTree"]
9 changes: 9 additions & 0 deletions ymmsl/v0_2/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ def __init__(
except ValueError:
raise RuntimeError(f'Invalid conduit filter "{f}"')

# Repeaters must come after reducers
is_repeating = False
for filter in self.filters:
if filter.is_reducer() and is_repeating:
raise ValueError(
f"Invalid conduit filters {self.filters}: reducer filters "
"must come before repeater filters.")
is_repeating = filter.is_repeater()

self.__check_reference(self.sender)
self.__check_reference(self.receiver)

Expand Down
10 changes: 10 additions & 0 deletions ymmsl/v0_2/ports.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from collections import OrderedDict
from collections.abc import ItemsView, KeysView, ValuesView
from typing import Any, cast, Iterator, List, Optional, overload, Sequence, Union

from ymmsl.v0_1.component import Operator # also the v0.2 version, import from here
Expand Down Expand Up @@ -273,6 +274,15 @@ def __iter__(self) -> Iterator[Identifier]:
for port_name in self._ports:
yield port_name

def items(self) -> ItemsView[Identifier, Port]:
return self._ports.items()

def keys(self) -> KeysView[Identifier]:
return self._ports.keys()

def values(self) -> ValuesView[Port]:
return self._ports.values()

def sending_port_names(self) -> List[Identifier]:
"""Return the names of all the sending ports.

Expand Down
107 changes: 107 additions & 0 deletions ymmsl/v0_2/tests/test_timelines.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
from ymmsl.v0_2.timelines import TimelineTree
from pathlib import Path
import ymmsl
from ymmsl.v0_2 import Configuration, Reference as Ref, Timeline, ConduitFilter

import pytest

ROOT_TIMELINE = Timeline(":")


@pytest.fixture()
def timelines_configuration() -> Configuration:
return ymmsl.load_as(
Configuration, Path(__file__).parent / "ymmsl1/timelines.ymmsl"
)


def test_consistent_configuration(timelines_configuration: Configuration) -> None:
timelines_configuration.check_consistent()


def test_dispatch(timelines_configuration: Configuration) -> None:
tltree = TimelineTree(timelines_configuration.models[Ref("dispatch")])
assert tltree.component_timeline(Ref("first")) == ROOT_TIMELINE
assert tltree.component_timeline(Ref("second")) == ROOT_TIMELINE


def test_macromicro(timelines_configuration: Configuration) -> None:
tltree = TimelineTree(timelines_configuration.models[Ref("macromicro")])
assert tltree.component_timeline(Ref("macro")) == ROOT_TIMELINE
assert tltree.component_timeline(Ref("micro")) == Timeline(":macro")


def test_cycle(timelines_configuration: Configuration) -> None:
with pytest.raises(RuntimeError, match="Cycle detected"):
TimelineTree(timelines_configuration.models[Ref("cycle")])


def test_reducer(timelines_configuration: Configuration) -> None:
tltree = TimelineTree(timelines_configuration.models[Ref("reducer")])
assert tltree.component_timeline(Ref("first")) == ROOT_TIMELINE
assert tltree.component_timeline(Ref("second")) == ROOT_TIMELINE


def test_too_many_reducers(timelines_configuration: Configuration) -> None:
model = timelines_configuration.models[Ref("reducer")]
model.conduits[-1].filters.append(model.conduits[-1].filters[0])
with pytest.raises(ValueError, match="Too many reducer filters"):
TimelineTree(model)


def test_inconsistent_timelines(timelines_configuration: Configuration) -> None:
with pytest.raises(ValueError, match="Inconsistent timelines"):
TimelineTree(timelines_configuration.models[Ref("inconsistent")])


def test_repeaters(timelines_configuration: Configuration) -> None:
tltree = TimelineTree(timelines_configuration.models[Ref("repeaters")])
assert tltree.component_timeline(Ref("macro")) == ROOT_TIMELINE
assert tltree.component_timeline(Ref("meso")) == Timeline(":macro")
assert tltree.component_timeline(Ref("micro")) == Timeline(":macro:meso")


def test_too_many_repeaters(timelines_configuration: Configuration) -> None:
model = timelines_configuration.models[Ref("repeaters")]
model.conduits[-2].filters.append(ConduitFilter.REPEAT)
with pytest.raises(ValueError, match="Too many repeater filters"):
TimelineTree(model)


def test_too_few_repeaters(timelines_configuration: Configuration) -> None:
model = timelines_configuration.models[Ref("repeaters")]
model.conduits[-1].filters.pop()
with pytest.raises(ValueError, match="Inconsistent timelines"):
TimelineTree(model)


def test_repeater_and_too_many_reducers(timelines_configuration: Configuration) -> None:
model = timelines_configuration.models[Ref("repeaters")]
model.conduits[-1].filters.insert(0, ConduitFilter.LAST)
with pytest.raises(ValueError, match="Too many reducer filters"):
TimelineTree(model)


def test_repeater_after_reducer(timelines_configuration: Configuration) -> None:
model = timelines_configuration.models[Ref("repeater_reducer")]
tltree = TimelineTree(model)
assert tltree.component_timeline(Ref("macro1")) == ROOT_TIMELINE
assert tltree.component_timeline(Ref("macro2")) == ROOT_TIMELINE
assert tltree.component_timeline(Ref("micro1")) == Timeline(":macro1")
assert tltree.component_timeline(Ref("micro2")) == Timeline(":macro2")

# Removing the filters on the last conduit is a problem
model.conduits[-1].filters = []
with pytest.raises(ValueError, match="Inconsistent timelines"):
TimelineTree(model)


def test_repeater_after_reducer_error(timelines_configuration: Configuration) -> None:
model = timelines_configuration.models[Ref("repeater_reducer_error")]
with pytest.raises(ValueError, match="repeater after reducer"):
TimelineTree(model)
model.conduits[-1].filters = []
tltree = TimelineTree(model)
assert tltree.component_timeline(Ref("macro")) == ROOT_TIMELINE
assert tltree.component_timeline(Ref("micro1")) == Timeline(":macro")
assert tltree.component_timeline(Ref("micro2")) == Timeline(":macro")
173 changes: 173 additions & 0 deletions ymmsl/v0_2/tests/ymmsl1/timelines.ymmsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
ymmsl_version: v0.2
description: Test models for determining timelines
models:
dispatch:
ports:
f_init: init
components:
first:
description: First component
ports:
f_init: init
o_f: final
second:
description: Second component
ports:
f_init: init
conduits:
init: first.init
first.final: second.init

macromicro:
ports:
f_init: init
components:
macro:
description: Macro component
ports:
f_init: init
o_i: out
s: in
micro:
description: Micro component
ports:
f_init: init1 init2
o_f: final
conduits:
init:
- macro.init
- repeat micro.init1 # Test repeater filter
macro.out: micro.init2
micro.final: macro.in

cycle:
components:
first:
description: First component
ports:
f_init: init
o_f: final
second:
description: Second component
ports:
f_init: init
o_f: final
conduits:
first.final: second.init
second.final: first.init

reducer:
components:
first:
description: First component
ports:
o_i: out
o_f: final
second:
description: Second component
ports:
f_init: init1 init2
conduits:
first.final: second.init1
first.out: last second.init2

inconsistent:
components:
macro:
description: Macro component
ports:
o_i: out
o_f: final
micro:
description: Micro component
ports:
f_init: in
o_f: final
inconsistent:
description: Component with inconsistent timelines
ports:
f_init: init1 init2
conduits:
macro.out: micro.in
macro.final: inconsistent.init1
micro.final: inconsistent.init2

repeaters:
ports:
f_init: init
components:
macro:
description: Macro component
ports:
f_init: init
o_i: out
s: in
meso:
description: Meso component
ports:
f_init: init init2
o_i: out
s: in
o_f: final
micro:
description: Micro component
ports:
f_init: init init2
o_f: final
conduits:
macro.out: meso.init
meso.final: macro.in
meso.out: micro.init
micro.final: meso.in
init:
- macro.init
- repeat meso.init2
- pad pad micro.init2

repeater_reducer:
components:
macro1:
description: First macro component
ports:
o_i: out
o_f: final
micro1:
description: First micro
ports:
f_init: init
o_f: final
macro2:
description: Second macro component
ports:
f_init: init
o_i: out
micro2:
description: Second micro
ports:
f_init: init_micro1 init_macro2
conduits:
macro1.out: micro1.init
macro1.final: macro2.init
macro2.out: micro2.init_macro2
micro1.final: last repeat micro2.init_micro1

repeater_reducer_error:
components:
macro:
description: Macro component
ports:
o_i: out
micro1:
description: First micro
ports:
f_init: init
o_f: final
micro2:
description: Second micro
ports:
f_init: init1 init2
conduits:
macro.out:
- micro1.init
- micro2.init1
micro1.final: last pad micro2.init2
Loading
Loading