Unverified Commit 0a32b755 authored by Jakob Görgen's avatar Jakob Görgen
Browse files

small comments and interface changes

parent bef618ad
...@@ -140,10 +140,16 @@ class Instantiation(util_base.IdObj): ...@@ -140,10 +140,16 @@ class Instantiation(util_base.IdObj):
assert queue_type is not None assert queue_type is not None
return f"{self._env._shm_base}/{queue_type}/{queue_ident}" return f"{self._env._shm_base}/{queue_type}/{queue_ident}"
def _create_opposing_socket(self, socket: Socket) -> Socket: def _create_opposing_socket(
self, socket: Socket, supported_sock_types: set[SockType] = set()
) -> Socket:
new_ty = ( new_ty = (
SockType.LISTEN if socket._type == SockType.CONNECT else SockType.LISTEN SockType.LISTEN if socket._type == SockType.CONNECT else SockType.LISTEN
) )
if new_ty not in supported_sock_types:
raise Exception(
f"cannot create opposing socket, as required type is not supported: required={new_ty}, supported={','.join(supported_sock_types)}"
)
new_path = socket._path new_path = socket._path
new_socket = Socket(path=new_path, ty=new_ty) new_socket = Socket(path=new_path, ty=new_ty)
return new_socket return new_socket
...@@ -151,7 +157,7 @@ class Instantiation(util_base.IdObj): ...@@ -151,7 +157,7 @@ class Instantiation(util_base.IdObj):
def get_socket( def get_socket(
self, self,
interface: sys_base.Interface, interface: sys_base.Interface,
supported_sock_types: set[SockType] = {SockType.LISTEN, SockType.CONNECT}, supported_sock_types: set[SockType] = set(),
) -> Socket: ) -> Socket:
# check if already a socket is associated with this interface # check if already a socket is associated with this interface
socket = self._get_socket_by_interface(interface=interface) socket = self._get_socket_by_interface(interface=interface)
...@@ -161,7 +167,9 @@ class Instantiation(util_base.IdObj): ...@@ -161,7 +167,9 @@ class Instantiation(util_base.IdObj):
# Check if other side already created a socket, and create an opposing one # Check if other side already created a socket, and create an opposing one
socket = self._get_opposing_socket_by_interface(interface=interface) socket = self._get_opposing_socket_by_interface(interface=interface)
if socket is not None: if socket is not None:
new_socket = self._create_opposing_socket(socket=socket) new_socket = self._create_opposing_socket(
socket=socket, supported_sock_types=supported_sock_types
)
self._updated_tracker_mapping(interface=interface, socket=new_socket) self._updated_tracker_mapping(interface=interface, socket=new_socket)
return new_socket return new_socket
...@@ -202,7 +210,7 @@ class Instantiation(util_base.IdObj): ...@@ -202,7 +210,7 @@ class Instantiation(util_base.IdObj):
executor: command_executor.Executor = command_executor.LocalExecutor(), executor: command_executor.Executor = command_executor.LocalExecutor(),
sockets: list[Socket] = [], sockets: list[Socket] = [],
) -> None: ) -> None:
wait_socks = map(lambda sock: sock._path, sockets) wait_socks = list(map(lambda sock: sock._path, sockets))
await executor.await_files(wait_socks, verbose=self.verbose) await executor.await_files(wait_socks, verbose=self.verbose)
# TODO: add more methods constructing paths as required by methods in simulators or image handling classes # TODO: add more methods constructing paths as required by methods in simulators or image handling classes
......
...@@ -27,6 +27,7 @@ import itertools ...@@ -27,6 +27,7 @@ import itertools
import time import time
import typing as tp import typing as tp
import simbricks.orchestration.system as sys_conf import simbricks.orchestration.system as sys_conf
import simbricks.orchestration.system.host as sys_host_conf
import simbricks.orchestration.instantiation.base as inst_base import simbricks.orchestration.instantiation.base as inst_base
import simbricks.orchestration.simulation.channel as sim_chan import simbricks.orchestration.simulation.channel as sim_chan
import simbricks.orchestration.utils.base as utils_base import simbricks.orchestration.utils.base as utils_base
...@@ -120,7 +121,7 @@ class Simulator(utils_base.IdObj): ...@@ -120,7 +121,7 @@ class Simulator(utils_base.IdObj):
"""Commands to prepare execution of this simulator.""" """Commands to prepare execution of this simulator."""
return [] return []
def _add_component(self, comp: sys_base.Component) -> None: def add(self, comp: sys_base.Component) -> None:
if comp in self._components: if comp in self._components:
raise Exception("cannot add the same specification twice to a simulator") raise Exception("cannot add the same specification twice to a simulator")
self._components.add(comp) self._components.add(comp)
...@@ -210,6 +211,8 @@ class Simulator(utils_base.IdObj): ...@@ -210,6 +211,8 @@ class Simulator(utils_base.IdObj):
# TODO: overwrite in sub-classes to reflect that currently not all adapters support both listening and connecting # TODO: overwrite in sub-classes to reflect that currently not all adapters support both listening and connecting
# In future version adapters should support both which would render this method obsolete # In future version adapters should support both which would render this method obsolete
# TODO: FIXME, this is still a little bit broken, as it might be important to create
# sockets in the correct order to not try creating a connect socket for a simulator that doesnt support it
def supported_socket_types(self) -> set[inst_base.SockType]: def supported_socket_types(self) -> set[inst_base.SockType]:
return {inst_base.SockType.LISTEN, inst_base.SockType.CONNECT} return {inst_base.SockType.LISTEN, inst_base.SockType.CONNECT}
...@@ -262,22 +265,12 @@ class Simulation(utils_base.IdObj): ...@@ -262,22 +265,12 @@ class Simulation(utils_base.IdObj):
by first running in a less accurate mode, then checkpointing the system by first running in a less accurate mode, then checkpointing the system
state after boot and running simulations from there. state after boot and running simulations from there.
""" """
# self.hosts: list[HostSim] = []
# """The host simulators to run."""
# self.pcidevs: list[PCIDevSim] = []
# """The PCIe device simulators to run."""
# self.memdevs: list[MemDevSim] = []
# """The memory device simulators to run."""
# self.netmems: list[NetMemSim] = []
# """The network memory simulators to run."""
# self.networks: list[NetSim] = []
# """The network simulators to run."""
self.metadata: dict[str, tp.Any] = {} self.metadata: dict[str, tp.Any] = {}
self._sys_sim_map: dict[sys_conf.Component, Simulator] = {} self._sys_sim_map: dict[sys_conf.Component, Simulator] = {}
"""System component and its simulator pairs""" """System component and its simulator pairs"""
self._chan_map: dict[sys_conf.Channel, Channel] = {} self._chan_map: dict[sys_conf.Channel, sim_chan.Channel] = {}
"""Channel spec and its instanciation""" """Channel spec and its instanciation"""
def add_spec_sim_map(self, sys: sys_conf.Component, sim: Simulator): def add_spec_sim_map(self, sys: sys_conf.Component, sim: Simulator):
...@@ -302,14 +295,6 @@ class Simulation(utils_base.IdObj): ...@@ -302,14 +295,6 @@ class Simulation(utils_base.IdObj):
simulators = set(map(lambda kv: kv[1], self._sys_sim_map.items())) simulators = set(map(lambda kv: kv[1], self._sys_sim_map.items()))
return simulators return simulators
# TODO: FIXME, either by filtering using specification type or simulator type
def nics() -> list[Simulator]:
pass
# TODO FIXME, either by filtering using specification type or simulator type
def hosts() -> list[Simulator]:
pass
def resreq_mem(self) -> int: def resreq_mem(self) -> int:
"""Memory required to run all simulators in this experiment.""" """Memory required to run all simulators in this experiment."""
mem = 0 mem = 0
...@@ -337,4 +322,3 @@ class Simulation(utils_base.IdObj): ...@@ -337,4 +322,3 @@ class Simulation(utils_base.IdObj):
# TODO: FIXME # TODO: FIXME
def is_checkpointing_enabled(self) -> bool: def is_checkpointing_enabled(self) -> bool:
raise Exception("not implemented") raise Exception("not implemented")
...@@ -26,6 +26,7 @@ import simbricks.orchestration.simulation.base as sim_base ...@@ -26,6 +26,7 @@ import simbricks.orchestration.simulation.base as sim_base
from simbricks.orchestration.system import eth from simbricks.orchestration.system import eth
from simbricks.orchestration.instantiation import base as inst_base from simbricks.orchestration.instantiation import base as inst_base
from simbricks.orchestration.experiment.experiment_environment_new import ExpEnv from simbricks.orchestration.experiment.experiment_environment_new import ExpEnv
from simbricks.orchestration.utils import base as base_utils
class NetSim(sim_base.Simulator): class NetSim(sim_base.Simulator):
...@@ -35,9 +36,6 @@ class NetSim(sim_base.Simulator): ...@@ -35,9 +36,6 @@ class NetSim(sim_base.Simulator):
self, simulation: sim_base.Simulation, relative_executable_path: str = "" self, simulation: sim_base.Simulation, relative_executable_path: str = ""
) -> None: ) -> None:
super().__init__(simulation, relative_executable_path=relative_executable_path) super().__init__(simulation, relative_executable_path=relative_executable_path)
# TODO: do we want them here?
self._switch_specs = []
self._host_specs = []
def full_name(self) -> str: def full_name(self) -> str:
return "net." + self.name return "net." + self.name
...@@ -50,21 +48,9 @@ class NetSim(sim_base.Simulator): ...@@ -50,21 +48,9 @@ class NetSim(sim_base.Simulator):
deps.append(n.net[0].sim) deps.append(n.net[0].sim)
return deps return deps
# TODO
def sockets_wait(self, env: ExpEnv) -> list[str]:
pass
def wait_terminate(self) -> bool:
# TODO
return self.wait
def init_network(self) -> None: def init_network(self) -> None:
pass pass
def sockets_cleanup(self, env: ExpEnv) -> list[str]:
# TODO
return []
class WireNet(NetSim): class WireNet(NetSim):
...@@ -74,13 +60,15 @@ class WireNet(NetSim): ...@@ -74,13 +60,15 @@ class WireNet(NetSim):
relative_executable_path="/sims/net/wire/net_wire", relative_executable_path="/sims/net/wire/net_wire",
relative_pcap_file_path=None, relative_pcap_file_path=None,
) )
self._wire_comp: eth.EthWire | None = None
self._relative_pcap_file_path: str | None = "relative_pcap_file_path" self._relative_pcap_file_path: str | None = "relative_pcap_file_path"
def add(self, wire: eth.EthWire): def add(self, wire: eth.EthWire):
assert self._wire_comp is None base_utils.has_expected_type(wire, eth.EthWire())
super()._add_component(wire) if len(self._components) > 1:
self._wire_comp = wire raise Exception(
"can only add a single wire component to the WireNet simulator"
)
super().add(wire)
def run_cmd(self, inst: inst_base.Instantiation) -> str: def run_cmd(self, inst: inst_base.Instantiation) -> str:
channels = self._get_channels(inst=inst) channels = self._get_channels(inst=inst)
...@@ -113,17 +101,15 @@ class SwitchNet(NetSim): ...@@ -113,17 +101,15 @@ class SwitchNet(NetSim):
super().__init__( super().__init__(
simulation=simulation, relative_executable_path=relative_executable_path simulation=simulation, relative_executable_path=relative_executable_path
) )
self._switch_spec: eth.EthSwitch | None = None
self._relative_pcap_file_path: str | None = relative_pcap_file_path self._relative_pcap_file_path: str | None = relative_pcap_file_path
def add(self, switch_spec: eth.EthSwitch): def add(self, switch_spec: eth.EthSwitch):
assert self._switch_spec is None base_utils.has_expected_type(wire, eth.EthSwitch())
super()._add_component(switch_spec) if len(self._components) > 1:
self._switch_spec = switch_spec raise Exception("can only add a single switch component to the SwitchNet")
super().add(switch_spec)
def run_cmd(self, inst: inst_base.Instantiation) -> str: def run_cmd(self, inst: inst_base.Instantiation) -> str:
assert self._switch_spec is not None
channels = self._get_channels(inst=inst) channels = self._get_channels(inst=inst)
eth_latency, sync_period, sync = ( eth_latency, sync_period, sync = (
sim_base.Simulator.get_unique_latency_period_sync(channels=channels) sim_base.Simulator.get_unique_latency_period_sync(channels=channels)
......
# Copyright 2024 Max Planck Institute for Software Systems, and
# National University of Singapore
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from simbricks.orchestration.simulation import base as sim_base
from simbricks.orchestration.runtime_new import command_executor
class SimulationOutput:
"""Manages an experiment's output."""
def __init__(self, sim: sim_base.Simulation) -> None:
self._sim_name: str = sim.name
self._start_time: float = None
self._end_time: float = None
self._success: bool = True
self._interrupted: bool = False
self._metadata = exp.metadata
self._sims: dict[str, dict[str, str | list[str]]] = {}
def set_start(self) -> None:
self._start_time = time.time()
def set_end(self) -> None:
self._end_time = time.time()
def set_failed(self) -> None:
self._success = False
def set_interrupted(self) -> None:
self._success = False
self._interrupted = True
def add_sim(self, sim: sim_base.Simulator, comp: command_executor.Component) -> None:
obj = {
"class": sim.__class__.__name__,
"cmd": comp.cmd_parts,
"stdout": comp.stdout,
"stderr": comp.stderr,
}
self._sims[sim.full_name()] = obj
def dump(self, outpath: str) -> None:
pathlib.Path(outpath).parent.mkdir(parents=True, exist_ok=True)
with open(outpath, "w", encoding="utf-8") as file:
json.dump(self.__dict__, file, indent=4)
def load(self, file: str) -> None:
with open(file, "r", encoding="utf-8") as fp:
for k, v in json.load(fp).items():
self.__dict__[k] = v
...@@ -29,3 +29,19 @@ class IdObj(abc.ABC): ...@@ -29,3 +29,19 @@ class IdObj(abc.ABC):
def __init__(self): def __init__(self):
self._id = next(self.__id_iter) self._id = next(self.__id_iter)
def check_type(obj, expected_type) -> bool:
"""
Checks if obj has type or is a subtype of expected_type
obj: an class object
expected_type: a type object
"""
match obj:
case expected_type:
return True
case _:
return False
def has_expected_type(obj, expected_type) -> None:
if not check_type(obj=obj, expected_type=expected_type):
raise Exception(f"obj of type {type(obj)} has not the type or is not a subtype of {type(expected_type)}")
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment