Skip to content

Commit c178409

Browse files
author
Rose Yemelyanova
committed
Allow standalone system simulation component
This involves changing the SystemSimulation input parameters, and making it so that the slave scheduler runs an 'initial' tick in the same way as master.
1 parent 6483aac commit c178409

File tree

6 files changed

+61
-8
lines changed

6 files changed

+61
-8
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
- tickit.core.components.system_simulation.SystemSimulation:
2+
name: internal_tickit
3+
inputs: {}
4+
components:
5+
- examples.devices.counter.Counter:
6+
name: counter
7+
inputs: {}
8+
- tickit.devices.sink.Sink:
9+
name: counter_sink
10+
inputs:
11+
input: counter:value
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
- tickit.core.components.system_simulation.SystemSimulation:
2+
name: internal_tickit
3+
inputs: {}
4+
components:
5+
- tickit.devices.source.Source:
6+
name: internal_source
7+
inputs: {}
8+
value: 42
9+
- tickit.devices.sink.Sink:
10+
name: internal_sink
11+
inputs:
12+
input: internal_source:value

examples/configs/test.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
- tickit.devices.source.Source:
2+
name: internal_source
3+
inputs: {}
4+
value: 42
5+
- tickit.devices.sink.Sink:
6+
name: internal_sink
7+
inputs:
8+
input: internal_source:value

src/tickit/core/components/system_simulation.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,8 @@ async def stop_component(self) -> None:
102102
class SystemSimulation(ComponentConfig):
103103
"""Simulation of a nested set of components."""
104104

105-
name: ComponentID
106-
inputs: Dict[PortID, ComponentPort]
107105
components: List[ComponentConfig]
108-
expose: Dict[PortID, ComponentPort]
106+
expose: Dict[PortID, ComponentPort] = field(default_factory=dict)
109107

110108
def __call__(self) -> Component: # noqa: D102
111109
return SystemSimulationComponent(

src/tickit/core/management/schedulers/slave.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import asyncio
12
import logging
23
from typing import Awaitable, Callable, Dict, Optional, Set, Tuple, Type, Union
34

@@ -48,10 +49,22 @@ def __init__(
4849
wiring = self.add_exposing_wiring(wiring, expose)
4950
super().__init__(wiring, state_consumer, state_producer)
5051

52+
reads_from_external: bool = False
53+
for component in self._wiring:
54+
input_components = [
55+
p.component for p in self._wiring[component].values() # type: ignore
56+
]
57+
if "external" in input_components:
58+
reads_from_external = True
59+
break
60+
61+
self.reads_from_external = reads_from_external
5162
self.raise_interrupt = raise_interrupt
5263
self.interrupts: Set[ComponentID] = set()
5364
self.component_error: ComponentException
5465

66+
self.first_tick: asyncio.Event = asyncio.Event()
67+
5568
@staticmethod
5669
def add_exposing_wiring(
5770
wiring: Union[Wiring, InverseWiring],
@@ -127,17 +140,20 @@ async def on_tick(
127140
wakeup_components = {
128141
component for component, when in self.wakeups.items() if when <= time
129142
}
130-
root_components: Set[ComponentID] = {
131-
*self.interrupts,
132-
*wakeup_components,
133-
ComponentID("external"),
134-
}
143+
144+
root_components: Set[ComponentID] = {*self.interrupts, *wakeup_components}
145+
146+
if self.reads_from_external:
147+
root_components.update([ComponentID("external")])
148+
135149
for component in wakeup_components:
136150
del self.wakeups[component]
137151
self.interrupts.clear()
138152

139153
self.input_changes = changes
140154
self.output_changes = Changes(Map())
155+
156+
await asyncio.wait_for(self.first_tick.wait(), timeout=30)
141157
await self.ticker(time, root_components)
142158

143159
_, call_at = self.get_first_wakeups()
@@ -146,6 +162,11 @@ async def on_tick(
146162
async def run_forever(self) -> None:
147163
"""Delegates to setup which instantiates the ticker and state interfaces."""
148164
await self.setup()
165+
await self.ticker(
166+
SimTime(0),
167+
self.ticker.components,
168+
)
169+
self.first_tick.set()
149170

150171
async def schedule_interrupt(self, source: ComponentID) -> None:
151172
"""Schedules the interrupt of a component immediately.

tests/core/management/schedulers/test_slave_scheduler.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ async def test_slave_scheduler_run_forever_method(slave_scheduler: SlaveSchedule
179179
async def test_slave_scheduler_on_tick_method(
180180
slave_scheduler: SlaveScheduler, mock_ticker: Mock
181181
):
182+
await slave_scheduler.run_forever()
183+
182184
changes = Changes(Map({PortID("67"): 67}))
183185
slave_scheduler.ticker = mock_ticker
184186
output_changes, call_at = await slave_scheduler.on_tick(SimTime(8), changes)
@@ -190,6 +192,7 @@ async def test_slave_scheduler_on_tick_method(
190192
async def test_slave_scheduler_on_tick_method_with_wakeups(
191193
slave_scheduler: SlaveScheduler, mock_ticker: Mock
192194
):
195+
await slave_scheduler.run_forever()
193196
changes = Changes(Map({PortID("67"): 67}))
194197
slave_scheduler.ticker = mock_ticker
195198
slave_scheduler.wakeups = {

0 commit comments

Comments
 (0)