Unverified Commit 79b2ee78 authored by Jakob Görgen's avatar Jakob Görgen
Browse files

deserialization of simulation json

parent f779730a
...@@ -48,11 +48,11 @@ class Simulator(utils_base.IdObj): ...@@ -48,11 +48,11 @@ class Simulator(utils_base.IdObj):
) -> None: ) -> None:
super().__init__() super().__init__()
self.name: str = name self.name: str = name
self._executable = executable self._executable: str = executable
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
self._start_tick = 0 self._start_tick: int = 0
"""The timestamp at which to start the simulation. This is useful when """The timestamp at which to start the simulation. This is useful when
the simulator is only attached at a later point in time and needs to the simulator is only attached at a later point in time and needs to
synchronize with connected simulators. For example, this could be used synchronize with connected simulators. For example, this could be used
...@@ -116,14 +116,33 @@ class Simulator(utils_base.IdObj): ...@@ -116,14 +116,33 @@ class Simulator(utils_base.IdObj):
json_obj["wait"] = self._wait json_obj["wait"] = self._wait
json_obj["start_tick"] = self._start_tick json_obj["start_tick"] = self._start_tick
if self._extra_args:
json_obj["extra_args"] = self._extra_args json_obj["extra_args"] = self._extra_args
return json_obj return json_obj
@staticmethod @classmethod
def fromJSON(json_obj): def fromJSON(cls, simulation: Simulation, json_obj: dict) -> Simulator:
# TODO: FIXME instance = super().fromJSON(json_obj)
pass instance.name = utils_base.get_json_attr_top(json_obj, "name")
instance._executable = utils_base.get_json_attr_top(json_obj, "executable")
sim_id = int(utils_base.get_json_attr_top(json_obj, "simulation"))
assert sim_id == simulation.id()
instance._simulation = simulation
instance._components = set()
components_json = utils_base.get_json_attr_top(json_obj, "components")
for comp_id in components_json:
component = simulation.system.get_comp(comp_id)
Simulator.add(instance, component)
# instance.add(component)
instance._wait = bool(utils_base.get_json_attr_top(json_obj, "wait"))
instance._start_tick = int(utils_base.get_json_attr_top(json_obj, "start_tick"))
instance._extra_args = utils_base.get_json_attr_top_or_none(
json_obj, "extra_args"
)
return instance
@staticmethod @staticmethod
def filter_sockets( def filter_sockets(
...@@ -329,7 +348,6 @@ class Simulation(utils_base.IdObj): ...@@ -329,7 +348,6 @@ class Simulation(utils_base.IdObj):
json_obj["name"] = self.name json_obj["name"] = self.name
json_obj["system"] = self.system.id() json_obj["system"] = self.system.id()
if self.timeout:
json_obj["timeout"] = self.timeout json_obj["timeout"] = self.timeout
simulators_json = [] simulators_json = []
...@@ -339,11 +357,12 @@ class Simulation(utils_base.IdObj): ...@@ -339,11 +357,12 @@ class Simulation(utils_base.IdObj):
json_obj["sim_list"] = simulators_json json_obj["sim_list"] = simulators_json
sys_sim_map_json = [] # TODO: we do not need this --> we can create it implicitly when deserializing because the simulators store a list of components themselves
for comp, sim in self._sys_sim_map.items(): # sys_sim_map_json = []
sys_sim_map_json.append({comp.id(): sim.id()}) # for comp, sim in self._sys_sim_map.items():
# sys_sim_map_json.append([comp.id(), sim.id()])
json_obj["sys_sim_map"] = sys_sim_map_json # json_obj["sys_sim_map"] = sys_sim_map_json
chan_map_json = [] chan_map_json = []
chan_json = [] chan_json = []
...@@ -351,19 +370,54 @@ class Simulation(utils_base.IdObj): ...@@ -351,19 +370,54 @@ class Simulation(utils_base.IdObj):
sys_chan, sys_chan,
sim_chan, sim_chan,
) in self._chan_map.items(): ) in self._chan_map.items():
chan_map_json.append({sys_chan.id(): sim_chan.id()})
utils_base.has_attribute(sim_chan, "toJSON") utils_base.has_attribute(sim_chan, "toJSON")
chan_json.append(sim_chan.toJSON()) chan_json = sim_chan.toJSON()
chan_map_json.append([sys_chan.id(), chan_json])
# chan_json.append(sim_chan.toJSON())
json_obj["chan_map"] = chan_map_json json_obj["chan_map"] = chan_map_json
json_obj["simulation_channels"] = chan_json # json_obj["simulation_channels"] = chan_json
return json_obj return json_obj
@staticmethod @classmethod
def fromJSON(json_obj): def fromJSON(cls, system: sys_conf.System, json_obj: dict) -> Simulation:
# TODO: FIXME instance = super().fromJSON(json_obj)
pass
instance.name = utils_base.get_json_attr_top(json_obj, "name")
system_id = int(utils_base.get_json_attr_top(json_obj, "system"))
assert system_id == system.id()
instance.system = system
instance.timeout = utils_base.get_json_attr_top_or_none(json_obj, "timeout")
instance._sim_list = []
instance._sys_sim_map = {}
simulators_json = utils_base.get_json_attr_top(json_obj, "sim_list")
for sim_json in simulators_json:
sim_class = utils_base.get_cls_by_json(sim_json)
utils_base.has_attribute(sim_class, "fromJSON")
sim = sim_class.fromJSON(instance, sim_json)
instance._sim_list.append(sim)
# TODO: probably do not need this --> we create it when deserializing the simulators that store a list of components themselves
# instance._sys_sim_map: dict[sys_conf.Component, Simulator] = {}
# sys_sim_map_json = utils_base.get_json_attr_top(json_obj, "sys_sim_map")
# print(sys_sim_map_json)
# for sys_id, sim_id in sys_sim_map_json:
# print(f"{sys_id} --> {sim_id}")
# # TODO
# pass
instance._chan_map = {}
chan_map_json = utils_base.get_json_attr_top(json_obj, "chan_map")
for sys_id, chan_json in chan_map_json:
chan_class = utils_base.get_cls_by_json(chan_json)
utils_base.has_attribute(chan_class, "fromJSON")
sim_chan = chan_class.fromJSON(instance, chan_json)
sys_chan = instance.system.get_chan(sys_id)
instance.update_channel_mapping(sys_chan=sys_chan, sim_chan=sim_chan)
return instance
def add_sim(self, sim: Simulator): def add_sim(self, sim: Simulator):
if sim in self._sim_list: if sim in self._sim_list:
...@@ -379,12 +433,21 @@ class Simulation(utils_base.IdObj): ...@@ -379,12 +433,21 @@ class Simulation(utils_base.IdObj):
def is_channel_instantiated(self, chan: sys_conf.Channel) -> bool: def is_channel_instantiated(self, chan: sys_conf.Channel) -> bool:
return chan in self._chan_map return chan in self._chan_map
def update_channel_mapping(
self, sys_chan: sys_conf.Channel, sim_chan: sim_chan.Channel
) -> None:
if self.is_channel_instantiated(sys_chan):
raise Exception(
f"channel {sys_chan} is already mapped. Cannot insert mapping {sys_chan.id()} -> {sim_chan.id()}"
)
self._chan_map[sys_chan] = sim_chan
def retrieve_or_create_channel(self, chan: sys_conf.Channel) -> sim_chan.Channel: def retrieve_or_create_channel(self, chan: sys_conf.Channel) -> sim_chan.Channel:
if self.is_channel_instantiated(chan): if self.is_channel_instantiated(chan):
return self._chan_map[chan] return self._chan_map[chan]
channel = sim_chan.Channel(chan) channel = sim_chan.Channel(chan)
self._chan_map[chan] = channel self.update_channel_mapping(sys_chan=chan, sim_chan=channel)
return channel return channel
def all_simulators(self) -> list[Simulator]: def all_simulators(self) -> list[Simulator]:
......
...@@ -20,8 +20,11 @@ ...@@ -20,8 +20,11 @@
# 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 enum import enum
from simbricks.orchestration.simulation import base as sim_base
from simbricks.orchestration.system import base as system_base from simbricks.orchestration.system import base as system_base
from simbricks.orchestration.utils import base as utils_base from simbricks.orchestration.utils import base as utils_base
...@@ -51,10 +54,18 @@ class Channel(utils_base.IdObj): ...@@ -51,10 +54,18 @@ class Channel(utils_base.IdObj):
json_obj["sys_channel"] = self.sys_channel.id() json_obj["sys_channel"] = self.sys_channel.id()
return json_obj return json_obj
@staticmethod @classmethod
def fromJSON(json_obj): def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> Channel:
# TODO instance = super().fromJSON(json_obj)
pass instance._synchronized = bool(
utils_base.get_json_attr_top(json_obj, "synchronized")
)
instance.sync_period = int(
utils_base.get_json_attr_top(json_obj, "sync_period")
)
chan_id = int(utils_base.get_json_attr_top(json_obj, "sys_channel"))
instance.sys_channel = simulation.system.get_chan(chan_id)
return instance
def full_name(self) -> str: def full_name(self) -> str:
return "channel." + self.name return "channel." + self.name
......
...@@ -38,6 +38,13 @@ class HostSim(sim_base.Simulator): ...@@ -38,6 +38,13 @@ class HostSim(sim_base.Simulator):
def __init__(self, simulation: sim_base.Simulation, executable: str, name=""): def __init__(self, simulation: sim_base.Simulation, executable: str, name=""):
super().__init__(simulation=simulation, executable=executable, name=name) super().__init__(simulation=simulation, executable=executable, name=name)
def toJSON(self) -> dict:
return super().toJSON()
@classmethod
def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> Gem5Sim:
return super().fromJSON(simulation, json_obj)
def full_name(self) -> str: def full_name(self) -> str:
return "host." + self.name return "host." + self.name
...@@ -92,10 +99,20 @@ class Gem5Sim(HostSim): ...@@ -92,10 +99,20 @@ class Gem5Sim(HostSim):
json_obj["_sys_clock"] = self._sys_clock json_obj["_sys_clock"] = self._sys_clock
return json_obj return json_obj
@staticmethod @classmethod
def fromJSON(json_obj): def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> Gem5Sim:
# TODO: FIXME instance = super().fromJSON(simulation, json_obj)
pass instance.cpu_type_cp = utils_base.get_json_attr_top(json_obj, "cpu_type_cp")
instance.cpu_type = utils_base.get_json_attr_top(json_obj, "cpu_type")
instance.extra_main_args = utils_base.get_json_attr_top(
json_obj, "extra_main_args"
)
instance.extra_config_args = utils_base.get_json_attr_top(
json_obj, "extra_config_args"
)
instance._variant = utils_base.get_json_attr_top(json_obj, "_variant")
instance._sys_clock = utils_base.get_json_attr_top(json_obj, "_sys_clock")
return instance
async def prepare(self, inst: inst_base.Instantiation) -> None: async def prepare(self, inst: inst_base.Instantiation) -> None:
await super().prepare(inst=inst) await super().prepare(inst=inst)
...@@ -237,10 +254,9 @@ class QemuSim(HostSim): ...@@ -237,10 +254,9 @@ class QemuSim(HostSim):
# disks is created upon invocation of "prepare", hence we do not need to serialize it # disks is created upon invocation of "prepare", hence we do not need to serialize it
return json_obj return json_obj
@staticmethod @classmethod
def fromJSON(json_obj): def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> QemuSim:
# TODO: FIXME return super().fromJSON(simulation, json_obj)
pass
async def prepare(self, inst: inst_base.Instantiation) -> None: async def prepare(self, inst: inst_base.Instantiation) -> None:
await super().prepare(inst=inst) await super().prepare(inst=inst)
...@@ -331,4 +347,5 @@ class QemuSim(HostSim): ...@@ -331,4 +347,5 @@ class QemuSim(HostSim):
cmd += ",sync=off" cmd += ",sync=off"
cmd += " " cmd += " "
print(cmd)
return cmd return cmd
...@@ -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
from simbricks.orchestration.system import base as sys_base from simbricks.orchestration.system import base as sys_base
from simbricks.orchestration.system import eth as sys_eth from simbricks.orchestration.system import eth as sys_eth
from simbricks.orchestration.simulation import base as sim_base from simbricks.orchestration.simulation import base as sim_base
...@@ -51,13 +53,11 @@ class NetSim(sim_base.Simulator): ...@@ -51,13 +53,11 @@ class NetSim(sim_base.Simulator):
def toJSON(self) -> dict: def toJSON(self) -> dict:
json_obj = super().toJSON() json_obj = super().toJSON()
# TODO: FIXME
return json_obj return json_obj
@staticmethod @classmethod
def fromJSON(json_obj): def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> NetSim:
# TODO: FIXME return super().fromJSON(simulation, json_obj)
pass
class WireNet(NetSim): class WireNet(NetSim):
...@@ -85,10 +85,11 @@ class WireNet(NetSim): ...@@ -85,10 +85,11 @@ class WireNet(NetSim):
json_obj["relative_pcap_file_path"] = self._relative_pcap_file_path json_obj["relative_pcap_file_path"] = self._relative_pcap_file_path
return json_obj return json_obj
@staticmethod @classmethod
def fromJSON(json_obj): def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> WireNet:
instance = super().fromJSON(simulation, json_obj)
# TODO: FIXME # TODO: FIXME
pass return instance
def run_cmd(self, inst: inst_base.Instantiation) -> str: def run_cmd(self, inst: inst_base.Instantiation) -> str:
channels = self.get_channels() channels = self.get_channels()
...@@ -136,10 +137,11 @@ class SwitchNet(NetSim): ...@@ -136,10 +137,11 @@ class SwitchNet(NetSim):
json_obj["relative_pcap_file_path"] = self._relative_pcap_file_path json_obj["relative_pcap_file_path"] = self._relative_pcap_file_path
return json_obj return json_obj
@staticmethod @classmethod
def fromJSON(json_obj): def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> SwitchNet:
instance = super().fromJSON(simulation, json_obj)
# TODO: FIXME # TODO: FIXME
pass return instance
def run_cmd(self, inst: inst_base.Instantiation) -> str: def run_cmd(self, inst: inst_base.Instantiation) -> str:
channels = self.get_channels() channels = self.get_channels()
...@@ -189,10 +191,11 @@ class MemSwitchNet(SwitchNet): ...@@ -189,10 +191,11 @@ class MemSwitchNet(SwitchNet):
json_obj = super().toJSON() json_obj = super().toJSON()
return json_obj return json_obj
@staticmethod @classmethod
def fromJSON(json_obj): def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> MemSwitchNet:
instance = super().fromJSON(simulation, json_obj)
# TODO: FIXME # TODO: FIXME
pass return instance
def run_cmd(self, inst: inst_base.Instantiation) -> str: def run_cmd(self, inst: inst_base.Instantiation) -> str:
cmd = super().run_cmd(inst) cmd = super().run_cmd(inst)
...@@ -224,14 +227,17 @@ class SimpleNS3Sim(NetSim): ...@@ -224,14 +227,17 @@ class SimpleNS3Sim(NetSim):
def toJSON(self) -> dict: def toJSON(self) -> dict:
json_obj = super().toJSON() json_obj = super().toJSON()
json_obj["ns3_run_script"] = self._ns3_run_script json_obj["ns3_run_script"] = self._ns3_run_script
if self.opt:
json_obj["opt"] = self.opt json_obj["opt"] = self.opt
return json_obj return json_obj
@staticmethod @classmethod
def fromJSON(json_obj): def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> SimpleNS3Sim:
# TODO: FIXME instance = super().fromJSON(simulation, json_obj)
pass instance._ns3_run_script = base_utils.get_json_attr_top(
json_obj, "ns3_run_script"
)
instance.opt = base_utils.get_json_attr_top_or_none(json_obj, "opt")
return instance
def run_cmd(self, inst: inst_base.Instantiation) -> str: def run_cmd(self, inst: inst_base.Instantiation) -> str:
return f"{inst.join_repo_base(self._executable)} {self._ns3_run_script} " return f"{inst.join_repo_base(self._executable)} {self._ns3_run_script} "
...@@ -270,10 +276,16 @@ class NS3DumbbellNet(SimpleNS3Sim): ...@@ -270,10 +276,16 @@ class NS3DumbbellNet(SimpleNS3Sim):
json_obj["right"] = self._right.id() json_obj["right"] = self._right.id()
return json_obj return json_obj
@staticmethod @classmethod
def fromJSON(json_obj): def fromJSON(
# TODO: FIXME cls, simulation: sim_base.Simulation, json_obj: dict
pass ) -> NS3DumbbellNet:
instance = super().fromJSON(simulation, json_obj)
left_id = int(base_utils.get_json_attr_top(json_obj, "left"))
instance._left = json_obj["left"] = simulation.system.get_comp(left_id)
right_id = int(base_utils.get_json_attr_top(json_obj, "right"))
instance._right = json_obj["right"] = simulation.system.get_comp(right_id)
return instance
def run_cmd(self, inst: inst_base.Instantiation) -> str: def run_cmd(self, inst: inst_base.Instantiation) -> str:
cmd = super().run_cmd(inst=inst) cmd = super().run_cmd(inst=inst)
...@@ -291,6 +303,7 @@ class NS3DumbbellNet(SimpleNS3Sim): ...@@ -291,6 +303,7 @@ class NS3DumbbellNet(SimpleNS3Sim):
if self.opt is not None: if self.opt is not None:
cmd += f"{self.opt}" cmd += f"{self.opt}"
print(cmd)
return cmd return cmd
...@@ -313,10 +326,11 @@ class NS3BridgeNet(SimpleNS3Sim): ...@@ -313,10 +326,11 @@ class NS3BridgeNet(SimpleNS3Sim):
json_obj = super().toJSON() json_obj = super().toJSON()
return json_obj return json_obj
@staticmethod @classmethod
def fromJSON(json_obj): def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> NS3BridgeNet:
instance = super().fromJSON(simulation, json_obj)
# TODO: FIXME # TODO: FIXME
pass return instance
def run_cmd(self, inst: inst_base.Instantiation) -> str: def run_cmd(self, inst: inst_base.Instantiation) -> str:
cmd = super().run_cmd(inst=inst) cmd = super().run_cmd(inst=inst)
......
...@@ -110,10 +110,9 @@ class I40eNicSim(NICSim): ...@@ -110,10 +110,9 @@ class I40eNicSim(NICSim):
json_obj = super().toJSON() json_obj = super().toJSON()
return json_obj return json_obj
@staticmethod @classmethod
def fromJSON(json_obj): def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> I40eNicSim:
# TODO: FIXME return super().fromJSON(simulation, json_obj)
pass
def run_cmd(self, inst: inst_base.Instantiation) -> str: def run_cmd(self, inst: inst_base.Instantiation) -> str:
return super().run_cmd(inst=inst) return super().run_cmd(inst=inst)
...@@ -131,10 +130,11 @@ class CorundumBMNICSim(NICSim): ...@@ -131,10 +130,11 @@ class CorundumBMNICSim(NICSim):
json_obj = super().toJSON() json_obj = super().toJSON()
return json_obj return json_obj
@staticmethod @classmethod
def fromJSON(json_obj): def fromJSON(
# TODO: FIXME cls, simulation: sim_base.Simulation, json_obj: dict
pass ) -> CorundumBMNICSim:
return super().fromJSON(simulation, json_obj)
def run_cmd(self, inst: inst_base.Instantiation) -> str: def run_cmd(self, inst: inst_base.Instantiation) -> str:
cmd = super().run_cmd(inst=inst) cmd = super().run_cmd(inst=inst)
...@@ -160,10 +160,11 @@ class CorundumVerilatorNICSim(NICSim): ...@@ -160,10 +160,11 @@ class CorundumVerilatorNICSim(NICSim):
json_obj["clock_freq"] = self.clock_freq json_obj["clock_freq"] = self.clock_freq
return json_obj return json_obj
@staticmethod @classmethod
def fromJSON(json_obj): def fromJSON(
# TODO: FIXME cls, simulation: sim_base.Simulation, json_obj: dict
pass ) -> CorundumVerilatorNICSim:
return super().fromJSON(simulation, json_obj)
def run_cmd(self, inst: inst_base.Instantiation) -> str: def run_cmd(self, inst: inst_base.Instantiation) -> str:
cmd = super().run_cmd(inst=inst) cmd = super().run_cmd(inst=inst)
......
...@@ -45,7 +45,9 @@ class System(util_base.IdObj): ...@@ -45,7 +45,9 @@ class System(util_base.IdObj):
self._all_components[c.id()] = c self._all_components[c.id()] = c
def get_comp(self, ident: int) -> Component: def get_comp(self, ident: int) -> Component:
assert ident in self._all_components if ident not in self._all_components:
raise Exception(f"system object does not store component with id {ident}")
return self._all_components[ident] return self._all_components[ident]
def _add_interface(self, i: Interface) -> None: def _add_interface(self, i: Interface) -> None:
...@@ -54,7 +56,9 @@ class System(util_base.IdObj): ...@@ -54,7 +56,9 @@ class System(util_base.IdObj):
self._all_interfaces[i.id()] = i self._all_interfaces[i.id()] = i
def get_inf(self, ident: int) -> Interface: def get_inf(self, ident: int) -> Interface:
assert ident in self._all_interfaces if ident not in self._all_interfaces:
raise Exception(f"system object does not store interface with id {ident}")
return self._all_interfaces[ident] return self._all_interfaces[ident]
def _add_channel(self, c: Channel) -> None: def _add_channel(self, c: Channel) -> None:
...@@ -63,7 +67,9 @@ class System(util_base.IdObj): ...@@ -63,7 +67,9 @@ class System(util_base.IdObj):
self._all_channels[c.id()] = c self._all_channels[c.id()] = c
def get_chan(self, ident: int) -> Channel: def get_chan(self, ident: int) -> Channel:
assert ident in self._all_channels if ident not in self._all_channels:
raise Exception(f"system does not store channel with id {ident}")
return self._all_channels[ident] return self._all_channels[ident]
def toJSON(self) -> dict: def toJSON(self) -> dict:
......
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