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):
) -> None:
super().__init__()
self.name: str = name
self._executable = executable
self._executable: str = executable
self._simulation: sim_base.Simulation = simulation
self._components: set[sys_conf.Component] = set()
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 simulator is only attached at a later point in time and needs to
synchronize with connected simulators. For example, this could be used
......@@ -116,14 +116,33 @@ class Simulator(utils_base.IdObj):
json_obj["wait"] = self._wait
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
@staticmethod
def fromJSON(json_obj):
# TODO: FIXME
pass
@classmethod
def fromJSON(cls, simulation: Simulation, json_obj: dict) -> Simulator:
instance = super().fromJSON(json_obj)
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
def filter_sockets(
......@@ -329,8 +348,7 @@ class Simulation(utils_base.IdObj):
json_obj["name"] = self.name
json_obj["system"] = self.system.id()
if self.timeout:
json_obj["timeout"] = self.timeout
json_obj["timeout"] = self.timeout
simulators_json = []
for sim in self._sim_list:
......@@ -339,11 +357,12 @@ class Simulation(utils_base.IdObj):
json_obj["sim_list"] = simulators_json
sys_sim_map_json = []
for comp, sim in self._sys_sim_map.items():
sys_sim_map_json.append({comp.id(): sim.id()})
# TODO: we do not need this --> we can create it implicitly when deserializing because the simulators store a list of components themselves
# sys_sim_map_json = []
# 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_json = []
......@@ -351,19 +370,54 @@ class Simulation(utils_base.IdObj):
sys_chan,
sim_chan,
) in self._chan_map.items():
chan_map_json.append({sys_chan.id(): sim_chan.id()})
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["simulation_channels"] = chan_json
# json_obj["simulation_channels"] = chan_json
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO: FIXME
pass
@classmethod
def fromJSON(cls, system: sys_conf.System, json_obj: dict) -> Simulation:
instance = super().fromJSON(json_obj)
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):
if sim in self._sim_list:
......@@ -379,12 +433,21 @@ class Simulation(utils_base.IdObj):
def is_channel_instantiated(self, chan: sys_conf.Channel) -> bool:
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:
if self.is_channel_instantiated(chan):
return self._chan_map[chan]
channel = sim_chan.Channel(chan)
self._chan_map[chan] = channel
self.update_channel_mapping(sys_chan=chan, sim_chan=channel)
return channel
def all_simulators(self) -> list[Simulator]:
......
......@@ -20,8 +20,11 @@
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import annotations
import enum
from simbricks.orchestration.simulation import base as sim_base
from simbricks.orchestration.system import base as system_base
from simbricks.orchestration.utils import base as utils_base
......@@ -51,10 +54,18 @@ class Channel(utils_base.IdObj):
json_obj["sys_channel"] = self.sys_channel.id()
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> Channel:
instance = super().fromJSON(json_obj)
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:
return "channel." + self.name
......
......@@ -38,6 +38,13 @@ class HostSim(sim_base.Simulator):
def __init__(self, simulation: sim_base.Simulation, executable: str, 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:
return "host." + self.name
......@@ -92,10 +99,20 @@ class Gem5Sim(HostSim):
json_obj["_sys_clock"] = self._sys_clock
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO: FIXME
pass
@classmethod
def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> Gem5Sim:
instance = super().fromJSON(simulation, json_obj)
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:
await super().prepare(inst=inst)
......@@ -237,10 +254,9 @@ class QemuSim(HostSim):
# disks is created upon invocation of "prepare", hence we do not need to serialize it
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO: FIXME
pass
@classmethod
def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> QemuSim:
return super().fromJSON(simulation, json_obj)
async def prepare(self, inst: inst_base.Instantiation) -> None:
await super().prepare(inst=inst)
......@@ -331,4 +347,5 @@ class QemuSim(HostSim):
cmd += ",sync=off"
cmd += " "
print(cmd)
return cmd
......@@ -20,6 +20,8 @@
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# 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 eth as sys_eth
from simbricks.orchestration.simulation import base as sim_base
......@@ -51,13 +53,11 @@ class NetSim(sim_base.Simulator):
def toJSON(self) -> dict:
json_obj = super().toJSON()
# TODO: FIXME
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO: FIXME
pass
@classmethod
def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> NetSim:
return super().fromJSON(simulation, json_obj)
class WireNet(NetSim):
......@@ -85,10 +85,11 @@ class WireNet(NetSim):
json_obj["relative_pcap_file_path"] = self._relative_pcap_file_path
return json_obj
@staticmethod
def fromJSON(json_obj):
@classmethod
def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> WireNet:
instance = super().fromJSON(simulation, json_obj)
# TODO: FIXME
pass
return instance
def run_cmd(self, inst: inst_base.Instantiation) -> str:
channels = self.get_channels()
......@@ -136,10 +137,11 @@ class SwitchNet(NetSim):
json_obj["relative_pcap_file_path"] = self._relative_pcap_file_path
return json_obj
@staticmethod
def fromJSON(json_obj):
@classmethod
def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> SwitchNet:
instance = super().fromJSON(simulation, json_obj)
# TODO: FIXME
pass
return instance
def run_cmd(self, inst: inst_base.Instantiation) -> str:
channels = self.get_channels()
......@@ -189,10 +191,11 @@ class MemSwitchNet(SwitchNet):
json_obj = super().toJSON()
return json_obj
@staticmethod
def fromJSON(json_obj):
@classmethod
def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> MemSwitchNet:
instance = super().fromJSON(simulation, json_obj)
# TODO: FIXME
pass
return instance
def run_cmd(self, inst: inst_base.Instantiation) -> str:
cmd = super().run_cmd(inst)
......@@ -224,14 +227,17 @@ class SimpleNS3Sim(NetSim):
def toJSON(self) -> dict:
json_obj = super().toJSON()
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
@staticmethod
def fromJSON(json_obj):
# TODO: FIXME
pass
@classmethod
def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> SimpleNS3Sim:
instance = super().fromJSON(simulation, json_obj)
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:
return f"{inst.join_repo_base(self._executable)} {self._ns3_run_script} "
......@@ -270,10 +276,16 @@ class NS3DumbbellNet(SimpleNS3Sim):
json_obj["right"] = self._right.id()
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO: FIXME
pass
@classmethod
def fromJSON(
cls, simulation: sim_base.Simulation, json_obj: dict
) -> 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:
cmd = super().run_cmd(inst=inst)
......@@ -291,6 +303,7 @@ class NS3DumbbellNet(SimpleNS3Sim):
if self.opt is not None:
cmd += f"{self.opt}"
print(cmd)
return cmd
......@@ -313,10 +326,11 @@ class NS3BridgeNet(SimpleNS3Sim):
json_obj = super().toJSON()
return json_obj
@staticmethod
def fromJSON(json_obj):
@classmethod
def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> NS3BridgeNet:
instance = super().fromJSON(simulation, json_obj)
# TODO: FIXME
pass
return instance
def run_cmd(self, inst: inst_base.Instantiation) -> str:
cmd = super().run_cmd(inst=inst)
......
......@@ -73,7 +73,7 @@ class NICSim(PCIDevSim):
nic_devices = self.filter_components_by_type(ty=sys_nic.SimplePCIeNIC)
assert len(nic_devices) == 1
nic_device = nic_devices[0]
socket = inst.get_socket(interface=nic_device._pci_if)
assert socket is not None and socket._type == inst_base.SockType.LISTEN
cmd += f"{socket._path} "
......@@ -110,10 +110,9 @@ class I40eNicSim(NICSim):
json_obj = super().toJSON()
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO: FIXME
pass
@classmethod
def fromJSON(cls, simulation: sim_base.Simulation, json_obj: dict) -> I40eNicSim:
return super().fromJSON(simulation, json_obj)
def run_cmd(self, inst: inst_base.Instantiation) -> str:
return super().run_cmd(inst=inst)
......@@ -131,10 +130,11 @@ class CorundumBMNICSim(NICSim):
json_obj = super().toJSON()
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO: FIXME
pass
@classmethod
def fromJSON(
cls, simulation: sim_base.Simulation, json_obj: dict
) -> CorundumBMNICSim:
return super().fromJSON(simulation, json_obj)
def run_cmd(self, inst: inst_base.Instantiation) -> str:
cmd = super().run_cmd(inst=inst)
......@@ -160,10 +160,11 @@ class CorundumVerilatorNICSim(NICSim):
json_obj["clock_freq"] = self.clock_freq
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO: FIXME
pass
@classmethod
def fromJSON(
cls, simulation: sim_base.Simulation, json_obj: dict
) -> CorundumVerilatorNICSim:
return super().fromJSON(simulation, json_obj)
def run_cmd(self, inst: inst_base.Instantiation) -> str:
cmd = super().run_cmd(inst=inst)
......
......@@ -45,7 +45,9 @@ class System(util_base.IdObj):
self._all_components[c.id()] = c
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]
def _add_interface(self, i: Interface) -> None:
......@@ -54,7 +56,9 @@ class System(util_base.IdObj):
self._all_interfaces[i.id()] = i
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]
def _add_channel(self, c: Channel) -> None:
......@@ -63,7 +67,9 @@ class System(util_base.IdObj):
self._all_channels[c.id()] = c
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]
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