Unverified Commit 1c24e0fb authored by Jakob Görgen's avatar Jakob Görgen
Browse files

minor runtime fixes + better type annotations

parent 1910a3af
...@@ -26,6 +26,7 @@ import asyncio ...@@ -26,6 +26,7 @@ import asyncio
import enum import enum
import pathlib import pathlib
import shutil import shutil
import typing
from simbricks.orchestration.utils import base as util_base from simbricks.orchestration.utils import base as util_base
from simbricks.orchestration.system import base as sys_base from simbricks.orchestration.system import base as sys_base
from simbricks.orchestration.system import pcie as sys_pcie from simbricks.orchestration.system import pcie as sys_pcie
...@@ -33,9 +34,11 @@ from simbricks.orchestration.system import mem as sys_mem ...@@ -33,9 +34,11 @@ from simbricks.orchestration.system import mem as sys_mem
from simbricks.orchestration.system import eth as sys_eth from simbricks.orchestration.system import eth as sys_eth
from simbricks.orchestration.system.host import base as sys_host from simbricks.orchestration.system.host import base as sys_host
from simbricks.orchestration.system.host import disk_images from simbricks.orchestration.system.host import disk_images
from simbricks.orchestration.simulation import base as sim_base
from simbricks.orchestration.runtime_new import command_executor from simbricks.orchestration.runtime_new import command_executor
if typing.TYPE_CHECKING:
from simbricks.orchestration.simulation import base as sim_base
class SockType(enum.Enum): class SockType(enum.Enum):
LISTEN = enum.auto() LISTEN = enum.auto()
......
...@@ -24,9 +24,6 @@ ...@@ -24,9 +24,6 @@
from __future__ import annotations from __future__ import annotations
import itertools import itertools
import pathlib
import shutil
import typing as tp
import abc import abc
from simbricks.orchestration.simulation import output from simbricks.orchestration.simulation import output
......
...@@ -55,10 +55,9 @@ class Simulator(utils_base.IdObj): ...@@ -55,10 +55,9 @@ class Simulator(utils_base.IdObj):
super().__init__() super().__init__()
self.name: str = name self.name: str = name
self._relative_executable_path: str = relative_executable_path self._relative_executable_path: str = relative_executable_path
# self.extra_deps: list[Simulator] = []
self._simulation: sim_base.Simulation = simulation self._simulation: sim_base.Simulation = simulation
self._components: set[sys_conf.Component] = set() self._components: set[sys_conf.Component] = set()
self._wait: bool = False self._wait: bool = False # TODO: FIXME
simulation.add_sim(self) simulation.add_sim(self)
@staticmethod @staticmethod
...@@ -122,12 +121,6 @@ class Simulator(utils_base.IdObj): ...@@ -122,12 +121,6 @@ class Simulator(utils_base.IdObj):
"""Full name of the simulator.""" """Full name of the simulator."""
return "" return ""
# TODO: move into prepare method
# pylint: disable=unused-argument
# def prep_cmds(self, inst: inst_base.Instantiation) -> list[str]:
# """Commands to prepare execution of this simulator."""
# return []
def add(self, comp: sys_conf.Component) -> None: def add(self, comp: sys_conf.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")
...@@ -211,6 +204,9 @@ class Simulator(utils_base.IdObj): ...@@ -211,6 +204,9 @@ class Simulator(utils_base.IdObj):
def run_cmd(self, inst: inst_base.Instantiation) -> str: def run_cmd(self, inst: inst_base.Instantiation) -> str:
"""Command to execute this simulator.""" """Command to execute this simulator."""
return "" return ""
def checkpoint_commands(self) -> list[str]:
return []
# 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
...@@ -236,6 +232,7 @@ class Simulator(utils_base.IdObj): ...@@ -236,6 +232,7 @@ class Simulator(utils_base.IdObj):
def start_delay(self) -> int: def start_delay(self) -> int:
return 5 return 5
# TODO: FIXME
def wait_terminate(self) -> bool: def wait_terminate(self) -> bool:
return self._wait return self._wait
......
...@@ -20,20 +20,18 @@ ...@@ -20,20 +20,18 @@
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import io from __future__ import annotations
import tarfile
import math import math
import asyncio import asyncio
import typing as tp import typing as tp
import simbricks.orchestration.simulation.base as sim_base import simbricks.orchestration.simulation.base as sim_base
import simbricks.orchestration.system.pcie as system_pcie
import simbricks.orchestration.system as system import simbricks.orchestration.system as system
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
if tp.TYPE_CHECKING: if tp.TYPE_CHECKING:
from simbricks.orchestration.system.host.base import Host from simbricks.orchestration.system import host as sys_host
class HostSim(sim_base.Simulator): class HostSim(sim_base.Simulator):
...@@ -44,22 +42,7 @@ class HostSim(sim_base.Simulator): ...@@ -44,22 +42,7 @@ class HostSim(sim_base.Simulator):
def full_name(self) -> str: def full_name(self) -> str:
return "host." + self.name return "host." + self.name
def dependencies(self) -> tp.List[sim_base.Simulator]: def add(self, host: sys_host.Host):
deps = []
for h in self._components:
for dev in h.ifs:
if not dev.is_connected():
raise Exception("host interface is not connected")
else:
if dev.channel.a == dev:
peer_if = dev.channel.b
else:
peer_if = dev.channel.a
deps.append(self._simulation.find_sim(peer_if.component))
return deps
def add(self, host: "Host"):
super().add(host) super().add(host)
def config_str(self) -> str: def config_str(self) -> str:
...@@ -139,8 +122,9 @@ class Gem5Sim(HostSim): ...@@ -139,8 +122,9 @@ class Gem5Sim(HostSim):
return cmd return cmd
def wait_terminate(self) -> bool:
return self.wait def checkpoint_commands(self) -> list[str]:
return ["m5 checkpoint"]
class QemuSim(HostSim): class QemuSim(HostSim):
...@@ -173,9 +157,9 @@ class QemuSim(HostSim): ...@@ -173,9 +157,9 @@ class QemuSim(HostSim):
disks = tp.cast(list[system.DiskImage], fsh.disks) disks = tp.cast(list[system.DiskImage], fsh.disks)
for disk in disks: for disk in disks:
prep_cmds.append( prep_cmds.append(
f"{inst.qemu_img_path()} create -f qcow2 -o " f'{inst.qemu_img_path()} create -f qcow2 -o '
f'backing_file="{disk.path(inst=inst, format="qcow2")}" ' f'backing_file="{disk.path(inst=inst, format="qcow2")}" '
f"{inst.hdcopy_path(img=disk, format="qcow2")}" f'{inst.hdcopy_path(img=disk, format="qcow2")}'
) )
task = asyncio.create_task( task = asyncio.create_task(
......
...@@ -21,10 +21,13 @@ ...@@ -21,10 +21,13 @@
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import annotations from __future__ import annotations
import abc import abc
import typing as tp import typing as tp
from simbricks.orchestration.utils import base as util_base from simbricks.orchestration.utils import base as util_base
from simbricks.orchestration.instantiation import base as inst_base
if tp.TYPE_CHECKING:
from simbricks.orchestration.instantiation import base as inst_base
class System: class System:
......
...@@ -20,41 +20,43 @@ ...@@ -20,41 +20,43 @@
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import annotations
import typing as tp import typing as tp
import abc import abc
import io import io
from simbricks.orchestration.experiment import experiment_environment as expenv from simbricks.orchestration.instantiation import base as inst_base
if tp.TYPE_CHECKING: if tp.TYPE_CHECKING:
from simbricks.orchestration.system.host import base from simbricks.orchestration.system import host as sys_host
class Application(abc.ABC): class Application(abc.ABC):
def __init__(self, h: 'Host') -> None: def __init__(self, h: sys_host.Host) -> None:
self.host = h self.host = h
# Note AK: Maybe we can factor most of the duplicate calls with the host out # Note AK: Maybe we can factor most of the duplicate calls with the host out
# into a separate module. # into a separate module.
class BaseLinuxApplication(abc.ABC): # TODO: FIXME!!! class BaseLinuxApplication(abc.ABC):
def __init__(self, h: 'LinuxHost') -> None: def __init__(self, h: sys_host.LinuxHost) -> None:
self.host = h self.host = h
self.start_delay: float | None = None self.start_delay: float | None = None
self.end_delay: float | None = None self.end_delay: float | None = None
self.wait = True self.wait = True
@abc.abstractmethod @abc.abstractmethod
def run_cmds(self, env: expenv.ExpEnv) -> list[str]: def run_cmds(self, inst: inst_base.Instantiation) -> list[str]:
"""Commands to run on node.""" """Commands to run on node."""
return [] return []
def cleanup_cmds(self, env: expenv.ExpEnv) -> list[str]: def cleanup_cmds(self, inst: inst_base.Instantiation) -> list[str]:
"""Commands to run to cleanup node.""" """Commands to run to cleanup node."""
if self.end_delay is None: if self.end_delay is None:
return [] return []
else: else:
return [f'sleep {self.start_delay}'] return [f'sleep {self.start_delay}']
def config_files(self, env: expenv.ExpEnv) -> dict[str, tp.IO]: def config_files(self, inst: inst_base.Instantiation) -> dict[str, tp.IO]:
""" """
Additional files to put inside the node, which are mounted under Additional files to put inside the node, which are mounted under
`/tmp/guest/`. `/tmp/guest/`.
...@@ -64,11 +66,11 @@ class BaseLinuxApplication(abc.ABC): # TODO: FIXME!!! ...@@ -64,11 +66,11 @@ class BaseLinuxApplication(abc.ABC): # TODO: FIXME!!!
""" """
return {} return {}
def prepare_pre_cp(self, env: expenv.ExpEnv) -> list[str]: def prepare_pre_cp(self, inst: inst_base.Instantiation) -> list[str]:
"""Commands to run to prepare node before checkpointing.""" """Commands to run to prepare node before checkpointing."""
return [] return []
def prepare_post_cp(self, env: expenv.ExpEnv) -> list[str]: def prepare_post_cp(self, inst: inst_base.Instantiation) -> list[str]:
"""Commands to run to prepare node after checkpoint restore.""" """Commands to run to prepare node after checkpoint restore."""
if self.end_delay is None: if self.end_delay is None:
return [] return []
...@@ -87,39 +89,39 @@ class BaseLinuxApplication(abc.ABC): # TODO: FIXME!!! ...@@ -87,39 +89,39 @@ class BaseLinuxApplication(abc.ABC): # TODO: FIXME!!!
class PingClient(BaseLinuxApplication): class PingClient(BaseLinuxApplication):
def __init__(self, h: 'LinuxHost', server_ip: str = '192.168.64.1') -> None: def __init__(self, h: sys_host.LinuxHost, server_ip: str = '192.168.64.1') -> None:
super().__init__(h) super().__init__(h)
self.server_ip = server_ip self.server_ip = server_ip
def run_cmds(self, env: expenv.ExpEnv) -> tp.List[str]: def run_cmds(self, inst: inst_base.Instantiation) -> tp.List[str]:
return [f'ping {self.server_ip} -c 10'] return [f'ping {self.server_ip} -c 10']
class Sleep(BaseLinuxApplication): class Sleep(BaseLinuxApplication):
def __init__(self, h: 'LinuxHost', delay: float = 10) -> None: def __init__(self, h: sys_host.LinuxHost, delay: float = 10) -> None:
super().__init__(h) super().__init__(h)
self.delay = delay self.delay = delay
def run_cmds(self, env: expenv.ExpEnv) -> tp.List[str]: def run_cmds(self, inst: inst_base.Instantiation) -> tp.List[str]:
return [f'sleep {self.delay}'] return [f'sleep {self.delay}']
class NetperfServer(BaseLinuxApplication): class NetperfServer(BaseLinuxApplication):
def __init__(self, h: 'LinuxHost') -> None: def __init__(self, h: sys_host.LinuxHost) -> None:
super().__init__(h) super().__init__(h)
def run_cmds(self, env: expenv.ExpEnv) -> tp.List[str]: def run_cmds(self, inst: inst_base.Instantiation) -> tp.List[str]:
return ['netserver', 'sleep infinity'] return ['netserver', 'sleep infinity']
class NetperfClient(BaseLinuxApplication): class NetperfClient(BaseLinuxApplication):
def __init__(self, h: 'LinuxHost', server_ip: str = '192.168.64.1') -> None: def __init__(self, h: sys_host.LinuxHost, server_ip: str = '192.168.64.1') -> None:
super().__init__(h) super().__init__(h)
self.server_ip = server_ip self.server_ip = server_ip
self.duration_tp = 10 self.duration_tp = 10
self.duration_lat = 10 self.duration_lat = 10
def run_cmds(self, env: expenv.ExpEnv) -> tp.List[str]: def run_cmds(self, inst: inst_base.Instantiation) -> tp.List[str]:
return [ return [
'netserver', 'netserver',
'sleep 0.5', 'sleep 0.5',
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import annotations
import typing as tp import typing as tp
import io import io
import asyncio import asyncio
...@@ -30,7 +32,6 @@ from simbricks.orchestration.system import eth as eth ...@@ -30,7 +32,6 @@ from simbricks.orchestration.system import eth as eth
from simbricks.orchestration.system.host import app from simbricks.orchestration.system.host import app
if tp.TYPE_CHECKING: if tp.TYPE_CHECKING:
from simbricks.orchestration.system import eth, mem, pcie
from simbricks.orchestration.system.host import disk_images from simbricks.orchestration.system.host import disk_images
...@@ -56,9 +57,9 @@ class FullSystemHost(Host): ...@@ -56,9 +57,9 @@ class FullSystemHost(Host):
self.memory = 512 self.memory = 512
self.cores = 1 self.cores = 1
self.cpu_freq = "3GHz" self.cpu_freq = "3GHz"
self.disks: list["DiskImage"] = [] self.disks: list[disk_images.DiskImage] = []
def add_disk(self, disk: "DiskImage") -> None: def add_disk(self, disk: disk_images.DiskImage) -> None:
self.disks.append(disk) self.disks.append(disk)
async def prepare(self, inst: instantiation.Instantiation) -> None: async def prepare(self, inst: instantiation.Instantiation) -> None:
...@@ -80,7 +81,7 @@ class BaseLinuxHost(FullSystemHost): ...@@ -80,7 +81,7 @@ class BaseLinuxHost(FullSystemHost):
self, self,
inst: instantiation.Instantiation, inst: instantiation.Instantiation,
mapper: tp.Callable[ mapper: tp.Callable[
["BaseLinuxApplication", instantiation.Instantiation], list[str] [app.BaseLinuxApplication, instantiation.Instantiation], list[str]
], ],
) -> list[str]: ) -> list[str]:
""" """
...@@ -111,7 +112,7 @@ class BaseLinuxHost(FullSystemHost): ...@@ -111,7 +112,7 @@ class BaseLinuxHost(FullSystemHost):
""" """
cfg_files = {} cfg_files = {}
for app in self.applications: for app in self.applications:
cfg_files |= self.applications[0].config_files(inst) cfg_files |= app.config_files(inst)
return cfg_files return cfg_files
def prepare_pre_cp(self, inst: instantiation.Instantiation) -> list[str]: def prepare_pre_cp(self, inst: instantiation.Instantiation) -> list[str]:
...@@ -122,13 +123,13 @@ class BaseLinuxHost(FullSystemHost): ...@@ -122,13 +123,13 @@ class BaseLinuxHost(FullSystemHost):
"""Commands to run to prepare node after checkpoint restore.""" """Commands to run to prepare node after checkpoint restore."""
return self._concat_app_cmds(inst, app.BaseLinuxApplication.prepare_post_cp) return self._concat_app_cmds(inst, app.BaseLinuxApplication.prepare_post_cp)
def _config_str(self, inst: instantiation.Instantiation) -> str: def config_str(self, inst: instantiation.Instantiation) -> str:
if inst.create_cp: if inst.create_cp():
cp_cmd = self.checkpoint_commands() sim = inst.find_sim_by_spec(spec=self)
cp_cmd = sim.checkpoint_commands()
else: else:
cp_cmd = [] cp_cmd = []
# TODO: FIXME
es = ( es = (
self.prepare_pre_cp(inst) self.prepare_pre_cp(inst)
+ self.applications[0].prepare_pre_cp(inst) + self.applications[0].prepare_pre_cp(inst)
...@@ -205,9 +206,6 @@ class I40ELinuxHost(LinuxHost): ...@@ -205,9 +206,6 @@ class I40ELinuxHost(LinuxHost):
super().__init__(sys) super().__init__(sys)
self.drivers.append("i40e") self.drivers.append("i40e")
def checkpoint_commands(self) -> list[str]:
return ["m5 checkpoint"]
class CorundumLinuxHost(LinuxHost): class CorundumLinuxHost(LinuxHost):
def __init__(self, sys) -> None: def __init__(self, sys) -> None:
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import annotations
import abc import abc
import io import io
import os.path import os.path
...@@ -27,13 +29,13 @@ import tarfile ...@@ -27,13 +29,13 @@ import tarfile
import typing as tp import typing as tp
from simbricks.orchestration.utils import base as utils_base from simbricks.orchestration.utils import base as utils_base
from simbricks.orchestration.instantiation import base as inst_base from simbricks.orchestration.instantiation import base as inst_base
from simbricks.orchestration.experiment import experiment_environment as expenv
if tp.TYPE_CHECKING: if tp.TYPE_CHECKING:
from simbricks.orchestration.system.host import base from simbricks.orchestration.system import host as sys_host
class DiskImage(utils_base.IdObj): class DiskImage(utils_base.IdObj):
def __init__(self, h: 'Host') -> None: def __init__(self, h: sys_host.Host) -> None:
self.host = None | str self.host = None | str
@abc.abstractmethod @abc.abstractmethod
...@@ -65,7 +67,7 @@ class DiskImage(utils_base.IdObj): ...@@ -65,7 +67,7 @@ class DiskImage(utils_base.IdObj):
# Disk image where user just provides a path # Disk image where user just provides a path
class ExternalDiskImage(DiskImage): class ExternalDiskImage(DiskImage):
def __init__(self, h: 'FullSystemHost', path: str) -> None: def __init__(self, h: sys_host.FullSystemHost, path: str) -> None:
super().__init__(h) super().__init__(h)
self.path = path self.path = path
self.formats = ["raw", "qcow2"] self.formats = ["raw", "qcow2"]
...@@ -80,7 +82,7 @@ class ExternalDiskImage(DiskImage): ...@@ -80,7 +82,7 @@ class ExternalDiskImage(DiskImage):
# Disk images shipped with simbricks # Disk images shipped with simbricks
class DistroDiskImage(DiskImage): class DistroDiskImage(DiskImage):
def __init__(self, h: 'FullSystemHost', name: str) -> None: def __init__(self, h: sys_host.FullSystemHost, name: str) -> None:
super().__init__(h) super().__init__(h)
self.name = name self.name = name
self.formats = ["raw", "qcow2"] self.formats = ["raw", "qcow2"]
...@@ -101,7 +103,7 @@ class DistroDiskImage(DiskImage): ...@@ -101,7 +103,7 @@ class DistroDiskImage(DiskImage):
# Abstract base class for dynamically generated images # Abstract base class for dynamically generated images
class DynamicDiskImage(DiskImage): class DynamicDiskImage(DiskImage):
def __init__(self, h: 'FullSystemHost') -> None: def __init__(self, h: sys_host.FullSystemHost) -> None:
super().__init__(h) super().__init__(h)
def path(self, inst: inst_base.Instantiation, format: str) -> str: def path(self, inst: inst_base.Instantiation, format: str) -> str:
...@@ -113,9 +115,9 @@ class DynamicDiskImage(DiskImage): ...@@ -113,9 +115,9 @@ class DynamicDiskImage(DiskImage):
# Builds the Tar with the commands to run etc. # Builds the Tar with the commands to run etc.
class LinuxConfigDiskImage(DynamicDiskImage): class LinuxConfigDiskImage(DynamicDiskImage):
def __init__(self, h: 'LinuxHost') -> None: def __init__(self, h: sys_host.LinuxHost) -> None:
super().__init__(h) super().__init__(h)
self.host: base.LinuxHost self.host: sys_host.LinuxHost
def available_formats(self) -> list[str]: def available_formats(self) -> list[str]:
return ["raw"] return ["raw"]
...@@ -126,7 +128,7 @@ class LinuxConfigDiskImage(DynamicDiskImage): ...@@ -126,7 +128,7 @@ class LinuxConfigDiskImage(DynamicDiskImage):
# add main run script # add main run script
cfg_i = tarfile.TarInfo('guest/run.sh') cfg_i = tarfile.TarInfo('guest/run.sh')
cfg_i.mode = 0o777 cfg_i.mode = 0o777
cfg_f = self.host.strfile(self.host._config_str(inst)) cfg_f = self.host.strfile(self.host.config_str(inst))
cfg_f.seek(0, io.SEEK_END) cfg_f.seek(0, io.SEEK_END)
cfg_i.size = cfg_f.tell() cfg_i.size = cfg_f.tell()
cfg_f.seek(0, io.SEEK_SET) cfg_f.seek(0, io.SEEK_SET)
...@@ -149,7 +151,7 @@ class LinuxConfigDiskImage(DynamicDiskImage): ...@@ -149,7 +151,7 @@ class LinuxConfigDiskImage(DynamicDiskImage):
# Could of course also have a version that generates the packer config from # Could of course also have a version that generates the packer config from
# python # python
class PackerDiskImage(DynamicDiskImage): class PackerDiskImage(DynamicDiskImage):
def __init__(self, h: 'FullSystemHost', packer_config_path: str) -> None: def __init__(self, h: sys_host.FullSystemHost, packer_config_path: str) -> None:
super().__init__(h) super().__init__(h)
self.config_path = packer_config_path self.config_path = packer_config_path
......
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