diff options
| author | Loic Guegan <manzerbredes@mailbox.org> | 2022-09-12 13:56:06 +0200 |
|---|---|---|
| committer | Loic Guegan <manzerbredes@mailbox.org> | 2022-09-12 13:56:06 +0200 |
| commit | a2c5db3882a53b897ef8ff3c0186739f2851f28a (patch) | |
| tree | e16f9d07cb0c01cb436e22d2fe66f869d95bfe8b /esds/platform.py | |
| parent | 47c71c85c9d018fc42a7182fc7f6265e3a4e5388 (diff) | |
Debug imports
Diffstat (limited to 'esds/platform.py')
| -rw-r--r-- | esds/platform.py | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/esds/platform.py b/esds/platform.py new file mode 100644 index 0000000..144e552 --- /dev/null +++ b/esds/platform.py @@ -0,0 +1,226 @@ + +import yaml, os, importlib +import numpy as np +import Simulator + +class UnitsParser: + def node_range(r,limit): + if r == "all": + return(range(0,limit)) + r=r.replace("@",str(limit-1)) + elt=r.split("-") + if len(elt) == 2: + min = int(elt[0]) + max = int(elt[1]) + if min < 0 or max >= limit: + raise Exception("Outside of range limit [0-"+str(limit)+"]") + return(range(min,max+1)) + else: + return(list(map(int, r.split(",")))) + + def bandwidth(bw): + for i,c in enumerate(bw): + if not c.isdigit() and c != ".": + break + number=float(bw[:i]) + unit=bw[i:] + number=number*1000 if unit == "Mbps" else number + number=number*1000*8 if unit == "MBps" else number + number=number*100 if unit == "kbps" else number + number=number*100*8 if unit == "kBps" else number + number=number*8 if unit == "Bps" else number + return(number) + + def latency(lat): + for i,c in enumerate(lat): + if not c.isdigit() and c != ".": + break + number=float(lat[:i]) + unit=lat[i:] + number=number*60 if unit in ["m","M"] else number + number=number*3600 if unit in ["h","H"] else number + number=number/1000 if unit in ["ms","MS"] else number + return(number) + +class YAMLPlatformFile: + + def __init__(self, file_path): + self.file_path=file_path + self.default={ + "breakpoints": [], + "breakpoints_every": None, + "breakpoints_file": None, + "breakpoints_callback": lambda s:None, + "debug": False, + "debug_file": "./esds.debug", + "interferences": True, + "node_count": 0, + "implementations": [], + "arguments": [], + "interfaces": dict() + } + + with open(file_path) as f: + self.platform = yaml.load(f, Loader=yaml.FullLoader) + + ##### General + if "general" in self.platform: + self.parse_general() + ##### Nodes + if "nodes" in self.platform: + self.parse_nodes() + else: + self.parsing_error("platform file has no nodes section") + ##### Interfaces + if "interfaces" in self.platform: + self.parse_interfaces() + else: + self.parsing_error("platform file has no interfaces section") + + ##### Sanity checks + if None in self.default["implementations"]: + self.parsing_error("Some nodes do not have assigned implementation") + + def parsing_error(self,msg): + raise Exception("Fail to parse platform file \""+self.file_path+"\": "+msg) + + def parse_link(self,link): + words=link.split() + if len(words) == 4: + return(( + UnitsParser.node_range(words[0],self.default["node_count"]), + UnitsParser.bandwidth(words[1]), + UnitsParser.latency(words[2]), + UnitsParser.node_range(words[3],self.default["node_count"]))) + self.parsing_error("Invalide link \""+link+"\"") + + def parse_txperf(self,txperf): + elts=txperf.split() + return((UnitsParser.node_range(elts[0],self.default["node_count"]),UnitsParser.bandwidth(elts[1]),UnitsParser.latency(elts[2]))) + + def parse_interfaces(self): + interfaces=self.platform["interfaces"] + node_count=self.default["node_count"] + for i in interfaces: + if interfaces[i]["type"] not in ["wireless","wired"]: + self.parsing_error("Invalid interface type \""+interfaces[i]["type"]+"\"") + is_wired=interfaces[i]["type"] == "wired" + links=list() + if type(interfaces[i]["links"]) != list: + self.parsing_error("Invalide type of links in interface "+i) + for link in interfaces[i]["links"]: + links.append(self.parse_link(link)) + ##### Create network matrix + BW=np.full((node_count,node_count),0) + LAT=np.full((node_count,node_count),0) + for link in links: + for n1 in link[0]: + for n2 in link[3]: + BW[n1][n2]=link[1] + LAT[n1][n2]=link[2] + + ##### Set txperfs for wireless interfaces + if not is_wired: + txperfs=interfaces[i]["txperfs"] + for txperf in txperfs: + p=self.parse_txperf(txperf) + for node in p[0]: + BW[node][node]=p[1] + LAT[node][node]=p[2] + if (BW.diagonal()==0).any(): + self.parsing_error("Not all node have a txpref on the wireless interface "+i) + + self.default["interfaces"][i]={ + "is_wired": is_wired, + "bandwidth": BW, + "latency": LAT + } + + def parse_nodes(self): + nodes=self.platform["nodes"] + if "count" in nodes: + if not str(nodes["count"]).isnumeric(): + self.parsing_error("node count should be a number") + self.default["node_count"]=nodes["count"] + else: + self.parsing_error("node count not provided") + if "implementations" in nodes: + if type(nodes["implementations"]) != list: + self.parsing_error("nodes implementations should be a list of file path") + self.default["implementations"]=[None]*self.default["node_count"] + for impl in nodes["implementations"]: + words=impl.split() + r=UnitsParser.node_range(words[0],self.default["node_count"]) + file="".join(words[1:]) + if not os.path.exists(file): + self.parsing_error("File "+file+ " not found") + path, extension = os.path.splitext(file) + if extension != ".py": + self.parsing_error("File "+file+" must be a python file") + for node in r: + self.default["implementations"][node]=path + count = len(nodes["implementations"]) + if count > 1 and count != self.default["node_count"]: + self.parsing_error("If more than one implementation is specified, each node implementation should be provided ("+str(self.default["node_count"])+" in total)") + else: + self.parsing_error("node implementation not provided") + ##### Nodes arguments + self.default["arguments"]=[None]*self.default["node_count"] + if "arguments" in nodes: + args=nodes["arguments"] + for r in args: + for node_id in UnitsParser.node_range(r,self.default["node_count"]): + self.default["arguments"][node_id]=args[r] + + def parse_general(self): + general=self.platform["general"] + if "breakpoints" in general: + if type(general["breakpoints"]) != list: + self.parsing_error("breakpoints should be a list of number") + self.default["breakpoints"]=general["breakpoints"] + if "breakpoints_every" in general: + if not str(general["breakpoints_every"]).isnumeric(): + self.parsing_error("breakpoints_every should be a number") + self.default["breakpoints_every"]=general["breakpoints_every"] + if "breakpoints_callback" in general: + cb=general["breakpoints_callback"] + file=cb["file"] + path, ext=os.path.splitext(file) + if not os.path.exists(file): + self.parsing_error("File "+file+ " not found") + path, extension = os.path.splitext(file) + if extension != ".py": + self.parsing_error("File "+file+" must be a python file") + self.default["breakpoints_file"]=cb["file"] + self.default["breakpoints_callback"]=cb["callback"] + if "debug" in general: + if type(general["debug"]) != bool: + self.parsing_error("debug should be on or off") + self.default["debug"]=general["debug"] + if "debug_file" in general: + self.default["debug_file"]=general["debug_file"] + if "interferences" in general: + if type(general["interferences"]) != bool: + self.parsing_error("interferences should be on or off") + self.default["interferences"]=general["interferences"] + + def run(self): + ##### First load callback from file if any + if self.default["breakpoints_file"] != None: + module, ext=os.path.splitext(self.default["breakpoints_file"]) + imported=importlib.import_module(module) + callback=getattr(imported, self.default["breakpoints_callback"]) + self.default["breakpoints_callback"]=callback + ##### Create simulator + simulator=Simulator(self.default["interfaces"]) + for node_id in range(0,self.default["node_count"]): + simulator.create_node(self.default["implementations"][node_id], args=self.default["arguments"][node_id]) + ##### Run simulation + simulator.run( + breakpoints=self.default["breakpoints"], + breakpoints_every=self.default["breakpoints_every"], + breakpoint_callback=self.default["breakpoints_callback"], + debug=self.default["debug"], + debug_file_path=self.default["debug_file"], + interferences=self.default["interferences"]) +
\ No newline at end of file |
