From f62870449b04da8a2c1462e756b78bf0edab2abf Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Tue, 18 May 2021 11:41:40 +0300 Subject: [PATCH 01/47] added .gitignore --- .gitignore | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5391d87 --- /dev/null +++ b/.gitignore @@ -0,0 +1,138 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ \ No newline at end of file -- GitLab From 126592324e1706fade2d11f49c1736156c7a871d Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Thu, 20 May 2021 22:31:00 +0300 Subject: [PATCH 02/47] added graph genertion scripts --- graph.py | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 graph.py diff --git a/graph.py b/graph.py new file mode 100644 index 0000000..bc7badb --- /dev/null +++ b/graph.py @@ -0,0 +1,71 @@ +import random +import networkx as nx +import matplotlib.pyplot as plt + +class ERG: + def __init__(self, node_count: int, connectivity: float, ax = None) -> None: + self.ax = ax + self.node_count = node_count + self.root = random.choice(list(range(self.node_count))) + self.G = nx.nx.erdos_renyi_graph(self.node_count, connectivity, seed=random.randint(100, 10000), directed=False) + + def plot(self): + node_colors = ["red" if i == self.root else "mediumslateblue" for i in range(self.node_count)] + + if self.ax is not None: + nx.draw(self.G, with_labels=True, node_color=node_colors, ax=self.ax) + else: + nx.draw(self.G, with_labels=True, node_color=node_colors) + +class Grid: + def __init__(self, node_count_on_edge: int, ax = None) -> None: + self.ax = ax + self.node_count_on_edge = node_count_on_edge + self.root = random.choice(list(range(self.node_count_on_edge ** 2))) + self.G = nx.grid_2d_graph(self.node_count_on_edge, self.node_count_on_edge) + self.positions = {self.node_count_on_edge * x[0] + x[1]: x for x in self.G.nodes()} + + self.G = nx.relabel_nodes(self.G, lambda x: self.node_count_on_edge * x[0] + x[1]) + + def plot(self): + node_colors = ["red" if i == self.root else "mediumslateblue" for i in range(self.node_count_on_edge ** 2)] + + if self.ax is not None: + nx.draw(self.G, with_labels=True, node_color=node_colors, pos=self.positions, ax=self.ax) + else: + nx.draw(self.G, with_labels=True, node_color=node_colors, pos=self.positions) + +class Star: + def __init__(self, slave_count: int, master_is_root: bool = True, ax = None) -> None: + self.ax = ax + self.slave_count = slave_count + self.root = 0 if master_is_root else random.choice(list(range(1, slave_count + 1))) + + self.G = nx.Graph() + + self.G.add_node(0) + + for i in range(1, self.slave_count + 1): + self.G.add_node(i) + self.G.add_edge(0, i) + + def plot(self): + node_colors = ["red" if i == self.root else "mediumslateblue" for i in range(self.slave_count + 1)] + + if self.ax is not None: + nx.draw(self.G, with_labels=True, node_color=node_colors, ax=self.ax) + else: + nx.draw(self.G, with_labels=True, node_color=node_colors) + +if __name__ == "__main__": + fig, axes = plt.subplots(1, 4) + fig.set_figheight(5) + fig.set_figwidth(25) + fig.tight_layout() + + ERG(10, 0.45, ax=axes[0]).plot() + Grid(4, ax=axes[1]).plot() + Star(6, master_is_root=True, ax=axes[2]).plot() + Star(6, master_is_root=False, ax=axes[3]).plot() + + plt.show() \ No newline at end of file -- GitLab From 1d59bfc5bd65993db3778555a9b41551bf8446ce Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Fri, 21 May 2021 00:29:07 +0300 Subject: [PATCH 03/47] context support --- Ahc.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Ahc.py b/Ahc.py index b2d5487..95aae4a 100644 --- a/Ahc.py +++ b/Ahc.py @@ -171,7 +171,8 @@ class ComponentModel: def on_message_from_peer(self, eventobj: Event): print(f"{EventTypes.MFRP} {self.componentname}.{self.componentinstancenumber}") - def __init__(self, componentname, componentinstancenumber, num_worker_threads=1): + def __init__(self, componentname, componentinstancenumber, context=None, num_worker_threads=1): + self.context = context self.eventhandlers = {EventTypes.INIT: self.on_init, EventTypes.MFRB: self.on_message_from_bottom, EventTypes.MFRT: self.on_message_from_top, EventTypes.MFRP: self.on_message_from_peer} # Add default handlers to all instantiated components. @@ -255,12 +256,12 @@ class Topology: nodes = {} channels = {} - def construct_from_graph(self, G: nx.Graph, nodetype, channeltype): + def construct_from_graph(self, G: nx.Graph, nodetype, channeltype, context): self.G = G nodes = list(G.nodes) edges = list(G.edges) for i in nodes: - cc = nodetype(nodetype.__name__, i) + cc = nodetype(nodetype.__name__, i, context) self.nodes[i] = cc for k in edges: ch = channeltype(channeltype.__name__, str(k[0]) + "-" + str(k[1])) -- GitLab From 4e9b60b72ad1cf7711402961a862e6d9930d4501 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Fri, 21 May 2021 00:29:19 +0300 Subject: [PATCH 04/47] simulation base --- algorithms.py | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++ simulator.py | 76 +++++++++++++++++++++++++++++++ 2 files changed, 200 insertions(+) create mode 100644 algorithms.py create mode 100644 simulator.py diff --git a/algorithms.py b/algorithms.py new file mode 100644 index 0000000..b7fd95b --- /dev/null +++ b/algorithms.py @@ -0,0 +1,124 @@ +import os +import sys +import time +import json +import random +import networkx as nx +from enum import Enum +import matplotlib.pyplot as plt + +from Channels import P2PFIFOPerfectChannel +from LinkLayers.GenericLinkLayer import LinkLayer +from NetworkLayers.AllSeeingEyeNetworkLayer import AllSeingEyeNetworkLayer +from Ahc import (ComponentModel, Event, ConnectorTypes, Topology, + ComponentRegistry, GenericMessagePayload, GenericMessageHeader, + GenericMessage, EventTypes) + +registry = ComponentRegistry() + +# define your own message types +class ApplicationLayerMessageTypes(Enum): + PROPOSE = "PROPOSE" + ACCEPT = "ACCEPT" + +# define your own message header structure +class ApplicationLayerMessageHeader(GenericMessageHeader): + pass + +# define your own message payload structure +class ApplicationLayerMessagePayload(GenericMessagePayload): + pass + +class ApplicationLayerComponent(ComponentModel): + def on_init(self, eventobj: Event): + print(f"Initializing {self.componentname}.{self.componentinstancenumber}") + print(self.context) + + + if self.componentinstancenumber == 0: + print("HEEYOOOOO!!!", flush=True) + # destination = random.randint(len(Topology.G.nodes)) + destination = 1 + hdr = ApplicationLayerMessageHeader(ApplicationLayerMessageTypes.PROPOSE, self.componentinstancenumber, + destination) + payload = ApplicationLayerMessagePayload("23") + proposalmessage = GenericMessage(hdr, payload) + randdelay = random.randint(0, 5) + #time.sleep(randdelay) + self.send_self(Event(self, "propose", proposalmessage)) + elif self.componentinstancenumber == 1: + #time.sleep(1) + pass + else: + pass + + def on_message_from_bottom(self, eventobj: Event): + try: + applmessage = eventobj.eventcontent + hdr = applmessage.header + if hdr.messagetype == ApplicationLayerMessageTypes.ACCEPT: + print(f"Node-{self.componentinstancenumber} says Node-{hdr.messagefrom} has sent {hdr.messagetype} message") + elif hdr.messagetype == ApplicationLayerMessageTypes.PROPOSE: + print(f"Node-{self.componentinstancenumber} says Node-{hdr.messagefrom} has sent {hdr.messagetype} message") + except AttributeError: + print("Attribute Error") + + # print(f"{self.componentname}.{self.componentinstancenumber}: Gotton message {eventobj.content} ") + # value = eventobj.content.value + # value += 1 + # newmsg = MessageContent( value ) + # myevent = Event( self, "agree", newmsg ) + # self.trigger_event(myevent) + + def on_propose(self, eventobj: Event): + destination = 1 + hdr = ApplicationLayerMessageHeader(ApplicationLayerMessageTypes.ACCEPT, self.componentinstancenumber, destination) + payload = ApplicationLayerMessagePayload("23") + proposalmessage = GenericMessage(hdr, payload) + self.send_down(Event(self, EventTypes.MFRT, proposalmessage)) + + def on_agree(self, eventobj: Event): + print(f"Agreed on {eventobj.eventcontent}") + + def on_timer_expired(self, eventobj: Event): + pass + + def __init__(self, componentname, componentinstancenumber, context): + self.context = context + super().__init__(componentname, componentinstancenumber, context=context) + self.eventhandlers["propose"] = self.on_propose + self.eventhandlers["agree"] = self.on_agree + self.eventhandlers["timerexpired"] = self.on_timer_expired + +class AdHocNode(ComponentModel): + + def on_init(self, eventobj: Event): + print(f"Initializing {self.componentname}.{self.componentinstancenumber}") + + def on_message_from_top(self, eventobj: Event): + self.send_down(Event(self, EventTypes.MFRT, eventobj.eventcontent)) + + def on_message_from_bottom(self, eventobj: Event): + self.send_up(Event(self, EventTypes.MFRB, eventobj.eventcontent)) + + def __init__(self, componentname, componentid, context): + self.context = context + # SUBCOMPONENTS + self.appllayer = ApplicationLayerComponent("ApplicationLayer", componentid, context=self.context) + self.netlayer = AllSeingEyeNetworkLayer("NetworkLayer", componentid) + self.linklayer = LinkLayer("LinkLayer", componentid) + # self.failuredetect = GenericFailureDetector("FailureDetector", componentid) + + # CONNECTIONS AMONG SUBCOMPONENTS + self.appllayer.connect_me_to_component(ConnectorTypes.DOWN, self.netlayer) + # self.failuredetect.connectMeToComponent(PortNames.DOWN, self.netlayer) + self.netlayer.connect_me_to_component(ConnectorTypes.UP, self.appllayer) + # self.netlayer.connectMeToComponent(PortNames.UP, self.failuredetect) + self.netlayer.connect_me_to_component(ConnectorTypes.DOWN, self.linklayer) + self.linklayer.connect_me_to_component(ConnectorTypes.UP, self.netlayer) + + # Connect the bottom component to the composite component.... + self.linklayer.connect_me_to_component(ConnectorTypes.DOWN, self) + self.connect_me_to_component(ConnectorTypes.UP, self.linklayer) + + super().__init__(componentname, componentid, context=self.context) \ No newline at end of file diff --git a/simulator.py b/simulator.py new file mode 100644 index 0000000..d592194 --- /dev/null +++ b/simulator.py @@ -0,0 +1,76 @@ +import os +import sys +import time +import random +import networkx as nx +from enum import Enum +import matplotlib.pyplot as plt +from argparse import ArgumentParser + +from graph import ERG, Grid, Star +from algorithms import AdHocNode +from Channels import P2PFIFOPerfectChannel +from LinkLayers.GenericLinkLayer import LinkLayer +from NetworkLayers.AllSeeingEyeNetworkLayer import AllSeingEyeNetworkLayer +from Ahc import (ComponentModel, Event, ConnectorTypes, Topology, + ComponentRegistry, GenericMessagePayload, GenericMessageHeader, + GenericMessage, EventTypes) + +parser = ArgumentParser() +parser.add_argument("simulation_ticks", type=int) +parser.add_argument("ms_per_tick", type=int) +parser.add_argument("--node_min_activeness_after_receive", type=int, default=3) +parser.add_argument("--node_max_activeness_after_receive", type=int, default=10) +parser.add_argument("--node_activeness_communication_prob", type=float, default=0.5) +parser.add_argument("--node_initial_activeness_prob", type=float, default=0.8) + +sp = parser.add_subparsers() + +erg_parser = sp.add_parser("erg") +erg_parser.add_argument("node_count", type=int) +erg_parser.add_argument("--node_connectivity", type=float, default=0.5) +erg_parser.set_defaults(network_type="erg") + +grid_parser = sp.add_parser("grid") +grid_parser.add_argument("node_count_on_edge", type=int) +grid_parser.set_defaults(network_type="grid") + +star_parser = sp.add_parser("star") +star_parser.add_argument("slave_count", type=int) +star_parser.add_argument("--master_is_root", type=bool, default=True) +star_parser.set_defaults(network_type="star") + +if __name__ == "__main__": + args = parser.parse_args() + print(f"[+] Network type: {args.network_type}") + + if args.network_type == "erg": + N = ERG(args.node_count, args.node_connectivity) + total_nodes = args.node_count + elif args.network_type == "grid": + N = Grid(args.node_count_on_edge) + total_nodes = args.node_count_on_edge ** 2 + elif args.network_type == "star": + N = Star(args.slave_count, master_is_root=args.master_is_root) + total_nodes = args.slave_count + 1 + + node_active_ticks_initial = [random.randint(args.node_min_activeness_after_receive, args.node_max_activeness_after_receive) if random.random() <= args.node_initial_activeness_prob else 0 for _ in range(total_nodes)] + + # N.plot() + # plt.show() + + topo = Topology() + topo.construct_from_graph(N.G, AdHocNode, P2PFIFOPerfectChannel, context={ + "network": N, + "ms_per_tick": args.ms_per_tick, + "simulation_ticks": args.simulation_ticks, + "initial_liveness": node_active_ticks_initial, + "communication_on_active_prob": args.node_activeness_communication_prob, + "min_activeness_after_receive": args.node_min_activeness_after_receive, + "max_activeness_after_receive": args.node_max_activeness_after_receive, + }) + + topo.start() + + topo.plot() + plt.show() \ No newline at end of file -- GitLab From 8bfae72a4fe310a8f7b8deec47fca710e70cca77 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Fri, 21 May 2021 22:03:02 +0300 Subject: [PATCH 05/47] indentation && dummy code elimination --- algorithms.py | 156 ++++++++++++++++++++++---------------------------- 1 file changed, 68 insertions(+), 88 deletions(-) diff --git a/algorithms.py b/algorithms.py index b7fd95b..c0ccd26 100644 --- a/algorithms.py +++ b/algorithms.py @@ -1,7 +1,9 @@ import os +import queue import sys import time import json +import queue import random import networkx as nx from enum import Enum @@ -17,108 +19,86 @@ from Ahc import (ComponentModel, Event, ConnectorTypes, Topology, registry = ComponentRegistry() # define your own message types -class ApplicationLayerMessageTypes(Enum): - PROPOSE = "PROPOSE" - ACCEPT = "ACCEPT" +class ApplicationLayerMessageType(Enum): + BASIC = "basic" + CONTROL = "control" # define your own message header structure class ApplicationLayerMessageHeader(GenericMessageHeader): - pass + pass # define your own message payload structure class ApplicationLayerMessagePayload(GenericMessagePayload): - pass + pass class ApplicationLayerComponent(ComponentModel): - def on_init(self, eventobj: Event): - print(f"Initializing {self.componentname}.{self.componentinstancenumber}") - print(self.context) - - - if self.componentinstancenumber == 0: - print("HEEYOOOOO!!!", flush=True) - # destination = random.randint(len(Topology.G.nodes)) - destination = 1 - hdr = ApplicationLayerMessageHeader(ApplicationLayerMessageTypes.PROPOSE, self.componentinstancenumber, - destination) - payload = ApplicationLayerMessagePayload("23") - proposalmessage = GenericMessage(hdr, payload) - randdelay = random.randint(0, 5) - #time.sleep(randdelay) - self.send_self(Event(self, "propose", proposalmessage)) - elif self.componentinstancenumber == 1: - #time.sleep(1) - pass - else: - pass - - def on_message_from_bottom(self, eventobj: Event): - try: - applmessage = eventobj.eventcontent - hdr = applmessage.header - if hdr.messagetype == ApplicationLayerMessageTypes.ACCEPT: - print(f"Node-{self.componentinstancenumber} says Node-{hdr.messagefrom} has sent {hdr.messagetype} message") - elif hdr.messagetype == ApplicationLayerMessageTypes.PROPOSE: - print(f"Node-{self.componentinstancenumber} says Node-{hdr.messagefrom} has sent {hdr.messagetype} message") - except AttributeError: - print("Attribute Error") - - # print(f"{self.componentname}.{self.componentinstancenumber}: Gotton message {eventobj.content} ") - # value = eventobj.content.value - # value += 1 - # newmsg = MessageContent( value ) - # myevent = Event( self, "agree", newmsg ) - # self.trigger_event(myevent) - - def on_propose(self, eventobj: Event): - destination = 1 - hdr = ApplicationLayerMessageHeader(ApplicationLayerMessageTypes.ACCEPT, self.componentinstancenumber, destination) - payload = ApplicationLayerMessagePayload("23") - proposalmessage = GenericMessage(hdr, payload) - self.send_down(Event(self, EventTypes.MFRT, proposalmessage)) - - def on_agree(self, eventobj: Event): - print(f"Agreed on {eventobj.eventcontent}") - - def on_timer_expired(self, eventobj: Event): - pass + def __init__(self, componentname, componentinstancenumber, context): + super().__init__(componentname, componentinstancenumber, context=context) - def __init__(self, componentname, componentinstancenumber, context): - self.context = context - super().__init__(componentname, componentinstancenumber, context=context) - self.eventhandlers["propose"] = self.on_propose - self.eventhandlers["agree"] = self.on_agree - self.eventhandlers["timerexpired"] = self.on_timer_expired + self.context = context + # self.eventhandlers[ApplicationLayerMessageType.BASIC] = self.on_basic_message + # self.eventhandlers[ApplicationLayerMessageType.CONTROL] = self.on_control_message -class AdHocNode(ComponentModel): + self.basic_message_queue = queue.Queue(maxsize=-1) + self.control_message_queue = queue.Queue(maxsize=-1) - def on_init(self, eventobj: Event): - print(f"Initializing {self.componentname}.{self.componentinstancenumber}") + def prepare_application_layer_message(self, message_type: ApplicationLayerMessageType, destination_node_id: int, payload: object) -> GenericMessage: + hdr = ApplicationLayerMessageHeader(message_type, self.componentinstancenumber, destination_node_id) + payload = ApplicationLayerMessagePayload(payload) + + return GenericMessage(hdr, payload) - def on_message_from_top(self, eventobj: Event): - self.send_down(Event(self, EventTypes.MFRT, eventobj.eventcontent)) + # def on_basic_message(self, *args, **kwargs): + # print(f"Node-{self.componentinstancenumber}: on_basic_message: {args}, {kwargs}") - def on_message_from_bottom(self, eventobj: Event): - self.send_up(Event(self, EventTypes.MFRB, eventobj.eventcontent)) + # def on_control_message(self, *args, **kwargs): + # print(f"Node-{self.componentinstancenumber}: on_control_message: {args}, {kwargs}") - def __init__(self, componentname, componentid, context): - self.context = context - # SUBCOMPONENTS - self.appllayer = ApplicationLayerComponent("ApplicationLayer", componentid, context=self.context) - self.netlayer = AllSeingEyeNetworkLayer("NetworkLayer", componentid) - self.linklayer = LinkLayer("LinkLayer", componentid) - # self.failuredetect = GenericFailureDetector("FailureDetector", componentid) + def on_init(self, eventobj: Event): + print(f"Initializing {self.componentname}.{self.componentinstancenumber}") - # CONNECTIONS AMONG SUBCOMPONENTS - self.appllayer.connect_me_to_component(ConnectorTypes.DOWN, self.netlayer) - # self.failuredetect.connectMeToComponent(PortNames.DOWN, self.netlayer) - self.netlayer.connect_me_to_component(ConnectorTypes.UP, self.appllayer) - # self.netlayer.connectMeToComponent(PortNames.UP, self.failuredetect) - self.netlayer.connect_me_to_component(ConnectorTypes.DOWN, self.linklayer) - self.linklayer.connect_me_to_component(ConnectorTypes.UP, self.netlayer) + if self.componentinstancenumber == 0: + self.send_down(Event(self, EventTypes.MFRT, self.prepare_application_layer_message(ApplicationLayerMessageType.BASIC, 3, "hey!"))) - # Connect the bottom component to the composite component.... - self.linklayer.connect_me_to_component(ConnectorTypes.DOWN, self) - self.connect_me_to_component(ConnectorTypes.UP, self.linklayer) + def on_message_from_bottom(self, eventobj: Event): + applmessage = eventobj.eventcontent + hdr = applmessage.header - super().__init__(componentname, componentid, context=self.context) \ No newline at end of file + print(f"Node-{self.componentinstancenumber}: Node-{hdr.messagefrom} has sent {hdr.messagetype} message (payload: {applmessage.payload})") + + if hdr.messagetype == ApplicationLayerMessageType.BASIC: + self.basic_message_queue.put_nowait(applmessage) + elif hdr.messagetype == ApplicationLayerMessageType.CONTROL: + self.control_message_queue.put_nowait(applmessage) + +class AdHocNode(ComponentModel): + def __init__(self, componentname, componentid, context): + self.context = context + # SUBCOMPONENTS + self.appllayer = ApplicationLayerComponent("ApplicationLayer", componentid, context=self.context) + self.netlayer = AllSeingEyeNetworkLayer("NetworkLayer", componentid) + self.linklayer = LinkLayer("LinkLayer", componentid) + # self.failuredetect = GenericFailureDetector("FailureDetector", componentid) + + # CONNECTIONS AMONG SUBCOMPONENTS + self.appllayer.connect_me_to_component(ConnectorTypes.DOWN, self.netlayer) + # self.failuredetect.connectMeToComponent(PortNames.DOWN, self.netlayer) + self.netlayer.connect_me_to_component(ConnectorTypes.UP, self.appllayer) + # self.netlayer.connectMeToComponent(PortNames.UP, self.failuredetect) + self.netlayer.connect_me_to_component(ConnectorTypes.DOWN, self.linklayer) + self.linklayer.connect_me_to_component(ConnectorTypes.UP, self.netlayer) + + # Connect the bottom component to the composite component.... + self.linklayer.connect_me_to_component(ConnectorTypes.DOWN, self) + self.connect_me_to_component(ConnectorTypes.UP, self.linklayer) + + super().__init__(componentname, componentid, context=self.context) + + def on_init(self, eventobj: Event): + print(f"Initializing {self.componentname}.{self.componentinstancenumber}") + + def on_message_from_top(self, eventobj: Event): + self.send_down(Event(self, EventTypes.MFRT, eventobj.eventcontent)) + + def on_message_from_bottom(self, eventobj: Event): + self.send_up(Event(self, EventTypes.MFRB, eventobj.eventcontent)) \ No newline at end of file -- GitLab From 9f48f41cec8463bc8a33dd8d91efc64e0a22c09b Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Fri, 21 May 2021 22:06:42 +0300 Subject: [PATCH 06/47] updated simulator.py --- simulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simulator.py b/simulator.py index d592194..4b9dfa0 100644 --- a/simulator.py +++ b/simulator.py @@ -72,5 +72,5 @@ if __name__ == "__main__": topo.start() - topo.plot() + N.plot() plt.show() \ No newline at end of file -- GitLab From 9e41e7128ef1e96630113de6192daea997cddd6b Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Fri, 21 May 2021 22:06:53 +0300 Subject: [PATCH 07/47] send_random_basic_message impl --- algorithms.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/algorithms.py b/algorithms.py index c0ccd26..5c26e13 100644 --- a/algorithms.py +++ b/algorithms.py @@ -8,6 +8,7 @@ import random import networkx as nx from enum import Enum import matplotlib.pyplot as plt +from datetime import datetime as dt from Channels import P2PFIFOPerfectChannel from LinkLayers.GenericLinkLayer import LinkLayer @@ -48,17 +49,14 @@ class ApplicationLayerComponent(ComponentModel): return GenericMessage(hdr, payload) - # def on_basic_message(self, *args, **kwargs): - # print(f"Node-{self.componentinstancenumber}: on_basic_message: {args}, {kwargs}") - - # def on_control_message(self, *args, **kwargs): - # print(f"Node-{self.componentinstancenumber}: on_control_message: {args}, {kwargs}") + def send_random_basic_message(self, to: int) -> None: + self.send_down(Event(self, EventTypes.MFRT, self.prepare_application_layer_message(ApplicationLayerMessageType.BASIC, to, str(dt.now().timestamp())))) def on_init(self, eventobj: Event): print(f"Initializing {self.componentname}.{self.componentinstancenumber}") if self.componentinstancenumber == 0: - self.send_down(Event(self, EventTypes.MFRT, self.prepare_application_layer_message(ApplicationLayerMessageType.BASIC, 3, "hey!"))) + self.send_random_basic_message(3) def on_message_from_bottom(self, eventobj: Event): applmessage = eventobj.eventcontent -- GitLab From 7839d6e8ca76c4e4257cd88f45083f6bdbd13a04 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Fri, 21 May 2021 22:14:01 +0300 Subject: [PATCH 08/47] updated simulator.py --- simulator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/simulator.py b/simulator.py index 4b9dfa0..edceced 100644 --- a/simulator.py +++ b/simulator.py @@ -19,9 +19,9 @@ from Ahc import (ComponentModel, Event, ConnectorTypes, Topology, parser = ArgumentParser() parser.add_argument("simulation_ticks", type=int) parser.add_argument("ms_per_tick", type=int) -parser.add_argument("--node_min_activeness_after_receive", type=int, default=3) -parser.add_argument("--node_max_activeness_after_receive", type=int, default=10) -parser.add_argument("--node_activeness_communication_prob", type=float, default=0.5) +parser.add_argument("--node_min_activeness_after_receive", type=int, default=3) # paket aldiktan sonra min bu kadar aktif kal +parser.add_argument("--node_max_activeness_after_receive", type=int, default=10) # paket aldiktan sonra max bu kadar aktif kal +parser.add_argument("--node_activeness_communication_prob", type=float, default=0.5) # alive iken baska nodelara paket gonderme olasiligi parser.add_argument("--node_initial_activeness_prob", type=float, default=0.8) sp = parser.add_subparsers() -- GitLab From 3c8e39ee1a3a22f9ed03253ba476fc9e3542cd60 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sat, 22 May 2021 00:06:06 +0300 Subject: [PATCH 09/47] updated AllSeeingEyeNetworkLayer.py --- NetworkLayers/AllSeeingEyeNetworkLayer.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/NetworkLayers/AllSeeingEyeNetworkLayer.py b/NetworkLayers/AllSeeingEyeNetworkLayer.py index c18259c..dcd4bed 100644 --- a/NetworkLayers/AllSeeingEyeNetworkLayer.py +++ b/NetworkLayers/AllSeeingEyeNetworkLayer.py @@ -23,14 +23,15 @@ class AllSeingEyeNetworkLayer(ComponentModel): destination = applmsg.header.messageto nexthop = Topology().get_next_hop(self.componentinstancenumber, destination) if nexthop != float('inf'): - print(f"{self.componentinstancenumber} will SEND a message to {destination} over {nexthop}") + # print(f"{self.componentinstancenumber} will SEND a message to {destination} over {nexthop}") hdr = NetworkLayerMessageHeader(NetworkLayerMessageTypes.NETMSG, self.componentinstancenumber, destination, nexthop) payload = eventobj.eventcontent msg = GenericMessage(hdr, payload) self.send_down(Event(self, EventTypes.MFRT, msg)) else: - print(f"NO PATH: {self.componentinstancenumber} will NOTSEND a message to {destination} over {nexthop}") + pass + # print(f"NO PATH: {self.componentinstancenumber} will NOTSEND a message to {destination} over {nexthop}") def on_message_from_bottom(self, eventobj: Event): msg = eventobj.eventcontent @@ -39,7 +40,7 @@ class AllSeingEyeNetworkLayer(ComponentModel): if hdr.messageto == self.componentinstancenumber or hdr.messageto == MessageDestinationIdentifiers.NETWORKLAYERBROADCAST: # Add if broadcast.... self.send_up(Event(self, EventTypes.MFRB, payload)) - print(f"I received a message to {hdr.messageto} and I am {self.componentinstancenumber}") + # print(f"I received a message to {hdr.messageto} and I am {self.componentinstancenumber}") else: destination = hdr.messageto nexthop = Topology().get_next_hop(self.componentinstancenumber, destination) @@ -49,9 +50,10 @@ class AllSeingEyeNetworkLayer(ComponentModel): newpayload = eventobj.eventcontent.payload msg = GenericMessage(newhdr, newpayload) self.send_down(Event(self, EventTypes.MFRT, msg)) - print(f"{self.componentinstancenumber} will FORWARD a message to {destination} over {nexthop}") + # print(f"{self.componentinstancenumber} will FORWARD a message to {destination} over {nexthop}") else: - print(f"NO PATH {self.componentinstancenumber} will NOT FORWARD a message to {destination} over {nexthop}") + pass + # print(f"NO PATH {self.componentinstancenumber} will NOT FORWARD a message to {destination} over {nexthop}") def __init__(self, componentname, componentinstancenumber): super().__init__(componentname, componentinstancenumber) -- GitLab From fc7906d3661ca6ed175ef4723f5f13fd07b0cc88 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sat, 22 May 2021 00:06:28 +0300 Subject: [PATCH 10/47] base setup complete --- algorithms.py | 124 +++++++++++++++++++++++++++++++++++++++++++++++--- simulator.py | 82 ++++++++++++++++++++++++++++----- 2 files changed, 188 insertions(+), 18 deletions(-) diff --git a/algorithms.py b/algorithms.py index 5c26e13..e6bc590 100644 --- a/algorithms.py +++ b/algorithms.py @@ -24,6 +24,11 @@ class ApplicationLayerMessageType(Enum): BASIC = "basic" CONTROL = "control" +class AHCNodeSimulationStatus(Enum): + ACTIVE = "active" + PASSIVE = "passive" + OUT_OF_CLOCK = "ooc" + # define your own message header structure class ApplicationLayerMessageHeader(GenericMessageHeader): pass @@ -42,6 +47,24 @@ class ApplicationLayerComponent(ComponentModel): self.basic_message_queue = queue.Queue(maxsize=-1) self.control_message_queue = queue.Queue(maxsize=-1) + self.simulation_state = AHCNodeSimulationStatus.PASSIVE + + self.sleep_ms_per_tick = context["ms_per_tick"] + self.simulation_ticks_total = context["simulation_ticks"] + self.alive_for_next_ticks = context["initial_liveness"][componentinstancenumber] + self.communication_on_active_prob = context["communication_on_active_prob"] + self.min_activeness_after_receive = context["min_activeness_after_receive"] + self.max_activeness_after_receive = context["max_activeness_after_receive"] + self.package_process_per_tick = context["node_package_process_per_tick"] + self.die_passiveness_threshold = context["passiveness_death_thresh"] + + self.friend_ids = [i for i in context["network"].G.nodes() if i != componentinstancenumber] + + self.__tick_n = 0 + self._passive_counter = 0 + + if self.alive_for_next_ticks > 0: + self.simulation_state = AHCNodeSimulationStatus.ACTIVE def prepare_application_layer_message(self, message_type: ApplicationLayerMessageType, destination_node_id: int, payload: object) -> GenericMessage: hdr = ApplicationLayerMessageHeader(message_type, self.componentinstancenumber, destination_node_id) @@ -53,22 +76,98 @@ class ApplicationLayerComponent(ComponentModel): self.send_down(Event(self, EventTypes.MFRT, self.prepare_application_layer_message(ApplicationLayerMessageType.BASIC, to, str(dt.now().timestamp())))) def on_init(self, eventobj: Event): - print(f"Initializing {self.componentname}.{self.componentinstancenumber}") - - if self.componentinstancenumber == 0: - self.send_random_basic_message(3) + # print(f"Initializing {self.componentname}.{self.componentinstancenumber}") + pass def on_message_from_bottom(self, eventobj: Event): applmessage = eventobj.eventcontent hdr = applmessage.header - print(f"Node-{self.componentinstancenumber}: Node-{hdr.messagefrom} has sent {hdr.messagetype} message (payload: {applmessage.payload})") + # print(f"Node-{self.componentinstancenumber}: Node-{hdr.messagefrom} has sent {hdr.messagetype} message (payload: {applmessage.payload})") if hdr.messagetype == ApplicationLayerMessageType.BASIC: self.basic_message_queue.put_nowait(applmessage) elif hdr.messagetype == ApplicationLayerMessageType.CONTROL: self.control_message_queue.put_nowait(applmessage) + def simulation_tick(self): + next_state = None + got_packages_from = None + to_friend = None + + if self.__tick_n >= self.simulation_ticks_total: + next_state = AHCNodeSimulationStatus.OUT_OF_CLOCK + elif self._passive_counter >= self.die_passiveness_threshold: + next_state = AHCNodeSimulationStatus.OUT_OF_CLOCK + else: + if self.simulation_state == AHCNodeSimulationStatus.OUT_OF_CLOCK: + next_state = AHCNodeSimulationStatus.OUT_OF_CLOCK + elif self.simulation_state == AHCNodeSimulationStatus.PASSIVE: + if self.basic_message_queue.empty(): + # no incoming package, still passive. + next_state = AHCNodeSimulationStatus.PASSIVE + else: + got_packages_from = [] + + for _ in range(self.package_process_per_tick): + try: + package = self.basic_message_queue.get_nowait() + # print(f"+P+ N-{self.componentinstancenumber} <==BASIC== N-{package.header.messagefrom} ({package.payload.messagepayload})") + got_packages_from.append(package.header.messagefrom) + except queue.Empty: + break + + self.alive_for_next_ticks = random.randint(self.min_activeness_after_receive, self.max_activeness_after_receive) + next_state = AHCNodeSimulationStatus.ACTIVE + elif self.simulation_state == AHCNodeSimulationStatus.ACTIVE: + got_packages_from = [] + + for _ in range(self.package_process_per_tick): + try: + package = self.basic_message_queue.get_nowait() + # print(f"+A+ N-{self.componentinstancenumber} <==BASIC== N-{package.header.messagefrom} ({package.payload.messagepayload})") + got_packages_from.append(package.header.messagefrom) + except queue.Empty: + break + + if random.random() <= self.communication_on_active_prob: + # send package to a random friend.. + to_friend = random.choice(self.friend_ids) + self.send_random_basic_message(to_friend) + + self.alive_for_next_ticks -= 1 + + if self.alive_for_next_ticks == 0: + if len(got_packages_from) > 0: + # got a package, this means immeiate activeness from passive! + next_state = AHCNodeSimulationStatus.ACTIVE + self.alive_for_next_ticks = random.randint(self.min_activeness_after_receive, self.max_activeness_after_receive) + else: + next_state = AHCNodeSimulationStatus.PASSIVE + else: + next_state = AHCNodeSimulationStatus.ACTIVE + + assert next_state is not None + + # ST: state + # NS: next state + # GPF: got packages from + # SPF: sent package to friend + # ANT: alive next ticks + # P2P: packages to process + # print(f" ==> N-{self.componentinstancenumber}: ST: {self.simulation_state}, NS: {next_state}, GPF: {got_packages_from}, SPF: {to_friend}, ANT: {self.alive_for_next_ticks}, P2P: {self.basic_message_queue.qsize()}") + + time.sleep(self.sleep_ms_per_tick / 1000) + self.__tick_n += 1 + self.simulation_state = next_state + + if self.simulation_state == AHCNodeSimulationStatus.PASSIVE: + self._passive_counter += 1 + elif self.simulation_state == AHCNodeSimulationStatus.ACTIVE: + self._passive_counter = 0 + + return next_state + class AdHocNode(ComponentModel): def __init__(self, componentname, componentid, context): self.context = context @@ -93,10 +192,21 @@ class AdHocNode(ComponentModel): super().__init__(componentname, componentid, context=self.context) def on_init(self, eventobj: Event): - print(f"Initializing {self.componentname}.{self.componentinstancenumber}") + # print(f"Initializing {self.componentname}.{self.componentinstancenumber}") + pass def on_message_from_top(self, eventobj: Event): self.send_down(Event(self, EventTypes.MFRT, eventobj.eventcontent)) def on_message_from_bottom(self, eventobj: Event): - self.send_up(Event(self, EventTypes.MFRB, eventobj.eventcontent)) \ No newline at end of file + self.send_up(Event(self, EventTypes.MFRB, eventobj.eventcontent)) + + def simulation_tick(self): + return self.appllayer.simulation_tick() + + @property + def waiting_packages_on_queue(self): + if self.appllayer.simulation_state == AHCNodeSimulationStatus.OUT_OF_CLOCK: + return 0 + + return self.appllayer.basic_message_queue.qsize() \ No newline at end of file diff --git a/simulator.py b/simulator.py index edceced..106df29 100644 --- a/simulator.py +++ b/simulator.py @@ -1,14 +1,16 @@ import os import sys import time +import pickle import random import networkx as nx from enum import Enum import matplotlib.pyplot as plt +from datetime import datetime as dt from argparse import ArgumentParser from graph import ERG, Grid, Star -from algorithms import AdHocNode +from algorithms import AdHocNode, AHCNodeSimulationStatus from Channels import P2PFIFOPerfectChannel from LinkLayers.GenericLinkLayer import LinkLayer from NetworkLayers.AllSeeingEyeNetworkLayer import AllSeingEyeNetworkLayer @@ -20,9 +22,12 @@ parser = ArgumentParser() parser.add_argument("simulation_ticks", type=int) parser.add_argument("ms_per_tick", type=int) parser.add_argument("--node_min_activeness_after_receive", type=int, default=3) # paket aldiktan sonra min bu kadar aktif kal -parser.add_argument("--node_max_activeness_after_receive", type=int, default=10) # paket aldiktan sonra max bu kadar aktif kal +parser.add_argument("--node_max_activeness_after_receive", type=int, default=5) # paket aldiktan sonra max bu kadar aktif kal parser.add_argument("--node_activeness_communication_prob", type=float, default=0.5) # alive iken baska nodelara paket gonderme olasiligi -parser.add_argument("--node_initial_activeness_prob", type=float, default=0.8) +parser.add_argument("--node_initial_activeness_prob", type=float, default=0.5) +parser.add_argument("--node_package_process_per_tick", type=int, default=5) +parser.add_argument("--run_until_termination", action="store_true", default=False) +parser.add_argument("--passiveness_death_thresh", type=int, default=20) sp = parser.add_subparsers() @@ -54,13 +59,11 @@ if __name__ == "__main__": N = Star(args.slave_count, master_is_root=args.master_is_root) total_nodes = args.slave_count + 1 - node_active_ticks_initial = [random.randint(args.node_min_activeness_after_receive, args.node_max_activeness_after_receive) if random.random() <= args.node_initial_activeness_prob else 0 for _ in range(total_nodes)] - - # N.plot() - # plt.show() + if args.run_until_termination: + args.simulation_ticks = 10**10 - topo = Topology() - topo.construct_from_graph(N.G, AdHocNode, P2PFIFOPerfectChannel, context={ + node_active_ticks_initial = [random.randint(args.node_min_activeness_after_receive, args.node_max_activeness_after_receive) if random.random() <= args.node_initial_activeness_prob else 0 for _ in range(total_nodes)] + topo_context = { "network": N, "ms_per_tick": args.ms_per_tick, "simulation_ticks": args.simulation_ticks, @@ -68,9 +71,66 @@ if __name__ == "__main__": "communication_on_active_prob": args.node_activeness_communication_prob, "min_activeness_after_receive": args.node_min_activeness_after_receive, "max_activeness_after_receive": args.node_max_activeness_after_receive, - }) + "node_package_process_per_tick": args.node_package_process_per_tick, + "passiveness_death_thresh": args.passiveness_death_thresh + } + + print(topo_context) + # N.plot() + # plt.show() + + topo = Topology() + topo.construct_from_graph(N.G, AdHocNode, P2PFIFOPerfectChannel, context=topo_context) topo.start() - N.plot() + stats = { + "active_nodes": [], + "packages_in_transmit": [], + "terminated_on_tick": None + } + + input("\n>>> Proceed ?") + + try: + for t in range(1, args.simulation_ticks + 1): + print(f"[S] Tick: {t}") + + num_packages_queued = 0 + num_nodes_active = 0 + + for node in topo.nodes.values(): + new_state = node.simulation_tick() + + if new_state == AHCNodeSimulationStatus.ACTIVE: + num_nodes_active += 1 + + num_packages_queued += node.waiting_packages_on_queue + + stats["active_nodes"].append(num_nodes_active) + stats["packages_in_transmit"].append(num_packages_queued) + + print(f" (ACTIVE: {num_nodes_active}, PKGS: {num_packages_queued})") + + if (num_packages_queued == 0 and num_nodes_active == 0): + stats["terminated_on_tick"] = t + print("!!! TERMINATED !!!") + break + except KeyboardInterrupt: + pass + + ts = dt.now().timestamp() + + plt.plot(stats["active_nodes"]) + #plt.plot(stats["packages_in_transmit"]) + + plt.savefig(f"simdump/stats_{args.network_type}_{total_nodes}_{ts}.png", dpi=200) + + with open(f"simdump/run_{args.network_type}_{total_nodes}_{ts}.pkl", "wb") as fp: + pickle.dump({ + "args": args, + "context": topo_context, + "stats": stats + }, fp) + plt.show() \ No newline at end of file -- GitLab From 140df4f3db92400bba2d6cd503dbabadc6fe16d9 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sat, 22 May 2021 10:06:10 +0300 Subject: [PATCH 11/47] better plotting --- algorithms.py | 4 ++-- simulator.py | 64 +++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/algorithms.py b/algorithms.py index e6bc590..4d3cf2e 100644 --- a/algorithms.py +++ b/algorithms.py @@ -157,7 +157,7 @@ class ApplicationLayerComponent(ComponentModel): # P2P: packages to process # print(f" ==> N-{self.componentinstancenumber}: ST: {self.simulation_state}, NS: {next_state}, GPF: {got_packages_from}, SPF: {to_friend}, ANT: {self.alive_for_next_ticks}, P2P: {self.basic_message_queue.qsize()}") - time.sleep(self.sleep_ms_per_tick / 1000) + # time.sleep(self.sleep_ms_per_tick / 1000) self.__tick_n += 1 self.simulation_state = next_state @@ -166,7 +166,7 @@ class ApplicationLayerComponent(ComponentModel): elif self.simulation_state == AHCNodeSimulationStatus.ACTIVE: self._passive_counter = 0 - return next_state + return next_state, to_friend class AdHocNode(ComponentModel): def __init__(self, componentname, componentid, context): diff --git a/simulator.py b/simulator.py index 106df29..df6d8a4 100644 --- a/simulator.py +++ b/simulator.py @@ -3,8 +3,10 @@ import sys import time import pickle import random +import pandas as pd import networkx as nx from enum import Enum +import seaborn as sns import matplotlib.pyplot as plt from datetime import datetime as dt from argparse import ArgumentParser @@ -27,6 +29,7 @@ parser.add_argument("--node_activeness_communication_prob", type=float, default= parser.add_argument("--node_initial_activeness_prob", type=float, default=0.5) parser.add_argument("--node_package_process_per_tick", type=int, default=5) parser.add_argument("--run_until_termination", action="store_true", default=False) +parser.add_argument("--exit_on_termination", action="store_true", default=False) parser.add_argument("--passiveness_death_thresh", type=int, default=20) sp = parser.add_subparsers() @@ -85,43 +88,75 @@ if __name__ == "__main__": topo.start() stats = { - "active_nodes": [], - "packages_in_transmit": [], + "df": pd.DataFrame(data={ + "dead_nodes": [], + "active_nodes": [], + "packages_in_transmit": [], + }), "terminated_on_tick": None } + fig, axes = plt.subplots(1, 1) + fig.set_figwidth(20) + fig.set_figheight(5) + # fig.tight_layout() + input("\n>>> Proceed ?") try: for t in range(1, args.simulation_ticks + 1): print(f"[S] Tick: {t}") - num_packages_queued = 0 + packages_sent = 0 + packages_waiting_on_queue = 0 num_nodes_active = 0 + num_dead_nodes = 0 for node in topo.nodes.values(): - new_state = node.simulation_tick() + new_state, pkg_sent_to_friend = node.simulation_tick() if new_state == AHCNodeSimulationStatus.ACTIVE: num_nodes_active += 1 + elif new_state == AHCNodeSimulationStatus.OUT_OF_CLOCK: + num_dead_nodes += 1 + + if pkg_sent_to_friend is not None: + packages_sent += 1 - num_packages_queued += node.waiting_packages_on_queue + packages_waiting_on_queue += node.waiting_packages_on_queue + + stats["df"].loc[t-1] = [num_dead_nodes, num_nodes_active, packages_sent] - stats["active_nodes"].append(num_nodes_active) - stats["packages_in_transmit"].append(num_packages_queued) + # stats["dead_nodes"].append(num_dead_nodes) + # stats["active_nodes"].append(num_nodes_active) + # stats["packages_in_transmit"].append(packages_sent) - print(f" (ACTIVE: {num_nodes_active}, PKGS: {num_packages_queued})") + print(f" (ACTIVE: {num_nodes_active}, PKGS-WAIT: {packages_waiting_on_queue}, PKGS-SENT: {packages_sent})") - if (num_packages_queued == 0 and num_nodes_active == 0): + if (packages_waiting_on_queue == 0 and num_nodes_active == 0 and packages_sent == 0): stats["terminated_on_tick"] = t print("!!! TERMINATED !!!") - break + + if args.exit_on_termination: + break + + # axes.scatter(x=t, y=num_nodes_active) + axes.cla() + sns.lineplot(data=stats["df"], ax=axes, color="red") + # sns.lineplot(data=stats["active_nodes"], ax=axes, color="red") + # sns.lineplot(data=stats["dead_nodes"], ax=axes, color="mediumslateblue") + # sns.lineplot(data=stats["packages_in_transmit"], ax=axes, color="green") + plt.pause(0.0005) + time.sleep(args.ms_per_tick / 1000) except KeyboardInterrupt: pass ts = dt.now().timestamp() - plt.plot(stats["active_nodes"]) + # axes.cla() + # sns.lineplot(data=stats["active_nodes"], ax=axes) + # sns.kdeplot(data=stats["active_nodes"], ax=axes) + #plt.plot(stats["packages_in_transmit"]) plt.savefig(f"simdump/stats_{args.network_type}_{total_nodes}_{ts}.png", dpi=200) @@ -133,4 +168,9 @@ if __name__ == "__main__": "stats": stats }, fp) - plt.show() \ No newline at end of file + plt.show() + + ## IMPORTANT + # possibe evaluation metrics + # num(control packages) / num(total packages) => + # tick(algo done) - tick(termination) => ne kadar erken detect etti \ No newline at end of file -- GitLab From 19b989819d7ee969cfb6eabb021f372839b981eb Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sat, 22 May 2021 10:18:08 +0300 Subject: [PATCH 12/47] hard stop --- algorithms.py | 8 ++++++++ simulator.py | 17 ++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/algorithms.py b/algorithms.py index 4d3cf2e..9fceced 100644 --- a/algorithms.py +++ b/algorithms.py @@ -58,6 +58,11 @@ class ApplicationLayerComponent(ComponentModel): self.package_process_per_tick = context["node_package_process_per_tick"] self.die_passiveness_threshold = context["passiveness_death_thresh"] + if context["hard_stop_on_tick"] is None: + self.hard_stop_on_tick = None + else: + self.hard_stop_on_tick = context["hard_stop_on_tick"][self.componentinstancenumber] + self.friend_ids = [i for i in context["network"].G.nodes() if i != componentinstancenumber] self.__tick_n = 0 @@ -99,6 +104,9 @@ class ApplicationLayerComponent(ComponentModel): next_state = AHCNodeSimulationStatus.OUT_OF_CLOCK elif self._passive_counter >= self.die_passiveness_threshold: next_state = AHCNodeSimulationStatus.OUT_OF_CLOCK + elif self.__tick_n >= self.hard_stop_on_tick: + next_state = AHCNodeSimulationStatus.OUT_OF_CLOCK + print(f" ==> N-{self.componentinstancenumber}: HARD STOP") else: if self.simulation_state == AHCNodeSimulationStatus.OUT_OF_CLOCK: next_state = AHCNodeSimulationStatus.OUT_OF_CLOCK diff --git a/simulator.py b/simulator.py index df6d8a4..2ea5ae3 100644 --- a/simulator.py +++ b/simulator.py @@ -28,9 +28,15 @@ parser.add_argument("--node_max_activeness_after_receive", type=int, default=5) parser.add_argument("--node_activeness_communication_prob", type=float, default=0.5) # alive iken baska nodelara paket gonderme olasiligi parser.add_argument("--node_initial_activeness_prob", type=float, default=0.5) parser.add_argument("--node_package_process_per_tick", type=int, default=5) + parser.add_argument("--run_until_termination", action="store_true", default=False) parser.add_argument("--exit_on_termination", action="store_true", default=False) + parser.add_argument("--passiveness_death_thresh", type=int, default=20) +parser.add_argument("--hard_stop_nodes", action="store_true", default=False) +parser.add_argument("--hard_stop_min_tick", type=int, default=50) +parser.add_argument("--hard_stop_max_tick", type=int, default=300) +parser.add_argument("--hard_stop_prob", type=float, default=0.5) sp = parser.add_subparsers() @@ -65,6 +71,14 @@ if __name__ == "__main__": if args.run_until_termination: args.simulation_ticks = 10**10 + assert args.hard_stop_max_tick < args.simulation_ticks + assert args.hard_stop_min_tick > 0 + + hard_stop_on_tick = None + + if args.hard_stop_nodes: + hard_stop_on_tick = [random.randint(args.hard_stop_min_tick, args.hard_stop_max_tick) for _ in range(total_nodes)] + node_active_ticks_initial = [random.randint(args.node_min_activeness_after_receive, args.node_max_activeness_after_receive) if random.random() <= args.node_initial_activeness_prob else 0 for _ in range(total_nodes)] topo_context = { "network": N, @@ -75,7 +89,8 @@ if __name__ == "__main__": "min_activeness_after_receive": args.node_min_activeness_after_receive, "max_activeness_after_receive": args.node_max_activeness_after_receive, "node_package_process_per_tick": args.node_package_process_per_tick, - "passiveness_death_thresh": args.passiveness_death_thresh + "passiveness_death_thresh": args.passiveness_death_thresh, + "hard_stop_on_tick": hard_stop_on_tick } print(topo_context) -- GitLab From 3ff9834a43a5f1eeb46b59c9d55b0b1287e75f64 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sat, 22 May 2021 10:32:56 +0300 Subject: [PATCH 13/47] cli and simulator funcs separation --- cli.py | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ simulator.py | 54 ++++------------------------------------------------ 2 files changed, 57 insertions(+), 50 deletions(-) create mode 100644 cli.py diff --git a/cli.py b/cli.py new file mode 100644 index 0000000..8471748 --- /dev/null +++ b/cli.py @@ -0,0 +1,53 @@ +from argparse import ArgumentParser +from simulator import run_dijkstra_scholten_simulation, run_shavit_francez_simulation + +algorithm_handlers = { + "djikstra-scholten": run_dijkstra_scholten_simulation, + "shavit-francez": run_shavit_francez_simulation, +} + + ## IMPORTANT NOTE + # possibe evaluation metrics + # num(control packages) / num(total packages) => + # tick(algo done) - tick(termination) => ne kadar erken detect etti + +parser = ArgumentParser() +parser.add_argument("algorithm", type=str, choices=list(algorithm_handlers.keys())) +parser.add_argument("simulation_ticks", type=int) +parser.add_argument("ms_per_tick", type=int) +parser.add_argument("--node_min_activeness_after_receive", type=int, default=3) # paket aldiktan sonra min bu kadar aktif kal +parser.add_argument("--node_max_activeness_after_receive", type=int, default=5) # paket aldiktan sonra max bu kadar aktif kal +parser.add_argument("--node_activeness_communication_prob", type=float, default=0.5) # alive iken baska nodelara paket gonderme olasiligi +parser.add_argument("--node_initial_activeness_prob", type=float, default=0.5) +parser.add_argument("--node_package_process_per_tick", type=int, default=5) + +parser.add_argument("--run_until_termination", action="store_true", default=False) +parser.add_argument("--exit_on_termination", action="store_true", default=False) + +parser.add_argument("--passiveness_death_thresh", type=int, default=20) +parser.add_argument("--hard_stop_nodes", action="store_true", default=False) +parser.add_argument("--hard_stop_min_tick", type=int, default=50) +parser.add_argument("--hard_stop_max_tick", type=int, default=300) +parser.add_argument("--hard_stop_prob", type=float, default=0.5) + +sp = parser.add_subparsers() + +erg_parser = sp.add_parser("erg") +erg_parser.add_argument("node_count", type=int) +erg_parser.add_argument("--node_connectivity", type=float, default=0.5) +erg_parser.set_defaults(network_type="erg") + +grid_parser = sp.add_parser("grid") +grid_parser.add_argument("node_count_on_edge", type=int) +grid_parser.set_defaults(network_type="grid") + +star_parser = sp.add_parser("star") +star_parser.add_argument("slave_count", type=int) +star_parser.add_argument("--master_is_root", type=bool, default=True) +star_parser.set_defaults(network_type="star") + +if __name__ == "__main__": + args = parser.parse_args() + print(f"[+] Network type: {args.network_type}") + + algorithm_handlers[args.algorithm](args) \ No newline at end of file diff --git a/simulator.py b/simulator.py index 2ea5ae3..f55a01b 100644 --- a/simulator.py +++ b/simulator.py @@ -4,60 +4,16 @@ import time import pickle import random import pandas as pd -import networkx as nx -from enum import Enum import seaborn as sns import matplotlib.pyplot as plt from datetime import datetime as dt -from argparse import ArgumentParser +from Ahc import Topology from graph import ERG, Grid, Star from algorithms import AdHocNode, AHCNodeSimulationStatus from Channels import P2PFIFOPerfectChannel -from LinkLayers.GenericLinkLayer import LinkLayer -from NetworkLayers.AllSeeingEyeNetworkLayer import AllSeingEyeNetworkLayer -from Ahc import (ComponentModel, Event, ConnectorTypes, Topology, - ComponentRegistry, GenericMessagePayload, GenericMessageHeader, - GenericMessage, EventTypes) - -parser = ArgumentParser() -parser.add_argument("simulation_ticks", type=int) -parser.add_argument("ms_per_tick", type=int) -parser.add_argument("--node_min_activeness_after_receive", type=int, default=3) # paket aldiktan sonra min bu kadar aktif kal -parser.add_argument("--node_max_activeness_after_receive", type=int, default=5) # paket aldiktan sonra max bu kadar aktif kal -parser.add_argument("--node_activeness_communication_prob", type=float, default=0.5) # alive iken baska nodelara paket gonderme olasiligi -parser.add_argument("--node_initial_activeness_prob", type=float, default=0.5) -parser.add_argument("--node_package_process_per_tick", type=int, default=5) - -parser.add_argument("--run_until_termination", action="store_true", default=False) -parser.add_argument("--exit_on_termination", action="store_true", default=False) - -parser.add_argument("--passiveness_death_thresh", type=int, default=20) -parser.add_argument("--hard_stop_nodes", action="store_true", default=False) -parser.add_argument("--hard_stop_min_tick", type=int, default=50) -parser.add_argument("--hard_stop_max_tick", type=int, default=300) -parser.add_argument("--hard_stop_prob", type=float, default=0.5) - -sp = parser.add_subparsers() - -erg_parser = sp.add_parser("erg") -erg_parser.add_argument("node_count", type=int) -erg_parser.add_argument("--node_connectivity", type=float, default=0.5) -erg_parser.set_defaults(network_type="erg") - -grid_parser = sp.add_parser("grid") -grid_parser.add_argument("node_count_on_edge", type=int) -grid_parser.set_defaults(network_type="grid") - -star_parser = sp.add_parser("star") -star_parser.add_argument("slave_count", type=int) -star_parser.add_argument("--master_is_root", type=bool, default=True) -star_parser.set_defaults(network_type="star") - -if __name__ == "__main__": - args = parser.parse_args() - print(f"[+] Network type: {args.network_type}") +def run_dijkstra_scholten_simulation(args): if args.network_type == "erg": N = ERG(args.node_count, args.node_connectivity) total_nodes = args.node_count @@ -185,7 +141,5 @@ if __name__ == "__main__": plt.show() - ## IMPORTANT - # possibe evaluation metrics - # num(control packages) / num(total packages) => - # tick(algo done) - tick(termination) => ne kadar erken detect etti \ No newline at end of file +def run_shavit_francez_simulation(args): + raise NotImplementedError() \ No newline at end of file -- GitLab From c3f3007f4fa587ede630d417fb48a7e10bbc7fb5 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sat, 22 May 2021 10:51:31 +0300 Subject: [PATCH 14/47] dijkstra-scolten separation && only root alive initially --- .gitignore | 5 + algorithms.py => algorithms_orig.py | 0 dijkstra_scholten.py | 230 ++++++++++++++++++++++++++++ simulator.py | 8 +- 4 files changed, 239 insertions(+), 4 deletions(-) rename algorithms.py => algorithms_orig.py (100%) create mode 100644 dijkstra_scholten.py diff --git a/.gitignore b/.gitignore index 5391d87..c55099c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ +# Custom +.DS_Store +simdump/ + + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/algorithms.py b/algorithms_orig.py similarity index 100% rename from algorithms.py rename to algorithms_orig.py diff --git a/dijkstra_scholten.py b/dijkstra_scholten.py new file mode 100644 index 0000000..e6c5a6f --- /dev/null +++ b/dijkstra_scholten.py @@ -0,0 +1,230 @@ +import os +import queue +import sys +import time +import json +import queue +import random +import networkx as nx +from enum import Enum +import matplotlib.pyplot as plt +from datetime import datetime as dt + +from Channels import P2PFIFOPerfectChannel +from LinkLayers.GenericLinkLayer import LinkLayer +from NetworkLayers.AllSeeingEyeNetworkLayer import AllSeingEyeNetworkLayer +from Ahc import (ComponentModel, Event, ConnectorTypes, Topology, + ComponentRegistry, GenericMessagePayload, GenericMessageHeader, + GenericMessage, EventTypes) + +registry = ComponentRegistry() + +# define your own message types +class ApplicationLayerMessageType(Enum): + BASIC = "basic" + CONTROL = "control" # NOTE: Means the acknowledgement message! + +class DSAHCNodeSimulationStatus(Enum): + ACTIVE = "active" + PASSIVE = "passive" + OUT_OF_CLOCK = "ooc" + +# define your own message header structure +class ApplicationLayerMessageHeader(GenericMessageHeader): + pass + +# define your own message payload structure +class ApplicationLayerMessagePayload(GenericMessagePayload): + pass + +class DijkstraScholtenApplicationLayerComponent(ComponentModel): + def __init__(self, componentname, componentinstancenumber, context): + super().__init__(componentname, componentinstancenumber, context=context) + + self.context = context + # self.eventhandlers[ApplicationLayerMessageType.BASIC] = self.on_basic_message + # self.eventhandlers[ApplicationLayerMessageType.CONTROL] = self.on_control_message + + self.basic_message_queue = queue.Queue(maxsize=-1) + self.control_message_queue = queue.Queue(maxsize=-1) + self.simulation_state = DSAHCNodeSimulationStatus.PASSIVE + + self.sleep_ms_per_tick = context["ms_per_tick"] + self.simulation_ticks_total = context["simulation_ticks"] + # self.alive_for_next_ticks = context["initial_liveness"][componentinstancenumber] + self.communication_on_active_prob = context["communication_on_active_prob"] + self.min_activeness_after_receive = context["min_activeness_after_receive"] + self.max_activeness_after_receive = context["max_activeness_after_receive"] + self.package_process_per_tick = context["node_package_process_per_tick"] + self.die_passiveness_threshold = context["passiveness_death_thresh"] + + if context["hard_stop_on_tick"] is None: + self.hard_stop_on_tick = None + else: + self.hard_stop_on_tick = context["hard_stop_on_tick"][self.componentinstancenumber] + + self.friend_ids = [i for i in context["network"].G.nodes() if i != componentinstancenumber] + + self.__tick_n = 0 + self._passive_counter = 0 + + self._child_counter = 0 + self._i_am_root = context["network"].root == self.componentinstancenumber + + if self._i_am_root: + self.alive_for_next_ticks = 10**6 # not inf, but enough! + else: + self.alive_for_next_ticks = 0 + + if self.alive_for_next_ticks > 0: + self.simulation_state = DSAHCNodeSimulationStatus.ACTIVE + + def prepare_application_layer_message(self, message_type: ApplicationLayerMessageType, destination_node_id: int, payload: object) -> GenericMessage: + hdr = ApplicationLayerMessageHeader(message_type, self.componentinstancenumber, destination_node_id) + payload = ApplicationLayerMessagePayload(payload) + + return GenericMessage(hdr, payload) + + def send_random_basic_message(self, to: int) -> None: + self._child_counter += 1 + self.send_down(Event(self, EventTypes.MFRT, self.prepare_application_layer_message(ApplicationLayerMessageType.BASIC, to, str(dt.now().timestamp())))) + + def on_init(self, eventobj: Event): + # print(f"Initializing {self.componentname}.{self.componentinstancenumber}") + pass + + def on_message_from_bottom(self, eventobj: Event): + applmessage = eventobj.eventcontent + hdr = applmessage.header + + # print(f"Node-{self.componentinstancenumber}: Node-{hdr.messagefrom} has sent {hdr.messagetype} message (payload: {applmessage.payload})") + + if hdr.messagetype == ApplicationLayerMessageType.BASIC: + self.basic_message_queue.put_nowait(applmessage) + elif hdr.messagetype == ApplicationLayerMessageType.CONTROL: + # self.control_message_queue.put_nowait(applmessage) + self._child_counter -= 1 + + def simulation_tick(self): + next_state = None + got_packages_from = None + to_friend = None + + if self.__tick_n >= self.simulation_ticks_total: + next_state = DSAHCNodeSimulationStatus.OUT_OF_CLOCK + elif self._passive_counter >= self.die_passiveness_threshold: + next_state = DSAHCNodeSimulationStatus.OUT_OF_CLOCK + elif self.__tick_n >= self.hard_stop_on_tick: + next_state = DSAHCNodeSimulationStatus.OUT_OF_CLOCK + print(f" ==> N-{self.componentinstancenumber}: HARD STOP") + else: + if self.simulation_state == DSAHCNodeSimulationStatus.OUT_OF_CLOCK: + next_state = DSAHCNodeSimulationStatus.OUT_OF_CLOCK + elif self.simulation_state == DSAHCNodeSimulationStatus.PASSIVE: + if self.basic_message_queue.empty(): + # no incoming package, still passive. + next_state = DSAHCNodeSimulationStatus.PASSIVE + else: + got_packages_from = [] + + for _ in range(self.package_process_per_tick): + try: + package = self.basic_message_queue.get_nowait() + # print(f"+P+ N-{self.componentinstancenumber} <==BASIC== N-{package.header.messagefrom} ({package.payload.messagepayload})") + got_packages_from.append(package.header.messagefrom) + except queue.Empty: + break + + self.alive_for_next_ticks = random.randint(self.min_activeness_after_receive, self.max_activeness_after_receive) + next_state = DSAHCNodeSimulationStatus.ACTIVE + elif self.simulation_state == DSAHCNodeSimulationStatus.ACTIVE: + got_packages_from = [] + + for _ in range(self.package_process_per_tick): + try: + package = self.basic_message_queue.get_nowait() + # print(f"+A+ N-{self.componentinstancenumber} <==BASIC== N-{package.header.messagefrom} ({package.payload.messagepayload})") + got_packages_from.append(package.header.messagefrom) + except queue.Empty: + break + + if random.random() <= self.communication_on_active_prob: + # send package to a random friend.. + to_friend = random.choice(self.friend_ids) + self.send_random_basic_message(to_friend) + + self.alive_for_next_ticks -= 1 + + if self.alive_for_next_ticks == 0: + if len(got_packages_from) > 0: + # got a package, this means immeiate activeness from passive! + next_state = DSAHCNodeSimulationStatus.ACTIVE + self.alive_for_next_ticks = random.randint(self.min_activeness_after_receive, self.max_activeness_after_receive) + else: + next_state = DSAHCNodeSimulationStatus.PASSIVE + else: + next_state = DSAHCNodeSimulationStatus.ACTIVE + + assert next_state is not None + + # ST: state + # NS: next state + # GPF: got packages from + # SPF: sent package to friend + # ANT: alive next ticks + # P2P: packages to process + # print(f" ==> N-{self.componentinstancenumber}: ST: {self.simulation_state}, NS: {next_state}, GPF: {got_packages_from}, SPF: {to_friend}, ANT: {self.alive_for_next_ticks}, P2P: {self.basic_message_queue.qsize()}") + + # time.sleep(self.sleep_ms_per_tick / 1000) + self.__tick_n += 1 + self.simulation_state = next_state + + if self.simulation_state == DSAHCNodeSimulationStatus.PASSIVE: + self._passive_counter += 1 + elif self.simulation_state == DSAHCNodeSimulationStatus.ACTIVE: + self._passive_counter = 0 + + return next_state, to_friend + +class DijkstraScholtenAdHocNode(ComponentModel): + def __init__(self, componentname, componentid, context): + self.context = context + # SUBCOMPONENTS + self.appllayer = DijkstraScholtenApplicationLayerComponent("ApplicationLayer", componentid, context=self.context) + self.netlayer = AllSeingEyeNetworkLayer("NetworkLayer", componentid) + self.linklayer = LinkLayer("LinkLayer", componentid) + # self.failuredetect = GenericFailureDetector("FailureDetector", componentid) + + # CONNECTIONS AMONG SUBCOMPONENTS + self.appllayer.connect_me_to_component(ConnectorTypes.DOWN, self.netlayer) + # self.failuredetect.connectMeToComponent(PortNames.DOWN, self.netlayer) + self.netlayer.connect_me_to_component(ConnectorTypes.UP, self.appllayer) + # self.netlayer.connectMeToComponent(PortNames.UP, self.failuredetect) + self.netlayer.connect_me_to_component(ConnectorTypes.DOWN, self.linklayer) + self.linklayer.connect_me_to_component(ConnectorTypes.UP, self.netlayer) + + # Connect the bottom component to the composite component.... + self.linklayer.connect_me_to_component(ConnectorTypes.DOWN, self) + self.connect_me_to_component(ConnectorTypes.UP, self.linklayer) + + super().__init__(componentname, componentid, context=self.context) + + def on_init(self, eventobj: Event): + # print(f"Initializing {self.componentname}.{self.componentinstancenumber}") + pass + + def on_message_from_top(self, eventobj: Event): + self.send_down(Event(self, EventTypes.MFRT, eventobj.eventcontent)) + + def on_message_from_bottom(self, eventobj: Event): + self.send_up(Event(self, EventTypes.MFRB, eventobj.eventcontent)) + + def simulation_tick(self): + return self.appllayer.simulation_tick() + + @property + def waiting_packages_on_queue(self): + if self.appllayer.simulation_state == DSAHCNodeSimulationStatus.OUT_OF_CLOCK: + return 0 + + return self.appllayer.basic_message_queue.qsize() \ No newline at end of file diff --git a/simulator.py b/simulator.py index f55a01b..e9965b1 100644 --- a/simulator.py +++ b/simulator.py @@ -10,7 +10,7 @@ from datetime import datetime as dt from Ahc import Topology from graph import ERG, Grid, Star -from algorithms import AdHocNode, AHCNodeSimulationStatus +from dijkstra_scholten import DijkstraScholtenAdHocNode, DSAHCNodeSimulationStatus from Channels import P2PFIFOPerfectChannel def run_dijkstra_scholten_simulation(args): @@ -54,7 +54,7 @@ def run_dijkstra_scholten_simulation(args): # plt.show() topo = Topology() - topo.construct_from_graph(N.G, AdHocNode, P2PFIFOPerfectChannel, context=topo_context) + topo.construct_from_graph(N.G, DijkstraScholtenAdHocNode, P2PFIFOPerfectChannel, context=topo_context) topo.start() @@ -86,9 +86,9 @@ def run_dijkstra_scholten_simulation(args): for node in topo.nodes.values(): new_state, pkg_sent_to_friend = node.simulation_tick() - if new_state == AHCNodeSimulationStatus.ACTIVE: + if new_state == DSAHCNodeSimulationStatus.ACTIVE: num_nodes_active += 1 - elif new_state == AHCNodeSimulationStatus.OUT_OF_CLOCK: + elif new_state == DSAHCNodeSimulationStatus.OUT_OF_CLOCK: num_dead_nodes += 1 if pkg_sent_to_friend is not None: -- GitLab From 88fdd83ff953a14fe190c64e53ca06980b58d1f1 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sat, 22 May 2021 12:55:09 +0300 Subject: [PATCH 15/47] DS DONE. --- dijkstra_scholten.py | 104 ++++++++++++++++++++++++++++++++++++------- simulator.py | 30 ++++++++++--- 2 files changed, 112 insertions(+), 22 deletions(-) diff --git a/dijkstra_scholten.py b/dijkstra_scholten.py index e6c5a6f..b04607c 100644 --- a/dijkstra_scholten.py +++ b/dijkstra_scholten.py @@ -28,6 +28,10 @@ class DSAHCNodeSimulationStatus(Enum): ACTIVE = "active" PASSIVE = "passive" OUT_OF_CLOCK = "ooc" + OUT_OF_TREE = "oot" + + def __str__(self): + return self.name # define your own message header structure class ApplicationLayerMessageHeader(GenericMessageHeader): @@ -63,16 +67,21 @@ class DijkstraScholtenApplicationLayerComponent(ComponentModel): else: self.hard_stop_on_tick = context["hard_stop_on_tick"][self.componentinstancenumber] - self.friend_ids = [i for i in context["network"].G.nodes() if i != componentinstancenumber] - self.__tick_n = 0 self._passive_counter = 0 self._child_counter = 0 + self._parent_node = None + self._in_tree = False + self._children = [] + + self._cms = 0 + self._i_am_root = context["network"].root == self.componentinstancenumber if self._i_am_root: - self.alive_for_next_ticks = 10**6 # not inf, but enough! + self.alive_for_next_ticks = 5 # this may change though... + self._in_tree = True else: self.alive_for_next_ticks = 0 @@ -87,8 +96,14 @@ class DijkstraScholtenApplicationLayerComponent(ComponentModel): def send_random_basic_message(self, to: int) -> None: self._child_counter += 1 + self._children.append(to) self.send_down(Event(self, EventTypes.MFRT, self.prepare_application_layer_message(ApplicationLayerMessageType.BASIC, to, str(dt.now().timestamp())))) + def send_ack_control_message(self, to: int, is_dead: bool) -> None: + # print(f"send_ack_control_message: N-{self.componentinstancenumber} ==> N-{to} ({self._parent_node}) : {'DEAD' if is_dead else 'PKG_RESP'}") + self.send_down(Event(self, EventTypes.MFRT, self.prepare_application_layer_message(ApplicationLayerMessageType.CONTROL, to, str(dt.now().timestamp())))) + self._cms += 1 + def on_init(self, eventobj: Event): # print(f"Initializing {self.componentname}.{self.componentinstancenumber}") pass @@ -101,29 +116,77 @@ class DijkstraScholtenApplicationLayerComponent(ComponentModel): if hdr.messagetype == ApplicationLayerMessageType.BASIC: self.basic_message_queue.put_nowait(applmessage) + + if self._in_tree: + self.send_ack_control_message(hdr.messagefrom, False) + else: + self._parent_node = hdr.messagefrom + self._in_tree = True + elif hdr.messagetype == ApplicationLayerMessageType.CONTROL: # self.control_message_queue.put_nowait(applmessage) - self._child_counter -= 1 + + try: + self._children.remove(hdr.messagefrom) + self._child_counter -= 1 + except ValueError as e: + # print(f"\n\n\n{self.componentinstancenumber}: {e} {hdr.messagefrom} {self._children}\n\n\n") + pass + + def exit_tree(self): + # Exit from the tree + if self._in_tree: + self.send_ack_control_message(self._parent_node, True) + self._in_tree = False + self._parent_node = None + + self.context["alive_nodes"].remove(self.componentinstancenumber) def simulation_tick(self): next_state = None got_packages_from = None to_friend = None - if self.__tick_n >= self.simulation_ticks_total: - next_state = DSAHCNodeSimulationStatus.OUT_OF_CLOCK + _upd_children = [] + + for c in self._children: + if c in self.context["alive_nodes"]: + _upd_children.append(c) + + self._children = _upd_children + self._child_counter = len(self._children) + + if self.simulation_state == DSAHCNodeSimulationStatus.OUT_OF_TREE: + next_state = DSAHCNodeSimulationStatus.OUT_OF_TREE + print(f" ==> N-{self.componentinstancenumber}: OUT OF TREE") + elif self.__tick_n >= self.simulation_ticks_total: + self.exit_tree() + next_state = DSAHCNodeSimulationStatus.OUT_OF_TREE elif self._passive_counter >= self.die_passiveness_threshold: - next_state = DSAHCNodeSimulationStatus.OUT_OF_CLOCK + self.exit_tree() + next_state = DSAHCNodeSimulationStatus.OUT_OF_TREE elif self.__tick_n >= self.hard_stop_on_tick: - next_state = DSAHCNodeSimulationStatus.OUT_OF_CLOCK + self.exit_tree() + next_state = DSAHCNodeSimulationStatus.OUT_OF_TREE print(f" ==> N-{self.componentinstancenumber}: HARD STOP") else: if self.simulation_state == DSAHCNodeSimulationStatus.OUT_OF_CLOCK: next_state = DSAHCNodeSimulationStatus.OUT_OF_CLOCK elif self.simulation_state == DSAHCNodeSimulationStatus.PASSIVE: if self.basic_message_queue.empty(): - # no incoming package, still passive. - next_state = DSAHCNodeSimulationStatus.PASSIVE + if self._in_tree and self._child_counter == 0: + if self._i_am_root: + print(f" **ROOT** N-{self.componentinstancenumber}: Termination!!!") + __cms = self._cms + self._cms = 0 + return None, None, __cms + else: + self.exit_tree() + next_state = DSAHCNodeSimulationStatus.OUT_OF_TREE + print(f" ==> N-{self.componentinstancenumber}: OUT OF TREE") + else: + # no incoming package, still passive. + next_state = DSAHCNodeSimulationStatus.PASSIVE else: got_packages_from = [] @@ -150,8 +213,16 @@ class DijkstraScholtenApplicationLayerComponent(ComponentModel): if random.random() <= self.communication_on_active_prob: # send package to a random friend.. - to_friend = random.choice(self.friend_ids) - self.send_random_basic_message(to_friend) + + _alive_ones = [n for n in self.context["alive_nodes"] if n != self.componentinstancenumber] + + if len(_alive_ones) == 0: # everyone is dead!!! + # print(f" **ROOT** N-{self.componentinstancenumber}: Eveyone is dead!!!") + # return None, None # time to go! + to_friend = None + else: + to_friend = random.choice(_alive_ones) + self.send_random_basic_message(to_friend) self.alive_for_next_ticks -= 1 @@ -173,7 +244,7 @@ class DijkstraScholtenApplicationLayerComponent(ComponentModel): # SPF: sent package to friend # ANT: alive next ticks # P2P: packages to process - # print(f" ==> N-{self.componentinstancenumber}: ST: {self.simulation_state}, NS: {next_state}, GPF: {got_packages_from}, SPF: {to_friend}, ANT: {self.alive_for_next_ticks}, P2P: {self.basic_message_queue.qsize()}") + # print(f" {'ROOT' if self._i_am_root else '==>'} N-{self.componentinstancenumber}: P: {self._parent_node}, CC: ({self._child_counter}) {self._children}, ST: {self.simulation_state}, NS: {next_state}, GPF: {got_packages_from}, SPF: {to_friend}, ANT: {self.alive_for_next_ticks}, P2P: {self.basic_message_queue.qsize()}") # time.sleep(self.sleep_ms_per_tick / 1000) self.__tick_n += 1 @@ -184,7 +255,10 @@ class DijkstraScholtenApplicationLayerComponent(ComponentModel): elif self.simulation_state == DSAHCNodeSimulationStatus.ACTIVE: self._passive_counter = 0 - return next_state, to_friend + __cms = self._cms + self._cms = 0 + + return next_state, to_friend, __cms class DijkstraScholtenAdHocNode(ComponentModel): def __init__(self, componentname, componentid, context): @@ -224,7 +298,7 @@ class DijkstraScholtenAdHocNode(ComponentModel): @property def waiting_packages_on_queue(self): - if self.appllayer.simulation_state == DSAHCNodeSimulationStatus.OUT_OF_CLOCK: + if self.appllayer.simulation_state == DSAHCNodeSimulationStatus.OUT_OF_CLOCK or self.appllayer.simulation_state == DSAHCNodeSimulationStatus.OUT_OF_TREE: return 0 return self.appllayer.basic_message_queue.qsize() \ No newline at end of file diff --git a/simulator.py b/simulator.py index e9965b1..9869b4c 100644 --- a/simulator.py +++ b/simulator.py @@ -36,6 +36,8 @@ def run_dijkstra_scholten_simulation(args): hard_stop_on_tick = [random.randint(args.hard_stop_min_tick, args.hard_stop_max_tick) for _ in range(total_nodes)] node_active_ticks_initial = [random.randint(args.node_min_activeness_after_receive, args.node_max_activeness_after_receive) if random.random() <= args.node_initial_activeness_prob else 0 for _ in range(total_nodes)] + alive_nodes = list(range(total_nodes)) + topo_context = { "network": N, "ms_per_tick": args.ms_per_tick, @@ -46,7 +48,8 @@ def run_dijkstra_scholten_simulation(args): "max_activeness_after_receive": args.node_max_activeness_after_receive, "node_package_process_per_tick": args.node_package_process_per_tick, "passiveness_death_thresh": args.passiveness_death_thresh, - "hard_stop_on_tick": hard_stop_on_tick + "hard_stop_on_tick": hard_stop_on_tick, + "alive_nodes": alive_nodes } print(topo_context) @@ -62,9 +65,12 @@ def run_dijkstra_scholten_simulation(args): "df": pd.DataFrame(data={ "dead_nodes": [], "active_nodes": [], - "packages_in_transmit": [], + "packets_in_transmit": [], + "queued_packets": [], + "control_packets_sent": [] }), - "terminated_on_tick": None + "terminated_on_tick": None, + "announced_on_tick": None } fig, axes = plt.subplots(1, 1) @@ -82,21 +88,28 @@ def run_dijkstra_scholten_simulation(args): packages_waiting_on_queue = 0 num_nodes_active = 0 num_dead_nodes = 0 + break_this_tick = False + control_packets_sent = 0 - for node in topo.nodes.values(): - new_state, pkg_sent_to_friend = node.simulation_tick() + for index, node in topo.nodes.items(): + new_state, pkg_sent_to_friend, cps = node.simulation_tick() + + if index == N.root and new_state is None: + break_this_tick = True if new_state == DSAHCNodeSimulationStatus.ACTIVE: num_nodes_active += 1 - elif new_state == DSAHCNodeSimulationStatus.OUT_OF_CLOCK: + elif new_state == DSAHCNodeSimulationStatus.OUT_OF_TREE: num_dead_nodes += 1 if pkg_sent_to_friend is not None: packages_sent += 1 + + control_packets_sent += cps packages_waiting_on_queue += node.waiting_packages_on_queue - stats["df"].loc[t-1] = [num_dead_nodes, num_nodes_active, packages_sent] + stats["df"].loc[t-1] = [num_dead_nodes, num_nodes_active, packages_sent, packages_waiting_on_queue, control_packets_sent] # stats["dead_nodes"].append(num_dead_nodes) # stats["active_nodes"].append(num_nodes_active) @@ -111,6 +124,9 @@ def run_dijkstra_scholten_simulation(args): if args.exit_on_termination: break + if break_this_tick: + break + # axes.scatter(x=t, y=num_nodes_active) axes.cla() sns.lineplot(data=stats["df"], ax=axes, color="red") -- GitLab From 0f4874e8198869784c347d5c9de6eb5bedeac978 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sat, 22 May 2021 13:15:49 +0300 Subject: [PATCH 16/47] better graohs --- dijkstra_scholten.py | 2 +- simulator.py | 36 +++++++++++++++++++++++++++++------- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/dijkstra_scholten.py b/dijkstra_scholten.py index b04607c..32f5f99 100644 --- a/dijkstra_scholten.py +++ b/dijkstra_scholten.py @@ -158,7 +158,7 @@ class DijkstraScholtenApplicationLayerComponent(ComponentModel): if self.simulation_state == DSAHCNodeSimulationStatus.OUT_OF_TREE: next_state = DSAHCNodeSimulationStatus.OUT_OF_TREE - print(f" ==> N-{self.componentinstancenumber}: OUT OF TREE") + # print(f" ==> N-{self.componentinstancenumber}: OUT OF TREE") elif self.__tick_n >= self.simulation_ticks_total: self.exit_tree() next_state = DSAHCNodeSimulationStatus.OUT_OF_TREE diff --git a/simulator.py b/simulator.py index 9869b4c..170fff5 100644 --- a/simulator.py +++ b/simulator.py @@ -67,15 +67,17 @@ def run_dijkstra_scholten_simulation(args): "active_nodes": [], "packets_in_transmit": [], "queued_packets": [], - "control_packets_sent": [] + "control_packets_sent": [], + "control_basic_instant_ratio": [], + "control_total_cumulative_ratio": [], }), "terminated_on_tick": None, "announced_on_tick": None } - fig, axes = plt.subplots(1, 1) - fig.set_figwidth(20) - fig.set_figheight(5) + fig, axes = plt.subplots(2, 2) + fig.set_figwidth(8) + fig.set_figheight(8) # fig.tight_layout() input("\n>>> Proceed ?") @@ -109,7 +111,17 @@ def run_dijkstra_scholten_simulation(args): packages_waiting_on_queue += node.waiting_packages_on_queue - stats["df"].loc[t-1] = [num_dead_nodes, num_nodes_active, packages_sent, packages_waiting_on_queue, control_packets_sent] + total_pkgs_sent_cum = (stats["df"]["control_packets_sent"].sum() + control_packets_sent + stats["df"]["packets_in_transmit"].sum() + packages_sent) + + stats["df"].loc[t-1] = [ + num_dead_nodes, + num_nodes_active, + packages_sent, + packages_waiting_on_queue, + control_packets_sent, + (control_packets_sent / packages_sent) if packages_sent > 0 else 0, # TODO: Fix later, find a better soln,,, + ((stats["df"]["control_packets_sent"].sum() + control_packets_sent) / total_pkgs_sent_cum) if total_pkgs_sent_cum > 0 else 0 + ] # stats["dead_nodes"].append(num_dead_nodes) # stats["active_nodes"].append(num_nodes_active) @@ -128,8 +140,18 @@ def run_dijkstra_scholten_simulation(args): break # axes.scatter(x=t, y=num_nodes_active) - axes.cla() - sns.lineplot(data=stats["df"], ax=axes, color="red") + + axes[0][0].cla() + axes[0][1].cla() + axes[1][0].cla() + axes[1][1].cla() + + sns.lineplot(data=stats["df"]["active_nodes"], ax=axes[0][0], color="orange") + sns.lineplot(data=stats["df"]["dead_nodes"], ax=axes[1][0], color="blue") + sns.lineplot(data=stats["df"]["packets_in_transmit"], ax=axes[0][1], color="purple") + sns.lineplot(data=stats["df"]["control_packets_sent"], ax=axes[0][1], color="green") + sns.lineplot(data=stats["df"]["control_basic_instant_ratio"], ax=axes[1][1], color="red") + sns.lineplot(data=stats["df"]["control_total_cumulative_ratio"], ax=axes[1][1], color="mediumslateblue") # sns.lineplot(data=stats["active_nodes"], ax=axes, color="red") # sns.lineplot(data=stats["dead_nodes"], ax=axes, color="mediumslateblue") # sns.lineplot(data=stats["packages_in_transmit"], ax=axes, color="green") -- GitLab From cbd9628484e3b7cb70aed76df44cdd315aa788c8 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sat, 22 May 2021 13:19:45 +0300 Subject: [PATCH 17/47] only_root_alive_initially --- cli.py | 2 ++ dijkstra_scholten.py | 15 +++++++++------ simulator.py | 3 ++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/cli.py b/cli.py index 8471748..c20b22f 100644 --- a/cli.py +++ b/cli.py @@ -21,6 +21,8 @@ parser.add_argument("--node_activeness_communication_prob", type=float, default= parser.add_argument("--node_initial_activeness_prob", type=float, default=0.5) parser.add_argument("--node_package_process_per_tick", type=int, default=5) +parser.add_argument("--only_root_alive_initially", action="store_true", default=False) + parser.add_argument("--run_until_termination", action="store_true", default=False) parser.add_argument("--exit_on_termination", action="store_true", default=False) diff --git a/dijkstra_scholten.py b/dijkstra_scholten.py index 32f5f99..871656e 100644 --- a/dijkstra_scholten.py +++ b/dijkstra_scholten.py @@ -55,7 +55,7 @@ class DijkstraScholtenApplicationLayerComponent(ComponentModel): self.sleep_ms_per_tick = context["ms_per_tick"] self.simulation_ticks_total = context["simulation_ticks"] - # self.alive_for_next_ticks = context["initial_liveness"][componentinstancenumber] + self.alive_for_next_ticks = context["initial_liveness"][componentinstancenumber] self.communication_on_active_prob = context["communication_on_active_prob"] self.min_activeness_after_receive = context["min_activeness_after_receive"] self.max_activeness_after_receive = context["max_activeness_after_receive"] @@ -79,11 +79,14 @@ class DijkstraScholtenApplicationLayerComponent(ComponentModel): self._i_am_root = context["network"].root == self.componentinstancenumber - if self._i_am_root: - self.alive_for_next_ticks = 5 # this may change though... - self._in_tree = True - else: - self.alive_for_next_ticks = 0 + if context["only_root_alive_initially"]: + if self._i_am_root: + self.alive_for_next_ticks = 20 # this may change though... + self._in_tree = True + else: + self.alive_for_next_ticks = 0 + elif self._i_am_root and self.alive_for_next_ticks == 0: + self.alive_for_next_ticks = 20 # this may change though... if self.alive_for_next_ticks > 0: self.simulation_state = DSAHCNodeSimulationStatus.ACTIVE diff --git a/simulator.py b/simulator.py index 170fff5..63cc78f 100644 --- a/simulator.py +++ b/simulator.py @@ -49,7 +49,8 @@ def run_dijkstra_scholten_simulation(args): "node_package_process_per_tick": args.node_package_process_per_tick, "passiveness_death_thresh": args.passiveness_death_thresh, "hard_stop_on_tick": hard_stop_on_tick, - "alive_nodes": alive_nodes + "alive_nodes": alive_nodes, + "only_root_alive_initially": args.only_root_alive_initially } print(topo_context) -- GitLab From c80ad68903b8c1ec2bd9ef0ac916648114b921c3 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sat, 22 May 2021 13:22:35 +0300 Subject: [PATCH 18/47] better and better graphs --- simulator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/simulator.py b/simulator.py index 63cc78f..87f8270 100644 --- a/simulator.py +++ b/simulator.py @@ -121,7 +121,7 @@ def run_dijkstra_scholten_simulation(args): packages_waiting_on_queue, control_packets_sent, (control_packets_sent / packages_sent) if packages_sent > 0 else 0, # TODO: Fix later, find a better soln,,, - ((stats["df"]["control_packets_sent"].sum() + control_packets_sent) / total_pkgs_sent_cum) if total_pkgs_sent_cum > 0 else 0 + (((stats["df"]["control_packets_sent"].sum() + control_packets_sent) / total_pkgs_sent_cum) if total_pkgs_sent_cum > 0 else 0) * 100 ] # stats["dead_nodes"].append(num_dead_nodes) @@ -148,11 +148,11 @@ def run_dijkstra_scholten_simulation(args): axes[1][1].cla() sns.lineplot(data=stats["df"]["active_nodes"], ax=axes[0][0], color="orange") - sns.lineplot(data=stats["df"]["dead_nodes"], ax=axes[1][0], color="blue") + sns.lineplot(data=stats["df"]["dead_nodes"], ax=axes[0][0], color="blue") sns.lineplot(data=stats["df"]["packets_in_transmit"], ax=axes[0][1], color="purple") sns.lineplot(data=stats["df"]["control_packets_sent"], ax=axes[0][1], color="green") + sns.lineplot(data=stats["df"]["control_total_cumulative_ratio"], ax=axes[1][0], color="mediumslateblue") sns.lineplot(data=stats["df"]["control_basic_instant_ratio"], ax=axes[1][1], color="red") - sns.lineplot(data=stats["df"]["control_total_cumulative_ratio"], ax=axes[1][1], color="mediumslateblue") # sns.lineplot(data=stats["active_nodes"], ax=axes, color="red") # sns.lineplot(data=stats["dead_nodes"], ax=axes, color="mediumslateblue") # sns.lineplot(data=stats["packages_in_transmit"], ax=axes, color="green") -- GitLab From 87a91c427e58880dbfe7ef7010569e388171f04e Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sat, 22 May 2021 16:12:11 +0300 Subject: [PATCH 19/47] better better plotting with nx --- dijkstra_scholten.py | 6 +++++- simulator.py | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/dijkstra_scholten.py b/dijkstra_scholten.py index 871656e..533b3ce 100644 --- a/dijkstra_scholten.py +++ b/dijkstra_scholten.py @@ -304,4 +304,8 @@ class DijkstraScholtenAdHocNode(ComponentModel): if self.appllayer.simulation_state == DSAHCNodeSimulationStatus.OUT_OF_CLOCK or self.appllayer.simulation_state == DSAHCNodeSimulationStatus.OUT_OF_TREE: return 0 - return self.appllayer.basic_message_queue.qsize() \ No newline at end of file + return self.appllayer.basic_message_queue.qsize() + + @property + def parent_node(self): + return self.appllayer._parent_node \ No newline at end of file diff --git a/simulator.py b/simulator.py index 87f8270..b799a36 100644 --- a/simulator.py +++ b/simulator.py @@ -5,8 +5,10 @@ import pickle import random import pandas as pd import seaborn as sns +import networkx as nx import matplotlib.pyplot as plt from datetime import datetime as dt +from networkx.drawing.nx_pydot import graphviz_layout from Ahc import Topology from graph import ERG, Grid, Star @@ -76,9 +78,9 @@ def run_dijkstra_scholten_simulation(args): "announced_on_tick": None } - fig, axes = plt.subplots(2, 2) - fig.set_figwidth(8) - fig.set_figheight(8) + fig, axes = plt.subplots(2, 3) + fig.set_figwidth(25) + fig.set_figheight(10) # fig.tight_layout() input("\n>>> Proceed ?") @@ -94,9 +96,20 @@ def run_dijkstra_scholten_simulation(args): break_this_tick = False control_packets_sent = 0 + T = nx.Graph() + for index, node in topo.nodes.items(): new_state, pkg_sent_to_friend, cps = node.simulation_tick() + if index not in T.nodes(): + T.add_node(index) + + if node.parent_node is not None: + if node.parent_node not in T.nodes(): + T.add_node(node.parent_node) + + T.add_edge(index, node.parent_node) + if index == N.root and new_state is None: break_this_tick = True @@ -144,8 +157,10 @@ def run_dijkstra_scholten_simulation(args): axes[0][0].cla() axes[0][1].cla() + axes[0][2].cla() axes[1][0].cla() axes[1][1].cla() + axes[1][2].cla() sns.lineplot(data=stats["df"]["active_nodes"], ax=axes[0][0], color="orange") sns.lineplot(data=stats["df"]["dead_nodes"], ax=axes[0][0], color="blue") @@ -156,6 +171,19 @@ def run_dijkstra_scholten_simulation(args): # sns.lineplot(data=stats["active_nodes"], ax=axes, color="red") # sns.lineplot(data=stats["dead_nodes"], ax=axes, color="mediumslateblue") # sns.lineplot(data=stats["packages_in_transmit"], ax=axes, color="green") + + # pos = nx.spring_layout(T) + # nx.draw_networkx_nodes(T , pos, nodelist=[N.root], node_color='red', ax=axes[0][2]) + # nx.draw_networkx_nodes(T , pos, nodelist=[i for i in T.nodes() if i != N.root], node_color='mediumslateblue', ax=axes[0][2]) + # nx.draw_networkx_edges(T , pos, ax=axes[0][2]) + + # pos = graphviz_layout(T, prog="twopi") + # nx.draw(T, ax=axes[0][2], pos=pos) + + node_color = ["red" if list(T.nodes)[i] == N.root else ("mediumslateblue" if list(T.nodes)[i] not in alive_nodes else "green") for i in range(total_nodes)] + nx.draw(T, ax=axes[0][2], with_labels=True, node_color=node_color) + nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color) + plt.pause(0.0005) time.sleep(args.ms_per_tick / 1000) except KeyboardInterrupt: -- GitLab From 4f35e5ba5ea2704f9f1501f8063d2390e1c6f6f5 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sat, 22 May 2021 17:31:25 +0300 Subject: [PATCH 20/47] SUPER SEXY GRIDS!!! --- cli.py | 1 + dijkstra_scholten.py | 7 +++++-- simulator.py | 31 ++++++++++++++++++++++++++++--- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/cli.py b/cli.py index c20b22f..606e3b6 100644 --- a/cli.py +++ b/cli.py @@ -25,6 +25,7 @@ parser.add_argument("--only_root_alive_initially", action="store_true", default= parser.add_argument("--run_until_termination", action="store_true", default=False) parser.add_argument("--exit_on_termination", action="store_true", default=False) +parser.add_argument("--wait_ticks_after_termination", type=int, default=0) parser.add_argument("--passiveness_death_thresh", type=int, default=20) parser.add_argument("--hard_stop_nodes", action="store_true", default=False) diff --git a/dijkstra_scholten.py b/dijkstra_scholten.py index 533b3ce..a6bb0c7 100644 --- a/dijkstra_scholten.py +++ b/dijkstra_scholten.py @@ -165,10 +165,10 @@ class DijkstraScholtenApplicationLayerComponent(ComponentModel): elif self.__tick_n >= self.simulation_ticks_total: self.exit_tree() next_state = DSAHCNodeSimulationStatus.OUT_OF_TREE - elif self._passive_counter >= self.die_passiveness_threshold: + elif not self._i_am_root and self._passive_counter >= self.die_passiveness_threshold: self.exit_tree() next_state = DSAHCNodeSimulationStatus.OUT_OF_TREE - elif self.__tick_n >= self.hard_stop_on_tick: + elif not self._i_am_root and self.__tick_n >= self.hard_stop_on_tick: self.exit_tree() next_state = DSAHCNodeSimulationStatus.OUT_OF_TREE print(f" ==> N-{self.componentinstancenumber}: HARD STOP") @@ -249,6 +249,9 @@ class DijkstraScholtenApplicationLayerComponent(ComponentModel): # P2P: packages to process # print(f" {'ROOT' if self._i_am_root else '==>'} N-{self.componentinstancenumber}: P: {self._parent_node}, CC: ({self._child_counter}) {self._children}, ST: {self.simulation_state}, NS: {next_state}, GPF: {got_packages_from}, SPF: {to_friend}, ANT: {self.alive_for_next_ticks}, P2P: {self.basic_message_queue.qsize()}") + if self._i_am_root: + print(f" {'ROOT' if self._i_am_root else '==>'} N-{self.componentinstancenumber}: P: {self._parent_node}, CC: ({self._child_counter}) {self._children}, ST: {self.simulation_state}, NS: {next_state}, GPF: {got_packages_from}, SPF: {to_friend}, ANT: {self.alive_for_next_ticks}, P2P: {self.basic_message_queue.qsize()}") + # time.sleep(self.sleep_ms_per_tick / 1000) self.__tick_n += 1 self.simulation_state = next_state diff --git a/simulator.py b/simulator.py index b799a36..aaf8d47 100644 --- a/simulator.py +++ b/simulator.py @@ -85,6 +85,8 @@ def run_dijkstra_scholten_simulation(args): input("\n>>> Proceed ?") + term_wait_ctr = 0 + try: for t in range(1, args.simulation_ticks + 1): print(f"[S] Tick: {t}") @@ -97,10 +99,20 @@ def run_dijkstra_scholten_simulation(args): control_packets_sent = 0 T = nx.Graph() + node_color = [] for index, node in topo.nodes.items(): new_state, pkg_sent_to_friend, cps = node.simulation_tick() + if N.root == index: + node_color.append("red") + elif new_state == DSAHCNodeSimulationStatus.ACTIVE: + node_color.append("green") + elif new_state == DSAHCNodeSimulationStatus.PASSIVE: + node_color.append("mediumslateblue") + elif new_state == DSAHCNodeSimulationStatus.OUT_OF_TREE: + node_color.append("gray") + if index not in T.nodes(): T.add_node(index) @@ -144,9 +156,17 @@ def run_dijkstra_scholten_simulation(args): print(f" (ACTIVE: {num_nodes_active}, PKGS-WAIT: {packages_waiting_on_queue}, PKGS-SENT: {packages_sent})") if (packages_waiting_on_queue == 0 and num_nodes_active == 0 and packages_sent == 0): - stats["terminated_on_tick"] = t + if stats["terminated_on_tick"] is None: + stats["terminated_on_tick"] = t + print("!!! TERMINATED !!!") + term_wait_ctr += 1 + + if args.wait_ticks_after_termination > 0 and term_wait_ctr > args.wait_ticks_after_termination: + print("!!! FORCE TERMINATED !!!") + break + if args.exit_on_termination: break @@ -180,9 +200,14 @@ def run_dijkstra_scholten_simulation(args): # pos = graphviz_layout(T, prog="twopi") # nx.draw(T, ax=axes[0][2], pos=pos) - node_color = ["red" if list(T.nodes)[i] == N.root else ("mediumslateblue" if list(T.nodes)[i] not in alive_nodes else "green") for i in range(total_nodes)] + # node_color = ["red" if list(T.nodes)[i] == N.root else ("mediumslateblue" if list(T.nodes)[i] not in alive_nodes else "green") for i in range(total_nodes)] nx.draw(T, ax=axes[0][2], with_labels=True, node_color=node_color) - nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color) + + if args.network_type == "grid": + pos = {i: (i // args.node_count_on_edge, i % args.node_count_on_edge) for i in range(total_nodes)} + nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color, pos=pos) + else: + nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color) plt.pause(0.0005) time.sleep(args.ms_per_tick / 1000) -- GitLab From 47be6f55186cf5d5658026024f7058ca2b7bcd28 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sat, 22 May 2021 22:35:41 +0300 Subject: [PATCH 21/47] updated .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c55099c..a458dee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Custom .DS_Store simdump/ +simdump_dev/ # Byte-compiled / optimized / DLL files -- GitLab From 02a87c7dc94728a3fdfea9baa950cf5ec7703ea8 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sat, 22 May 2021 22:36:06 +0300 Subject: [PATCH 22/47] --no_realtime_plot --- cli.py | 2 + simulator.py | 157 ++++++++++++++++++++++++++++++++------------------- 2 files changed, 100 insertions(+), 59 deletions(-) diff --git a/cli.py b/cli.py index 606e3b6..b84acdb 100644 --- a/cli.py +++ b/cli.py @@ -33,6 +33,8 @@ parser.add_argument("--hard_stop_min_tick", type=int, default=50) parser.add_argument("--hard_stop_max_tick", type=int, default=300) parser.add_argument("--hard_stop_prob", type=float, default=0.5) +parser.add_argument("--no_realtime_plot", action="store_true", default=False) + sp = parser.add_subparsers() erg_parser = sp.add_parser("erg") diff --git a/simulator.py b/simulator.py index aaf8d47..3c61f25 100644 --- a/simulator.py +++ b/simulator.py @@ -3,6 +3,7 @@ import sys import time import pickle import random +from typing import Text import pandas as pd import seaborn as sns import networkx as nx @@ -78,14 +79,18 @@ def run_dijkstra_scholten_simulation(args): "announced_on_tick": None } - fig, axes = plt.subplots(2, 3) - fig.set_figwidth(25) - fig.set_figheight(10) - # fig.tight_layout() + graphs = [] + + if not args.no_realtime_plot: + fig, axes = plt.subplots(2, 3) + fig.set_figwidth(25) + fig.set_figheight(10) + # fig.tight_layout() input("\n>>> Proceed ?") term_wait_ctr = 0 + reason = None try: for t in range(1, args.simulation_ticks + 1): @@ -123,6 +128,7 @@ def run_dijkstra_scholten_simulation(args): T.add_edge(index, node.parent_node) if index == N.root and new_state is None: + reason = f"root terminated ({t})" break_this_tick = True if new_state == DSAHCNodeSimulationStatus.ACTIVE: @@ -134,9 +140,27 @@ def run_dijkstra_scholten_simulation(args): packages_sent += 1 control_packets_sent += cps - packages_waiting_on_queue += node.waiting_packages_on_queue + print(f" (ACTIVE: {num_nodes_active}, PKGS-WAIT: {packages_waiting_on_queue}, PKGS-SENT: {packages_sent})") + + if (packages_waiting_on_queue == 0 and num_nodes_active == 0 and packages_sent == 0): + if not args.no_realtime_plot: + if stats["terminated_on_tick"] is None: + stats["terminated_on_tick"] = t + + print("!!! TERMINATED !!!") + + term_wait_ctr += 1 + + if args.wait_ticks_after_termination > 0 and term_wait_ctr > args.wait_ticks_after_termination: + print("!!! FORCE TERMINATED !!!") + reason = f"forced ({args.wait_ticks_after_termination})" + break_this_tick = True + + if args.exit_on_termination: + break_this_tick = True + total_pkgs_sent_cum = (stats["df"]["control_packets_sent"].sum() + control_packets_sent + stats["df"]["packets_in_transmit"].sum() + packages_sent) stats["df"].loc[t-1] = [ @@ -152,64 +176,53 @@ def run_dijkstra_scholten_simulation(args): # stats["dead_nodes"].append(num_dead_nodes) # stats["active_nodes"].append(num_nodes_active) # stats["packages_in_transmit"].append(packages_sent) + graphs.append({ + "edges": T.edges(), + "nodes": T.nodes(), + }) - print(f" (ACTIVE: {num_nodes_active}, PKGS-WAIT: {packages_waiting_on_queue}, PKGS-SENT: {packages_sent})") - - if (packages_waiting_on_queue == 0 and num_nodes_active == 0 and packages_sent == 0): - if stats["terminated_on_tick"] is None: - stats["terminated_on_tick"] = t - - print("!!! TERMINATED !!!") - - term_wait_ctr += 1 + # axes.scatter(x=t, y=num_nodes_active) + + if not args.no_realtime_plot: + axes[0][0].cla() + axes[0][1].cla() + axes[0][2].cla() + axes[1][0].cla() + axes[1][1].cla() + axes[1][2].cla() + + sns.lineplot(data=stats["df"]["active_nodes"], ax=axes[0][0], color="orange") + sns.lineplot(data=stats["df"]["dead_nodes"], ax=axes[0][0], color="blue") + sns.lineplot(data=stats["df"]["packets_in_transmit"], ax=axes[0][1], color="purple") + sns.lineplot(data=stats["df"]["control_packets_sent"], ax=axes[0][1], color="green") + sns.lineplot(data=stats["df"]["control_total_cumulative_ratio"], ax=axes[1][0], color="mediumslateblue") + sns.lineplot(data=stats["df"]["control_basic_instant_ratio"], ax=axes[1][1], color="red") + # sns.lineplot(data=stats["active_nodes"], ax=axes, color="red") + # sns.lineplot(data=stats["dead_nodes"], ax=axes, color="mediumslateblue") + # sns.lineplot(data=stats["packages_in_transmit"], ax=axes, color="green") + + # pos = nx.spring_layout(T) + # nx.draw_networkx_nodes(T , pos, nodelist=[N.root], node_color='red', ax=axes[0][2]) + # nx.draw_networkx_nodes(T , pos, nodelist=[i for i in T.nodes() if i != N.root], node_color='mediumslateblue', ax=axes[0][2]) + # nx.draw_networkx_edges(T , pos, ax=axes[0][2]) + + # pos = graphviz_layout(T, prog="twopi") + # nx.draw(T, ax=axes[0][2], pos=pos) + + # node_color = ["red" if list(T.nodes)[i] == N.root else ("mediumslateblue" if list(T.nodes)[i] not in alive_nodes else "green") for i in range(total_nodes)] + nx.draw(T, ax=axes[0][2], with_labels=True, node_color=node_color) + + if args.network_type == "grid": + pos = {i: (i // args.node_count_on_edge, i % args.node_count_on_edge) for i in range(total_nodes)} + nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color, pos=pos) + else: + nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color) - if args.wait_ticks_after_termination > 0 and term_wait_ctr > args.wait_ticks_after_termination: - print("!!! FORCE TERMINATED !!!") - break - - if args.exit_on_termination: - break + plt.pause(0.0005) if break_this_tick: break - # axes.scatter(x=t, y=num_nodes_active) - - axes[0][0].cla() - axes[0][1].cla() - axes[0][2].cla() - axes[1][0].cla() - axes[1][1].cla() - axes[1][2].cla() - - sns.lineplot(data=stats["df"]["active_nodes"], ax=axes[0][0], color="orange") - sns.lineplot(data=stats["df"]["dead_nodes"], ax=axes[0][0], color="blue") - sns.lineplot(data=stats["df"]["packets_in_transmit"], ax=axes[0][1], color="purple") - sns.lineplot(data=stats["df"]["control_packets_sent"], ax=axes[0][1], color="green") - sns.lineplot(data=stats["df"]["control_total_cumulative_ratio"], ax=axes[1][0], color="mediumslateblue") - sns.lineplot(data=stats["df"]["control_basic_instant_ratio"], ax=axes[1][1], color="red") - # sns.lineplot(data=stats["active_nodes"], ax=axes, color="red") - # sns.lineplot(data=stats["dead_nodes"], ax=axes, color="mediumslateblue") - # sns.lineplot(data=stats["packages_in_transmit"], ax=axes, color="green") - - # pos = nx.spring_layout(T) - # nx.draw_networkx_nodes(T , pos, nodelist=[N.root], node_color='red', ax=axes[0][2]) - # nx.draw_networkx_nodes(T , pos, nodelist=[i for i in T.nodes() if i != N.root], node_color='mediumslateblue', ax=axes[0][2]) - # nx.draw_networkx_edges(T , pos, ax=axes[0][2]) - - # pos = graphviz_layout(T, prog="twopi") - # nx.draw(T, ax=axes[0][2], pos=pos) - - # node_color = ["red" if list(T.nodes)[i] == N.root else ("mediumslateblue" if list(T.nodes)[i] not in alive_nodes else "green") for i in range(total_nodes)] - nx.draw(T, ax=axes[0][2], with_labels=True, node_color=node_color) - - if args.network_type == "grid": - pos = {i: (i // args.node_count_on_edge, i % args.node_count_on_edge) for i in range(total_nodes)} - nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color, pos=pos) - else: - nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color) - - plt.pause(0.0005) time.sleep(args.ms_per_tick / 1000) except KeyboardInterrupt: pass @@ -222,16 +235,42 @@ def run_dijkstra_scholten_simulation(args): #plt.plot(stats["packages_in_transmit"]) + axes[0][0].cla() + axes[0][1].cla() + axes[0][2].cla() + axes[1][0].cla() + axes[1][1].cla() + axes[1][2].cla() + + sns.lineplot(data=stats["df"]["active_nodes"], ax=axes[0][0], color="orange") + sns.lineplot(data=stats["df"]["dead_nodes"], ax=axes[0][0], color="blue") + sns.lineplot(data=stats["df"]["packets_in_transmit"], ax=axes[0][1], color="purple") + sns.lineplot(data=stats["df"]["control_packets_sent"], ax=axes[0][1], color="green") + sns.lineplot(data=stats["df"]["control_total_cumulative_ratio"], ax=axes[1][0], color="mediumslateblue") + sns.lineplot(data=stats["df"]["control_basic_instant_ratio"], ax=axes[1][1], color="red") + + nx.draw(T, ax=axes[0][2], with_labels=True, node_color=node_color) + + if args.network_type == "grid": + pos = {i: (i // args.node_count_on_edge, i % args.node_count_on_edge) for i in range(total_nodes)} + nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color, pos=pos) + else: + nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color) + plt.savefig(f"simdump/stats_{args.network_type}_{total_nodes}_{ts}.png", dpi=200) with open(f"simdump/run_{args.network_type}_{total_nodes}_{ts}.pkl", "wb") as fp: pickle.dump({ "args": args, "context": topo_context, - "stats": stats + "stats": stats, + "graphs": graphs }, fp) - plt.show() + if not args.no_realtime_plot: + plt.show() + + print(f"\n{reason}") def run_shavit_francez_simulation(args): raise NotImplementedError() \ No newline at end of file -- GitLab From 45e40b35e57aeb76bdd3b070da7b15ef2f589e04 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sun, 23 May 2021 09:30:27 +0300 Subject: [PATCH 23/47] updated ds_run.sh --- ds_run.sh | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100755 ds_run.sh diff --git a/ds_run.sh b/ds_run.sh new file mode 100755 index 0000000..ce7549b --- /dev/null +++ b/ds_run.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +set -e + +run_sim() { + python3 ../cli.py djikstra-scholten 100 100 --run_until_termination --passiveness_death_thresh 3000 --hard_stop_nodes --hard_stop_min_tick 50 --hard_stop_max_tick 250 --node_package_process_per_tick 3 --node_initial_activeness_prob .5 --node_activeness_communication_prob .8 --wait_ticks_after_termination 50 --only_root_alive_initially --no_realtime_plot "${1}" "${2}" > "${1}_${2}_run-${3}.out" <<< "\n" +} + +for i in {1..10}; do + run_sim "grid" "3" "${i}" + run_sim "grid" "4" "${i}" + run_sim "grid" "5" "${i}" + run_sim "grid" "6" "${i}" + run_sim "grid" "7" "${i}" + run_sim "grid" "8" "${i}" + run_sim "grid" "9" "${i}" + run_sim "grid" "10" "${i}" +done + +for i in {1..10}; do + run_sim "star" "4" "${i}" + run_sim "star" "9" "${i}" + run_sim "star" "19" "${i}" + run_sim "star" "29" "${i}" + run_sim "star" "39" "${i}" + run_sim "star" "49" "${i}" + run_sim "star" "59" "${i}" +done + +for i in {1..10}; do + run_sim "erg" "5" "${i}" + run_sim "erg" "10" "${i}" + run_sim "erg" "15" "${i}" + run_sim "erg" "20" "${i}" + run_sim "erg" "25" "${i}" + run_sim "erg" "30" "${i}" + run_sim "erg" "35" "${i}" + run_sim "erg" "40" "${i}" + run_sim "erg" "45" "${i}" + run_sim "erg" "50" "${i}" +done \ No newline at end of file -- GitLab From c43dd83c0b4e6887fd0c79ffb538fd42a549e662 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sun, 23 May 2021 09:30:36 +0300 Subject: [PATCH 24/47] updated dijkstra_scholten.py --- dijkstra_scholten.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/dijkstra_scholten.py b/dijkstra_scholten.py index a6bb0c7..c06ddc4 100644 --- a/dijkstra_scholten.py +++ b/dijkstra_scholten.py @@ -126,6 +126,9 @@ class DijkstraScholtenApplicationLayerComponent(ComponentModel): self._parent_node = hdr.messagefrom self._in_tree = True + if self.componentinstancenumber not in self.context["alive_nodes"]: + self.context["alive_nodes"].append(self.componentinstancenumber) + elif hdr.messagetype == ApplicationLayerMessageType.CONTROL: # self.control_message_queue.put_nowait(applmessage) @@ -139,11 +142,14 @@ class DijkstraScholtenApplicationLayerComponent(ComponentModel): def exit_tree(self): # Exit from the tree if self._in_tree: - self.send_ack_control_message(self._parent_node, True) self._in_tree = False - self._parent_node = None + if self._parent_node is not None: + self.send_ack_control_message(self._parent_node, True) + + self._parent_node = None - self.context["alive_nodes"].remove(self.componentinstancenumber) + if self.componentinstancenumber in self.context["alive_nodes"]: + self.context["alive_nodes"].remove(self.componentinstancenumber) def simulation_tick(self): next_state = None @@ -161,17 +167,20 @@ class DijkstraScholtenApplicationLayerComponent(ComponentModel): if self.simulation_state == DSAHCNodeSimulationStatus.OUT_OF_TREE: next_state = DSAHCNodeSimulationStatus.OUT_OF_TREE - # print(f" ==> N-{self.componentinstancenumber}: OUT OF TREE") + # print(f" ==> N-{self.componentinstancenumber}: OOT") #NOTE: DEV + # print(f" ==> N-{self.componentinstancenumber}: OUT OF TREE") elif self.__tick_n >= self.simulation_ticks_total: self.exit_tree() next_state = DSAHCNodeSimulationStatus.OUT_OF_TREE + # print(f" ==> N-{self.componentinstancenumber}: OOC DEAD") #NOTE: DEV elif not self._i_am_root and self._passive_counter >= self.die_passiveness_threshold: self.exit_tree() next_state = DSAHCNodeSimulationStatus.OUT_OF_TREE + # print(f" ==> N-{self.componentinstancenumber}: PASSIVE DIE") #NOTE: DEV elif not self._i_am_root and self.__tick_n >= self.hard_stop_on_tick: self.exit_tree() next_state = DSAHCNodeSimulationStatus.OUT_OF_TREE - print(f" ==> N-{self.componentinstancenumber}: HARD STOP") + # print(f" ==> N-{self.componentinstancenumber}: HARD STOP") #NOTE: DEV else: if self.simulation_state == DSAHCNodeSimulationStatus.OUT_OF_CLOCK: next_state = DSAHCNodeSimulationStatus.OUT_OF_CLOCK @@ -185,8 +194,8 @@ class DijkstraScholtenApplicationLayerComponent(ComponentModel): return None, None, __cms else: self.exit_tree() - next_state = DSAHCNodeSimulationStatus.OUT_OF_TREE - print(f" ==> N-{self.componentinstancenumber}: OUT OF TREE") + next_state = DSAHCNodeSimulationStatus.PASSIVE + print(f" ==> N-{self.componentinstancenumber}: OUT OF TREE / PASSIVE") else: # no incoming package, still passive. next_state = DSAHCNodeSimulationStatus.PASSIVE -- GitLab From 618d94da7a5d9acd4206a6eefec6b01163319726 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sun, 23 May 2021 09:30:52 +0300 Subject: [PATCH 25/47] updated simulator.py --- simulator.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/simulator.py b/simulator.py index 3c61f25..203f4bb 100644 --- a/simulator.py +++ b/simulator.py @@ -81,11 +81,10 @@ def run_dijkstra_scholten_simulation(args): graphs = [] - if not args.no_realtime_plot: - fig, axes = plt.subplots(2, 3) - fig.set_figwidth(25) - fig.set_figheight(10) - # fig.tight_layout() + fig, axes = plt.subplots(2, 3) + fig.set_figwidth(25) + fig.set_figheight(10) + # fig.tight_layout() input("\n>>> Proceed ?") -- GitLab From a425ba22749536c1e0344361cf8396b8d25cb277 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sun, 23 May 2021 10:16:59 +0300 Subject: [PATCH 26/47] SF components impl --- shavit_francez.py | 398 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 398 insertions(+) create mode 100644 shavit_francez.py diff --git a/shavit_francez.py b/shavit_francez.py new file mode 100644 index 0000000..bf42e23 --- /dev/null +++ b/shavit_francez.py @@ -0,0 +1,398 @@ +import os +import queue +import sys +import time +import json +import queue +import random +import networkx as nx +from enum import Enum +import matplotlib.pyplot as plt +from datetime import datetime as dt + +from Channels import P2PFIFOPerfectChannel +from LinkLayers.GenericLinkLayer import LinkLayer +from NetworkLayers.AllSeeingEyeNetworkLayer import AllSeingEyeNetworkLayer +from Ahc import (ComponentModel, Event, ConnectorTypes, Topology, + ComponentRegistry, GenericMessagePayload, GenericMessageHeader, + GenericMessage, EventTypes) + +registry = ComponentRegistry() + +# define your own message types +class ApplicationLayerMessageType(Enum): + BASIC = "basic" + CONTROL = "control" # NOTE: Means the acknowledgement message! + WAVE = "wave" + +class SFWaveMessageType(Enum): + REQUEST = "req" + RESPONSE = "resp" + + def __str__(self): + return self.name + +class SFWaveResponse(Enum): + FINISHED = "fin" + ACTIVE = "act" + + def __str__(self): + return self.name + +class SFWaveMessagePayload: + tag: int + type: SFWaveMessageType + response: SFWaveResponse + + def __init__(self, tag: int, typ: SFWaveMessageType, resp: SFWaveResponse = None) -> None: + self.tag = tag + self.response = resp + self.type = typ + +class SFAHCNodeSimulationStatus(Enum): + ACTIVE = "active" + PASSIVE = "passive" + OUT_OF_CLOCK = "ooc" + OUT_OF_TREE = "oot" + + def __str__(self): + return self.name + +# define your own message header structure +class ApplicationLayerMessageHeader(GenericMessageHeader): + pass + +# define your own message payload structure +class ApplicationLayerMessagePayload(GenericMessagePayload): + pass + +class ShavitFrancezApplicationLayerComponent(ComponentModel): + def __init__(self, componentname, componentinstancenumber, context): + super().__init__(componentname, componentinstancenumber, context=context) + + self.context = context + # self.eventhandlers[ApplicationLayerMessageType.BASIC] = self.on_basic_message + # self.eventhandlers[ApplicationLayerMessageType.CONTROL] = self.on_control_message + + self.basic_message_queue = queue.Queue(maxsize=-1) + self.control_message_queue = queue.Queue(maxsize=-1) + self.simulation_state = SFAHCNodeSimulationStatus.PASSIVE + + self.sleep_ms_per_tick = context["ms_per_tick"] + self.simulation_ticks_total = context["simulation_ticks"] + self.alive_for_next_ticks = context["initial_liveness"][componentinstancenumber] + self.communication_on_active_prob = context["communication_on_active_prob"] + self.min_activeness_after_receive = context["min_activeness_after_receive"] + self.max_activeness_after_receive = context["max_activeness_after_receive"] + self.package_process_per_tick = context["node_package_process_per_tick"] + self.die_passiveness_threshold = context["passiveness_death_thresh"] + + if context["hard_stop_on_tick"] is None: + self.hard_stop_on_tick = None + else: + self.hard_stop_on_tick = context["hard_stop_on_tick"][self.componentinstancenumber] + + self.__tick_n = 0 + self._passive_counter = 0 + + self._child_counter = 0 + self._parent_node = None + self._in_tree = False + self._children = [] + + self._cms = 0 # control messages sent + self._wms = 0 # wave messages sent + + self._i_am_root = context["network"].root == self.componentinstancenumber + + if context["only_root_alive_initially"]: + if self._i_am_root: + self.alive_for_next_ticks = 20 # this may change though... + self._in_tree = True + else: + self.alive_for_next_ticks = 0 + elif self._i_am_root and self.alive_for_next_ticks == 0: + self.alive_for_next_ticks = 20 # this may change though... + + if self.alive_for_next_ticks > 0: + self.simulation_state = SFAHCNodeSimulationStatus.ACTIVE + + self.__exited_from_tree = False + self.my_wave_bucket = [] + self.announce_on_next_tick = False + + def prepare_application_layer_message(self, message_type: ApplicationLayerMessageType, destination_node_id: int, payload: object) -> GenericMessage: + hdr = ApplicationLayerMessageHeader(message_type, self.componentinstancenumber, destination_node_id) + payload = ApplicationLayerMessagePayload(payload) + + return GenericMessage(hdr, payload) + + def send_random_basic_message(self, to: int) -> None: + self._child_counter += 1 + self._children.append(to) + self.send_down(Event(self, EventTypes.MFRT, self.prepare_application_layer_message(ApplicationLayerMessageType.BASIC, to, str(dt.now().timestamp())))) + + def send_ack_control_message(self, to: int, is_dead: bool) -> None: + # print(f"send_ack_control_message: N-{self.componentinstancenumber} ==> N-{to} ({self._parent_node}) : {'DEAD' if is_dead else 'PKG_RESP'}") + self.send_down(Event(self, EventTypes.MFRT, self.prepare_application_layer_message(ApplicationLayerMessageType.CONTROL, to, str(dt.now().timestamp())))) + self._cms += 1 + + def on_init(self, eventobj: Event): + # print(f"Initializing {self.componentname}.{self.componentinstancenumber}") + pass + + def on_message_from_bottom(self, eventobj: Event): + applmessage = eventobj.eventcontent + hdr = applmessage.header + + # print(f"Node-{self.componentinstancenumber}: Node-{hdr.messagefrom} has sent {hdr.messagetype} message (payload: {applmessage.payload})") + + if hdr.messagetype == ApplicationLayerMessageType.BASIC: + self.basic_message_queue.put_nowait(applmessage) + + if self._in_tree: + self.send_ack_control_message(hdr.messagefrom, False) + else: + self._parent_node = hdr.messagefrom + self._in_tree = True + + if self.componentinstancenumber not in self.context["alive_nodes"]: + self.context["alive_nodes"].append(self.componentinstancenumber) + elif hdr.messagetype == ApplicationLayerMessageType.CONTROL: + # self.control_message_queue.put_nowait(applmessage) + + try: + self._children.remove(hdr.messagefrom) + self._child_counter -= 1 + except ValueError as e: + # print(f"\n\n\n{self.componentinstancenumber}: {e} {hdr.messagefrom} {self._children}\n\n\n") + pass + elif hdr.messagetype == ApplicationLayerMessageType.WAVE: + if applmessage.payload.tag == self.componentinstancenumber: + self.my_wave_bucket.append(applmessage.payload.response) + + print(f" WAVE << N-{self.componentinstancenumber} << N-{hdr.messagefrom} ({applmessage.payload.response})") + + if len(self.my_wave_bucket) == (self.context["network"].G.nodes() - 1): + print(f" ::: WAVE END >> N-{self.componentinstancenumber}: {self.my_wave_bucket}") + + if SFWaveResponse.ACTIVE not in self.my_wave_bucket: + print(f" ::: WAVE END >> N-{self.componentinstancenumber}: ANNOUNCE!") + self.announce_on_next_tick = True + else: + print(f" ::: WAVE END >> N-{self.componentinstancenumber}: NOT DONE YET!") + self.my_wave_bucket = [] + else: + if self.__exited_from_tree: + self.send_down(Event(self, EventTypes.MFRT, self.prepare_application_layer_message(ApplicationLayerMessageType.WAVE, applmessage.payload.tag, SFWaveMessagePayload(applmessage.payload.tag, SFWaveMessageType.RESPONSE, SFWaveResponse.FINISHED)))) + print(f" WAVE >> N-{self.componentinstancenumber} >> N-{applmessage.payload.tag} >> FINISHED") + else: + self.send_down(Event(self, EventTypes.MFRT, self.prepare_application_layer_message(ApplicationLayerMessageType.WAVE, applmessage.payload.tag, SFWaveMessagePayload(applmessage.payload.tag, SFWaveMessageType.RESPONSE, SFWaveResponse.ACTIVE)))) + print(f" WAVE >> N-{self.componentinstancenumber} >> N-{applmessage.payload.tag} >> ACTIVE") + + self._wms += 1 + else: + print(f"\n!!! N-{self.componentinstancenumber}: GOT MSG UNIDENT: {hdr.messagetype}, FROM {hdr.messagefrom}") + sys.exit(2) + + def call_wave(self): + print(f" > CALL WAVE @@ N-{self.componentinstancenumber}") + + to_nodes = [i for i in range(self.context["network"].G.nodes()) if i != self.componentinstancenumber] + + for to in to_nodes: + self.send_down(Event(self, EventTypes.MFRT, self.prepare_application_layer_message(ApplicationLayerMessageType.WAVE, to, SFWaveMessagePayload(self.componentinstancenumber, SFWaveMessageType.REQUEST)))) + self._wms += 1 + + def exit_tree(self): + # Exit from the tree + + if not self.__exited_from_tree: + if self._in_tree: + self._in_tree = False + if self._parent_node is not None: + self.send_ack_control_message(self._parent_node, True) + + self._parent_node = None + + if self.componentinstancenumber in self.context["alive_nodes"]: + self.context["alive_nodes"].remove(self.componentinstancenumber) + + print(f" > EXIT @@ N-{self.componentinstancenumber}") + + self.call_wave() + + def simulation_tick(self): + next_state = None + got_packages_from = None + to_friend = None + + _upd_children = [] + + for c in self._children: + if c in self.context["alive_nodes"]: + _upd_children.append(c) + + self._children = _upd_children + self._child_counter = len(self._children) + + if self.announce_on_next_tick: + __cms = self._cms + __wms = self._wms + self._cms = 0 + self._wms = 0 + + return None, None, __cms, __wms + + if self.simulation_state == SFAHCNodeSimulationStatus.OUT_OF_TREE: + next_state = SFAHCNodeSimulationStatus.OUT_OF_TREE + # print(f" ==> N-{self.componentinstancenumber}: OOT") #NOTE: DEV + # print(f" ==> N-{self.componentinstancenumber}: OUT OF TREE") + elif self.__tick_n >= self.simulation_ticks_total: + self.exit_tree() + next_state = SFAHCNodeSimulationStatus.OUT_OF_TREE + # print(f" ==> N-{self.componentinstancenumber}: OOC DEAD") #NOTE: DEV + elif self._passive_counter >= self.die_passiveness_threshold: # NOTE: initiator can also die from passiveness in Shavit-Francez. + self.exit_tree() + next_state = SFAHCNodeSimulationStatus.OUT_OF_TREE + # print(f" ==> N-{self.componentinstancenumber}: PASSIVE DIE") #NOTE: DEV + elif self.__tick_n >= self.hard_stop_on_tick: # NOTE: initiator can also hard stop in Shavit-Francez. + self.exit_tree() + next_state = SFAHCNodeSimulationStatus.OUT_OF_TREE + # print(f" ==> N-{self.componentinstancenumber}: HARD STOP") #NOTE: DEV + else: + if self.simulation_state == SFAHCNodeSimulationStatus.OUT_OF_CLOCK: + next_state = SFAHCNodeSimulationStatus.OUT_OF_CLOCK + elif self.simulation_state == SFAHCNodeSimulationStatus.PASSIVE: + if self.basic_message_queue.empty(): + if self._in_tree and self._child_counter == 0: + self.exit_tree() + next_state = SFAHCNodeSimulationStatus.PASSIVE + print(f" ==> N-{self.componentinstancenumber}: OUT OF TREE / PASSIVE") + else: + # no incoming package, still passive. + next_state = SFAHCNodeSimulationStatus.PASSIVE + else: + got_packages_from = [] + + for _ in range(self.package_process_per_tick): + try: + package = self.basic_message_queue.get_nowait() + # print(f"+P+ N-{self.componentinstancenumber} <==BASIC== N-{package.header.messagefrom} ({package.payload.messagepayload})") + got_packages_from.append(package.header.messagefrom) + except queue.Empty: + break + + self.alive_for_next_ticks = random.randint(self.min_activeness_after_receive, self.max_activeness_after_receive) + next_state = SFAHCNodeSimulationStatus.ACTIVE + elif self.simulation_state == SFAHCNodeSimulationStatus.ACTIVE: + got_packages_from = [] + + for _ in range(self.package_process_per_tick): + try: + package = self.basic_message_queue.get_nowait() + # print(f"+A+ N-{self.componentinstancenumber} <==BASIC== N-{package.header.messagefrom} ({package.payload.messagepayload})") + got_packages_from.append(package.header.messagefrom) + except queue.Empty: + break + + if random.random() <= self.communication_on_active_prob: + # send package to a random friend.. + + _alive_ones = [n for n in self.context["alive_nodes"] if n != self.componentinstancenumber] + + if len(_alive_ones) == 0: # everyone is dead!!! + # print(f" **ROOT** N-{self.componentinstancenumber}: Eveyone is dead!!!") + # return None, None # time to go! + to_friend = None + else: + to_friend = random.choice(_alive_ones) + self.send_random_basic_message(to_friend) + + self.alive_for_next_ticks -= 1 + + if self.alive_for_next_ticks == 0: + if len(got_packages_from) > 0: + # got a package, this means immeiate activeness from passive! + next_state = SFAHCNodeSimulationStatus.ACTIVE + self.alive_for_next_ticks = random.randint(self.min_activeness_after_receive, self.max_activeness_after_receive) + else: + next_state = SFAHCNodeSimulationStatus.PASSIVE + else: + next_state = SFAHCNodeSimulationStatus.ACTIVE + + assert next_state is not None + + # ST: state + # NS: next state + # GPF: got packages from + # SPF: sent package to friend + # ANT: alive next ticks + # P2P: packages to process + # print(f" {'ROOT' if self._i_am_root else '==>'} N-{self.componentinstancenumber}: P: {self._parent_node}, CC: ({self._child_counter}) {self._children}, ST: {self.simulation_state}, NS: {next_state}, GPF: {got_packages_from}, SPF: {to_friend}, ANT: {self.alive_for_next_ticks}, P2P: {self.basic_message_queue.qsize()}") + + if self._i_am_root: + print(f" {'INIT' if self._i_am_root else '==>'} N-{self.componentinstancenumber}: P: {self._parent_node}, CC: ({self._child_counter}) {self._children}, ST: {self.simulation_state}, NS: {next_state}, GPF: {got_packages_from}, SPF: {to_friend}, ANT: {self.alive_for_next_ticks}, P2P: {self.basic_message_queue.qsize()}") + + # time.sleep(self.sleep_ms_per_tick / 1000) + self.__tick_n += 1 + self.simulation_state = next_state + + if self.simulation_state == SFAHCNodeSimulationStatus.PASSIVE: + self._passive_counter += 1 + elif self.simulation_state == SFAHCNodeSimulationStatus.ACTIVE: + self._passive_counter = 0 + + __cms = self._cms + __wms = self._wms + self._cms = 0 + self._wms = 0 + + return next_state, to_friend, __cms, __wms + +class ShavitFrancezAdHocNode(ComponentModel): + def __init__(self, componentname, componentid, context): + self.context = context + # SUBCOMPONENTS + self.appllayer = ShavitFrancezApplicationLayerComponent("ApplicationLayer", componentid, context=self.context) + self.netlayer = AllSeingEyeNetworkLayer("NetworkLayer", componentid) + self.linklayer = LinkLayer("LinkLayer", componentid) + # self.failuredetect = GenericFailureDetector("FailureDetector", componentid) + + # CONNECTIONS AMONG SUBCOMPONENTS + self.appllayer.connect_me_to_component(ConnectorTypes.DOWN, self.netlayer) + # self.failuredetect.connectMeToComponent(PortNames.DOWN, self.netlayer) + self.netlayer.connect_me_to_component(ConnectorTypes.UP, self.appllayer) + # self.netlayer.connectMeToComponent(PortNames.UP, self.failuredetect) + self.netlayer.connect_me_to_component(ConnectorTypes.DOWN, self.linklayer) + self.linklayer.connect_me_to_component(ConnectorTypes.UP, self.netlayer) + + # Connect the bottom component to the composite component.... + self.linklayer.connect_me_to_component(ConnectorTypes.DOWN, self) + self.connect_me_to_component(ConnectorTypes.UP, self.linklayer) + + super().__init__(componentname, componentid, context=self.context) + + def on_init(self, eventobj: Event): + # print(f"Initializing {self.componentname}.{self.componentinstancenumber}") + pass + + def on_message_from_top(self, eventobj: Event): + self.send_down(Event(self, EventTypes.MFRT, eventobj.eventcontent)) + + def on_message_from_bottom(self, eventobj: Event): + self.send_up(Event(self, EventTypes.MFRB, eventobj.eventcontent)) + + def simulation_tick(self): + return self.appllayer.simulation_tick() + + @property + def waiting_packages_on_queue(self): + if self.appllayer.simulation_state == SFAHCNodeSimulationStatus.OUT_OF_CLOCK or self.appllayer.simulation_state == SFAHCNodeSimulationStatus.OUT_OF_TREE: + return 0 + + return self.appllayer.basic_message_queue.qsize() + + @property + def parent_node(self): + return self.appllayer._parent_node \ No newline at end of file -- GitLab From 51ee625e3be2413c1e355f29415aeeb528ad955f Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sun, 23 May 2021 10:18:19 +0300 Subject: [PATCH 27/47] simulator separation --- simulator.py => simulator_ds.py | 3 --- 1 file changed, 3 deletions(-) rename simulator.py => simulator_ds.py (99%) diff --git a/simulator.py b/simulator_ds.py similarity index 99% rename from simulator.py rename to simulator_ds.py index 203f4bb..ab262c6 100644 --- a/simulator.py +++ b/simulator_ds.py @@ -270,6 +270,3 @@ def run_dijkstra_scholten_simulation(args): plt.show() print(f"\n{reason}") - -def run_shavit_francez_simulation(args): - raise NotImplementedError() \ No newline at end of file -- GitLab From aff35bd942c7b9cfdf52b8a9ac9dda1b92ada673 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sun, 23 May 2021 10:24:29 +0300 Subject: [PATCH 28/47] sf simulation impl --- simulator_sf.py | 283 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 simulator_sf.py diff --git a/simulator_sf.py b/simulator_sf.py new file mode 100644 index 0000000..539308d --- /dev/null +++ b/simulator_sf.py @@ -0,0 +1,283 @@ +import os +import sys +import time +import pickle +import random +from typing import Text +import pandas as pd +import seaborn as sns +import networkx as nx +import matplotlib.pyplot as plt +from datetime import datetime as dt +from networkx.drawing.nx_pydot import graphviz_layout + +from Ahc import Topology +from graph import ERG, Grid, Star +from shavit_francez import ShavitFrancezAdHocNode, SFAHCNodeSimulationStatus +from Channels import P2PFIFOPerfectChannel + +def run_shavit_francez_simulation(args): + if args.network_type == "erg": + N = ERG(args.node_count, args.node_connectivity) + total_nodes = args.node_count + elif args.network_type == "grid": + N = Grid(args.node_count_on_edge) + total_nodes = args.node_count_on_edge ** 2 + elif args.network_type == "star": + N = Star(args.slave_count, master_is_root=args.master_is_root) + total_nodes = args.slave_count + 1 + + if args.run_until_termination: + args.simulation_ticks = 10**10 + + assert args.hard_stop_max_tick < args.simulation_ticks + assert args.hard_stop_min_tick > 0 + + hard_stop_on_tick = None + + if args.hard_stop_nodes: + hard_stop_on_tick = [random.randint(args.hard_stop_min_tick, args.hard_stop_max_tick) for _ in range(total_nodes)] + + node_active_ticks_initial = [random.randint(args.node_min_activeness_after_receive, args.node_max_activeness_after_receive) if random.random() <= args.node_initial_activeness_prob else 0 for _ in range(total_nodes)] + alive_nodes = list(range(total_nodes)) + + topo_context = { + "network": N, + "ms_per_tick": args.ms_per_tick, + "simulation_ticks": args.simulation_ticks, + "initial_liveness": node_active_ticks_initial, + "communication_on_active_prob": args.node_activeness_communication_prob, + "min_activeness_after_receive": args.node_min_activeness_after_receive, + "max_activeness_after_receive": args.node_max_activeness_after_receive, + "node_package_process_per_tick": args.node_package_process_per_tick, + "passiveness_death_thresh": args.passiveness_death_thresh, + "hard_stop_on_tick": hard_stop_on_tick, + "alive_nodes": alive_nodes, + "only_root_alive_initially": args.only_root_alive_initially + } + + print(topo_context) + # N.plot() + # plt.show() + + topo = Topology() + topo.construct_from_graph(N.G, ShavitFrancezAdHocNode, P2PFIFOPerfectChannel, context=topo_context) + + topo.start() + + stats = { + "df": pd.DataFrame(data={ + "dead_nodes": [], + "active_nodes": [], + "packets_in_transmit": [], + "queued_packets": [], + "control_packets_sent": [], + "control_basic_instant_ratio": [], + "control_total_cumulative_ratio": [], + "wave_packets_sent": [], + "wave_basic_instant_ratio": [], + "wave_total_cumulative_ratio": [], + }), + "terminated_on_tick": None, + "announced_on_tick": None + } + + graphs = [] + + fig, axes = plt.subplots(2, 3) + fig.set_figwidth(25) + fig.set_figheight(10) + # fig.tight_layout() + + input("\n>>> Proceed ?") + + term_wait_ctr = 0 + reason = None + + try: + for t in range(1, args.simulation_ticks + 1): + print(f"[S] Tick: {t}") + + packages_sent = 0 + packages_waiting_on_queue = 0 + num_nodes_active = 0 + num_dead_nodes = 0 + break_this_tick = False + control_packets_sent = 0 + wave_packets_sent = 0 + + T = nx.Graph() + node_color = [] + + for index, node in topo.nodes.items(): + new_state, pkg_sent_to_friend, cps, wps = node.simulation_tick() + + if N.root == index: + node_color.append("red") + elif new_state == SFAHCNodeSimulationStatus.ACTIVE: + node_color.append("green") + elif new_state == SFAHCNodeSimulationStatus.PASSIVE: + node_color.append("mediumslateblue") + elif new_state == SFAHCNodeSimulationStatus.OUT_OF_TREE: + node_color.append("gray") + + if index not in T.nodes(): + T.add_node(index) + + if node.parent_node is not None: + if node.parent_node not in T.nodes(): + T.add_node(node.parent_node) + + T.add_edge(index, node.parent_node) + + if index == N.root and new_state is None: + reason = f"root terminated ({t})" + break_this_tick = True + + if new_state == SFAHCNodeSimulationStatus.ACTIVE: + num_nodes_active += 1 + elif new_state == SFAHCNodeSimulationStatus.OUT_OF_TREE: + num_dead_nodes += 1 + + if pkg_sent_to_friend is not None: + packages_sent += 1 + + control_packets_sent += cps + wave_packets_sent += wps + packages_waiting_on_queue += node.waiting_packages_on_queue + + print(f" (ACTIVE: {num_nodes_active}, PKGS-WAIT: {packages_waiting_on_queue}, PKGS-SENT: {packages_sent})") + + if (packages_waiting_on_queue == 0 and num_nodes_active == 0 and packages_sent == 0): + if not args.no_realtime_plot: + if stats["terminated_on_tick"] is None: + stats["terminated_on_tick"] = t + + print("!!! TERMINATED !!!") + + term_wait_ctr += 1 + + if args.wait_ticks_after_termination > 0 and term_wait_ctr > args.wait_ticks_after_termination: + print("!!! FORCE TERMINATED !!!") + reason = f"forced ({args.wait_ticks_after_termination})" + break_this_tick = True + + if args.exit_on_termination: + break_this_tick = True + + total_pkgs_sent_cum = (stats["df"]["control_packets_sent"].sum() + control_packets_sent + stats["df"]["packets_in_transmit"].sum() + packages_sent + stats["df"]["wave_packets_sent"].sum() + wave_packets_sent) + + stats["df"].loc[t-1] = [ + num_dead_nodes, + num_nodes_active, + packages_sent, + packages_waiting_on_queue, + control_packets_sent, + (control_packets_sent / packages_sent) if packages_sent > 0 else 0, # TODO: Fix later, find a better soln,,, + (((stats["df"]["control_packets_sent"].sum() + control_packets_sent) / total_pkgs_sent_cum) if total_pkgs_sent_cum > 0 else 0) * 100, + wave_packets_sent, + (wave_packets_sent / packages_sent) if packages_sent > 0 else 0, # TODO: Fix later, find a better soln,,, + (((stats["df"]["wave_packets_sent"].sum() + wave_packets_sent) / total_pkgs_sent_cum) if total_pkgs_sent_cum > 0 else 0) * 100, + ] + + # stats["dead_nodes"].append(num_dead_nodes) + # stats["active_nodes"].append(num_nodes_active) + # stats["packages_in_transmit"].append(packages_sent) + graphs.append({ + "edges": T.edges(), + "nodes": T.nodes(), + }) + + # axes.scatter(x=t, y=num_nodes_active) + + if not args.no_realtime_plot: + axes[0][0].cla() + axes[0][1].cla() + axes[0][2].cla() + axes[1][0].cla() + axes[1][1].cla() + axes[1][2].cla() + + sns.lineplot(data=stats["df"]["active_nodes"], ax=axes[0][0], color="orange") + sns.lineplot(data=stats["df"]["dead_nodes"], ax=axes[0][0], color="blue") + sns.lineplot(data=stats["df"]["packets_in_transmit"], ax=axes[0][1], color="purple") + sns.lineplot(data=stats["df"]["control_packets_sent"], ax=axes[0][1], color="green") + sns.lineplot(data=stats["df"]["wave_packets_sent"], ax=axes[0][1], color="blue") + sns.lineplot(data=stats["df"]["control_total_cumulative_ratio"], ax=axes[1][0], color="mediumslateblue") + sns.lineplot(data=stats["df"]["wave_total_cumulative_ratio"], ax=axes[1][0], color="yellow") + sns.lineplot(data=stats["df"]["control_basic_instant_ratio"], ax=axes[1][1], color="red") + sns.lineplot(data=stats["df"]["wave_basic_instant_ratio"], ax=axes[1][1], color="orange") + # sns.lineplot(data=stats["active_nodes"], ax=axes, color="red") + # sns.lineplot(data=stats["dead_nodes"], ax=axes, color="mediumslateblue") + # sns.lineplot(data=stats["packages_in_transmit"], ax=axes, color="green") + + # pos = nx.spring_layout(T) + # nx.draw_networkx_nodes(T , pos, nodelist=[N.root], node_color='red', ax=axes[0][2]) + # nx.draw_networkx_nodes(T , pos, nodelist=[i for i in T.nodes() if i != N.root], node_color='mediumslateblue', ax=axes[0][2]) + # nx.draw_networkx_edges(T , pos, ax=axes[0][2]) + + # pos = graphviz_layout(T, prog="twopi") + # nx.draw(T, ax=axes[0][2], pos=pos) + + # node_color = ["red" if list(T.nodes)[i] == N.root else ("mediumslateblue" if list(T.nodes)[i] not in alive_nodes else "green") for i in range(total_nodes)] + nx.draw(T, ax=axes[0][2], with_labels=True, node_color=node_color) + + if args.network_type == "grid": + pos = {i: (i // args.node_count_on_edge, i % args.node_count_on_edge) for i in range(total_nodes)} + nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color, pos=pos) + else: + nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color) + + plt.pause(0.0005) + + if break_this_tick: + break + + time.sleep(args.ms_per_tick / 1000) + except KeyboardInterrupt: + pass + + ts = dt.now().timestamp() + + # axes.cla() + # sns.lineplot(data=stats["active_nodes"], ax=axes) + # sns.kdeplot(data=stats["active_nodes"], ax=axes) + + #plt.plot(stats["packages_in_transmit"]) + + axes[0][0].cla() + axes[0][1].cla() + axes[0][2].cla() + axes[1][0].cla() + axes[1][1].cla() + axes[1][2].cla() + + sns.lineplot(data=stats["df"]["active_nodes"], ax=axes[0][0], color="orange") + sns.lineplot(data=stats["df"]["dead_nodes"], ax=axes[0][0], color="blue") + sns.lineplot(data=stats["df"]["packets_in_transmit"], ax=axes[0][1], color="purple") + sns.lineplot(data=stats["df"]["control_packets_sent"], ax=axes[0][1], color="green") + sns.lineplot(data=stats["df"]["control_total_cumulative_ratio"], ax=axes[1][0], color="mediumslateblue") + sns.lineplot(data=stats["df"]["control_basic_instant_ratio"], ax=axes[1][1], color="red") + + nx.draw(T, ax=axes[0][2], with_labels=True, node_color=node_color) + + if args.network_type == "grid": + pos = {i: (i // args.node_count_on_edge, i % args.node_count_on_edge) for i in range(total_nodes)} + nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color, pos=pos) + else: + nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color) + + plt.savefig(f"simdump/stats_{args.network_type}_{total_nodes}_{ts}.png", dpi=200) + + with open(f"simdump/run_{args.network_type}_{total_nodes}_{ts}.pkl", "wb") as fp: + pickle.dump({ + "args": args, + "context": topo_context, + "stats": stats, + "graphs": graphs + }, fp) + + if not args.no_realtime_plot: + plt.show() + + print(f"\n{reason}") -- GitLab From 2917a0fe65eddc315b835773ce71200b25848dc6 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sun, 23 May 2021 10:25:26 +0300 Subject: [PATCH 29/47] updated simulator_ds.py --- simulator_ds.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/simulator_ds.py b/simulator_ds.py index ab262c6..4473217 100644 --- a/simulator_ds.py +++ b/simulator_ds.py @@ -256,9 +256,9 @@ def run_dijkstra_scholten_simulation(args): else: nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color) - plt.savefig(f"simdump/stats_{args.network_type}_{total_nodes}_{ts}.png", dpi=200) + plt.savefig(f"simdump/DS_stats_{args.network_type}_{total_nodes}_{ts}.png", dpi=200) - with open(f"simdump/run_{args.network_type}_{total_nodes}_{ts}.pkl", "wb") as fp: + with open(f"simdump/DS_run_{args.network_type}_{total_nodes}_{ts}.pkl", "wb") as fp: pickle.dump({ "args": args, "context": topo_context, -- GitLab From 45fe3dbbff7402eefb10f2c01e3dde933848a8b7 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sun, 23 May 2021 10:25:26 +0300 Subject: [PATCH 30/47] updated simulator_sf.py --- simulator_sf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/simulator_sf.py b/simulator_sf.py index 539308d..6e33538 100644 --- a/simulator_sf.py +++ b/simulator_sf.py @@ -267,9 +267,9 @@ def run_shavit_francez_simulation(args): else: nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color) - plt.savefig(f"simdump/stats_{args.network_type}_{total_nodes}_{ts}.png", dpi=200) + plt.savefig(f"simdump/SF_stats_{args.network_type}_{total_nodes}_{ts}.png", dpi=200) - with open(f"simdump/run_{args.network_type}_{total_nodes}_{ts}.pkl", "wb") as fp: + with open(f"simdump/SF_run_{args.network_type}_{total_nodes}_{ts}.pkl", "wb") as fp: pickle.dump({ "args": args, "context": topo_context, -- GitLab From a20dffc82d63ac814b3208f5910a87221b3e84ab Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sun, 23 May 2021 10:25:36 +0300 Subject: [PATCH 31/47] sf/ds sim separation --- cli.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli.py b/cli.py index b84acdb..b238d5f 100644 --- a/cli.py +++ b/cli.py @@ -1,5 +1,6 @@ from argparse import ArgumentParser -from simulator import run_dijkstra_scholten_simulation, run_shavit_francez_simulation +from simulator_sf import run_shavit_francez_simulation +from simulator_ds import run_dijkstra_scholten_simulation algorithm_handlers = { "djikstra-scholten": run_dijkstra_scholten_simulation, -- GitLab From d31fce5a70635647108b082c191c476636460f4c Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sun, 23 May 2021 10:26:03 +0300 Subject: [PATCH 32/47] updated .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a458dee..22b782d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .DS_Store simdump/ simdump_dev/ +bench_dump/ # Byte-compiled / optimized / DLL files -- GitLab From b36d1d1653999dfb620728e837b25d635ae988e5 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sun, 23 May 2021 11:18:37 +0300 Subject: [PATCH 33/47] simulator update --- shavit_francez.py | 27 +++++++---- simulator_ds.py | 7 ++- simulator_sf.py | 114 ++++++++++++++++++---------------------------- 3 files changed, 64 insertions(+), 84 deletions(-) diff --git a/shavit_francez.py b/shavit_francez.py index bf42e23..8a94390 100644 --- a/shavit_francez.py +++ b/shavit_francez.py @@ -17,6 +17,8 @@ from Ahc import (ComponentModel, Event, ConnectorTypes, Topology, ComponentRegistry, GenericMessagePayload, GenericMessageHeader, GenericMessage, EventTypes) +WAVE_DEBUG = False + registry = ComponentRegistry() # define your own message types @@ -168,13 +170,15 @@ class ShavitFrancezApplicationLayerComponent(ComponentModel): # print(f"\n\n\n{self.componentinstancenumber}: {e} {hdr.messagefrom} {self._children}\n\n\n") pass elif hdr.messagetype == ApplicationLayerMessageType.WAVE: - if applmessage.payload.tag == self.componentinstancenumber: - self.my_wave_bucket.append(applmessage.payload.response) + if applmessage.payload.messagepayload.tag == self.componentinstancenumber: + self.my_wave_bucket.append(applmessage.payload.messagepayload.response) - print(f" WAVE << N-{self.componentinstancenumber} << N-{hdr.messagefrom} ({applmessage.payload.response})") + if WAVE_DEBUG: + print(f" WAVE << N-{self.componentinstancenumber} << N-{hdr.messagefrom} ({applmessage.payload.messagepayload.response})") - if len(self.my_wave_bucket) == (self.context["network"].G.nodes() - 1): - print(f" ::: WAVE END >> N-{self.componentinstancenumber}: {self.my_wave_bucket}") + if len(self.my_wave_bucket) == (len(self.context["network"].G.nodes()) - 1): + if WAVE_DEBUG: + print(f" ::: WAVE END >> N-{self.componentinstancenumber}: {' '.join(['A' if x == SFWaveResponse.ACTIVE else ('F' if x == SFWaveResponse.FINISHED else 'XXX') for x in self.my_wave_bucket])}") if SFWaveResponse.ACTIVE not in self.my_wave_bucket: print(f" ::: WAVE END >> N-{self.componentinstancenumber}: ANNOUNCE!") @@ -184,11 +188,13 @@ class ShavitFrancezApplicationLayerComponent(ComponentModel): self.my_wave_bucket = [] else: if self.__exited_from_tree: - self.send_down(Event(self, EventTypes.MFRT, self.prepare_application_layer_message(ApplicationLayerMessageType.WAVE, applmessage.payload.tag, SFWaveMessagePayload(applmessage.payload.tag, SFWaveMessageType.RESPONSE, SFWaveResponse.FINISHED)))) - print(f" WAVE >> N-{self.componentinstancenumber} >> N-{applmessage.payload.tag} >> FINISHED") + self.send_down(Event(self, EventTypes.MFRT, self.prepare_application_layer_message(ApplicationLayerMessageType.WAVE, applmessage.payload.messagepayload.tag, SFWaveMessagePayload(applmessage.payload.messagepayload.tag, SFWaveMessageType.RESPONSE, SFWaveResponse.FINISHED)))) + if WAVE_DEBUG: + print(f" WAVE >> N-{self.componentinstancenumber} >> N-{applmessage.payload.messagepayload.tag} >> FINISHED") else: - self.send_down(Event(self, EventTypes.MFRT, self.prepare_application_layer_message(ApplicationLayerMessageType.WAVE, applmessage.payload.tag, SFWaveMessagePayload(applmessage.payload.tag, SFWaveMessageType.RESPONSE, SFWaveResponse.ACTIVE)))) - print(f" WAVE >> N-{self.componentinstancenumber} >> N-{applmessage.payload.tag} >> ACTIVE") + self.send_down(Event(self, EventTypes.MFRT, self.prepare_application_layer_message(ApplicationLayerMessageType.WAVE, applmessage.payload.messagepayload.tag, SFWaveMessagePayload(applmessage.payload.messagepayload.tag, SFWaveMessageType.RESPONSE, SFWaveResponse.ACTIVE)))) + if WAVE_DEBUG: + print(f" WAVE >> N-{self.componentinstancenumber} >> N-{applmessage.payload.messagepayload.tag} >> ACTIVE") self._wms += 1 else: @@ -198,7 +204,7 @@ class ShavitFrancezApplicationLayerComponent(ComponentModel): def call_wave(self): print(f" > CALL WAVE @@ N-{self.componentinstancenumber}") - to_nodes = [i for i in range(self.context["network"].G.nodes()) if i != self.componentinstancenumber] + to_nodes = [i for i in range(len(self.context["network"].G.nodes())) if i != self.componentinstancenumber] for to in to_nodes: self.send_down(Event(self, EventTypes.MFRT, self.prepare_application_layer_message(ApplicationLayerMessageType.WAVE, to, SFWaveMessagePayload(self.componentinstancenumber, SFWaveMessageType.REQUEST)))) @@ -218,6 +224,7 @@ class ShavitFrancezApplicationLayerComponent(ComponentModel): if self.componentinstancenumber in self.context["alive_nodes"]: self.context["alive_nodes"].remove(self.componentinstancenumber) + self.__exited_from_tree = True print(f" > EXIT @@ N-{self.componentinstancenumber}") self.call_wave() diff --git a/simulator_ds.py b/simulator_ds.py index 4473217..f9bab88 100644 --- a/simulator_ds.py +++ b/simulator_ds.py @@ -144,9 +144,8 @@ def run_dijkstra_scholten_simulation(args): print(f" (ACTIVE: {num_nodes_active}, PKGS-WAIT: {packages_waiting_on_queue}, PKGS-SENT: {packages_sent})") if (packages_waiting_on_queue == 0 and num_nodes_active == 0 and packages_sent == 0): - if not args.no_realtime_plot: - if stats["terminated_on_tick"] is None: - stats["terminated_on_tick"] = t + if stats["terminated_on_tick"] is None: + stats["terminated_on_tick"] = t print("!!! TERMINATED !!!") @@ -269,4 +268,4 @@ def run_dijkstra_scholten_simulation(args): if not args.no_realtime_plot: plt.show() - print(f"\n{reason}") + print(f"\n{reason} [{t - stats['terminated_on_tick'] if stats['terminated_on_tick'] is not None else None}]") diff --git a/simulator_sf.py b/simulator_sf.py index 6e33538..163e6f4 100644 --- a/simulator_sf.py +++ b/simulator_sf.py @@ -77,13 +77,12 @@ def run_shavit_francez_simulation(args): "wave_packets_sent": [], "wave_basic_instant_ratio": [], "wave_total_cumulative_ratio": [], + "wave_control_cumulative_ratio": [] }), "terminated_on_tick": None, "announced_on_tick": None } - graphs = [] - fig, axes = plt.subplots(2, 3) fig.set_figwidth(25) fig.set_figheight(10) @@ -93,6 +92,7 @@ def run_shavit_francez_simulation(args): term_wait_ctr = 0 reason = None + wave_finisher = None try: for t in range(1, args.simulation_ticks + 1): @@ -106,32 +106,28 @@ def run_shavit_francez_simulation(args): control_packets_sent = 0 wave_packets_sent = 0 - T = nx.Graph() node_color = [] for index, node in topo.nodes.items(): new_state, pkg_sent_to_friend, cps, wps = node.simulation_tick() - if N.root == index: + if N.root == index and new_state != SFAHCNodeSimulationStatus.OUT_OF_TREE: node_color.append("red") + elif N.root == index and new_state == SFAHCNodeSimulationStatus.OUT_OF_TREE: + node_color.append("orange") elif new_state == SFAHCNodeSimulationStatus.ACTIVE: node_color.append("green") elif new_state == SFAHCNodeSimulationStatus.PASSIVE: node_color.append("mediumslateblue") elif new_state == SFAHCNodeSimulationStatus.OUT_OF_TREE: node_color.append("gray") + else: # is None... + # It's the wave finisher!!! + node_color.append("yellow") + wave_finisher = index - if index not in T.nodes(): - T.add_node(index) - - if node.parent_node is not None: - if node.parent_node not in T.nodes(): - T.add_node(node.parent_node) - - T.add_edge(index, node.parent_node) - - if index == N.root and new_state is None: - reason = f"root terminated ({t})" + if new_state is None: + reason = f"wave terminated ({t}) ({wave_finisher})" break_this_tick = True if new_state == SFAHCNodeSimulationStatus.ACTIVE: @@ -149,9 +145,8 @@ def run_shavit_francez_simulation(args): print(f" (ACTIVE: {num_nodes_active}, PKGS-WAIT: {packages_waiting_on_queue}, PKGS-SENT: {packages_sent})") if (packages_waiting_on_queue == 0 and num_nodes_active == 0 and packages_sent == 0): - if not args.no_realtime_plot: - if stats["terminated_on_tick"] is None: - stats["terminated_on_tick"] = t + if stats["terminated_on_tick"] is None: + stats["terminated_on_tick"] = t print("!!! TERMINATED !!!") @@ -165,6 +160,7 @@ def run_shavit_francez_simulation(args): if args.exit_on_termination: break_this_tick = True + control_pkgs_sent_cum = stats["df"]["control_packets_sent"].sum() + control_packets_sent total_pkgs_sent_cum = (stats["df"]["control_packets_sent"].sum() + control_packets_sent + stats["df"]["packets_in_transmit"].sum() + packages_sent + stats["df"]["wave_packets_sent"].sum() + wave_packets_sent) stats["df"].loc[t-1] = [ @@ -178,16 +174,9 @@ def run_shavit_francez_simulation(args): wave_packets_sent, (wave_packets_sent / packages_sent) if packages_sent > 0 else 0, # TODO: Fix later, find a better soln,,, (((stats["df"]["wave_packets_sent"].sum() + wave_packets_sent) / total_pkgs_sent_cum) if total_pkgs_sent_cum > 0 else 0) * 100, + (((stats["df"]["wave_packets_sent"].sum() + wave_packets_sent) / control_pkgs_sent_cum) if control_pkgs_sent_cum > 0 else 0) * 100, ] - # stats["dead_nodes"].append(num_dead_nodes) - # stats["active_nodes"].append(num_nodes_active) - # stats["packages_in_transmit"].append(packages_sent) - graphs.append({ - "edges": T.edges(), - "nodes": T.nodes(), - }) - # axes.scatter(x=t, y=num_nodes_active) if not args.no_realtime_plot: @@ -207,20 +196,7 @@ def run_shavit_francez_simulation(args): sns.lineplot(data=stats["df"]["wave_total_cumulative_ratio"], ax=axes[1][0], color="yellow") sns.lineplot(data=stats["df"]["control_basic_instant_ratio"], ax=axes[1][1], color="red") sns.lineplot(data=stats["df"]["wave_basic_instant_ratio"], ax=axes[1][1], color="orange") - # sns.lineplot(data=stats["active_nodes"], ax=axes, color="red") - # sns.lineplot(data=stats["dead_nodes"], ax=axes, color="mediumslateblue") - # sns.lineplot(data=stats["packages_in_transmit"], ax=axes, color="green") - - # pos = nx.spring_layout(T) - # nx.draw_networkx_nodes(T , pos, nodelist=[N.root], node_color='red', ax=axes[0][2]) - # nx.draw_networkx_nodes(T , pos, nodelist=[i for i in T.nodes() if i != N.root], node_color='mediumslateblue', ax=axes[0][2]) - # nx.draw_networkx_edges(T , pos, ax=axes[0][2]) - - # pos = graphviz_layout(T, prog="twopi") - # nx.draw(T, ax=axes[0][2], pos=pos) - - # node_color = ["red" if list(T.nodes)[i] == N.root else ("mediumslateblue" if list(T.nodes)[i] not in alive_nodes else "green") for i in range(total_nodes)] - nx.draw(T, ax=axes[0][2], with_labels=True, node_color=node_color) + sns.lineplot(data=stats["df"]["wave_control_cumulative_ratio"], ax=axes[0][2], color="mediumslateblue") if args.network_type == "grid": pos = {i: (i // args.node_count_on_edge, i % args.node_count_on_edge) for i in range(total_nodes)} @@ -239,33 +215,32 @@ def run_shavit_francez_simulation(args): ts = dt.now().timestamp() - # axes.cla() - # sns.lineplot(data=stats["active_nodes"], ax=axes) - # sns.kdeplot(data=stats["active_nodes"], ax=axes) - - #plt.plot(stats["packages_in_transmit"]) - - axes[0][0].cla() - axes[0][1].cla() - axes[0][2].cla() - axes[1][0].cla() - axes[1][1].cla() - axes[1][2].cla() - - sns.lineplot(data=stats["df"]["active_nodes"], ax=axes[0][0], color="orange") - sns.lineplot(data=stats["df"]["dead_nodes"], ax=axes[0][0], color="blue") - sns.lineplot(data=stats["df"]["packets_in_transmit"], ax=axes[0][1], color="purple") - sns.lineplot(data=stats["df"]["control_packets_sent"], ax=axes[0][1], color="green") - sns.lineplot(data=stats["df"]["control_total_cumulative_ratio"], ax=axes[1][0], color="mediumslateblue") - sns.lineplot(data=stats["df"]["control_basic_instant_ratio"], ax=axes[1][1], color="red") - - nx.draw(T, ax=axes[0][2], with_labels=True, node_color=node_color) - - if args.network_type == "grid": - pos = {i: (i // args.node_count_on_edge, i % args.node_count_on_edge) for i in range(total_nodes)} - nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color, pos=pos) - else: - nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color) + if args.no_realtime_plot: + axes[0][0].cla() + axes[0][1].cla() + axes[0][2].cla() + axes[1][0].cla() + axes[1][1].cla() + axes[1][2].cla() + + sns.lineplot(data=stats["df"]["active_nodes"], ax=axes[0][0], color="orange") + sns.lineplot(data=stats["df"]["dead_nodes"], ax=axes[0][0], color="blue") + sns.lineplot(data=stats["df"]["packets_in_transmit"], ax=axes[0][1], color="purple") + sns.lineplot(data=stats["df"]["control_packets_sent"], ax=axes[0][1], color="green") + sns.lineplot(data=stats["df"]["wave_packets_sent"], ax=axes[0][1], color="blue") + sns.lineplot(data=stats["df"]["control_total_cumulative_ratio"], ax=axes[1][0], color="mediumslateblue") + sns.lineplot(data=stats["df"]["wave_total_cumulative_ratio"], ax=axes[1][0], color="yellow") + sns.lineplot(data=stats["df"]["control_basic_instant_ratio"], ax=axes[1][1], color="red") + sns.lineplot(data=stats["df"]["wave_basic_instant_ratio"], ax=axes[1][1], color="orange") + sns.lineplot(data=stats["df"]["wave_control_cumulative_ratio"], ax=axes[0][2], color="mediumslateblue") + + if args.network_type == "grid": + pos = {i: (i // args.node_count_on_edge, i % args.node_count_on_edge) for i in range(total_nodes)} + nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color, pos=pos) + else: + nx.draw(N.G, ax=axes[1][2], with_labels=True, node_color=node_color) + + plt.pause(0.0005) plt.savefig(f"simdump/SF_stats_{args.network_type}_{total_nodes}_{ts}.png", dpi=200) @@ -273,11 +248,10 @@ def run_shavit_francez_simulation(args): pickle.dump({ "args": args, "context": topo_context, - "stats": stats, - "graphs": graphs + "stats": stats }, fp) if not args.no_realtime_plot: plt.show() - print(f"\n{reason}") + print(f"\n{reason} [{t - stats['terminated_on_tick'] if stats['terminated_on_tick'] is not None else None}]") -- GitLab From 0eeb2755fbff115fe64c5a19cb630b3b56061c63 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sun, 23 May 2021 11:23:20 +0300 Subject: [PATCH 34/47] updated Paper Notes.md --- Paper Notes.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Paper Notes.md diff --git a/Paper Notes.md b/Paper Notes.md new file mode 100644 index 0000000..cb776d4 --- /dev/null +++ b/Paper Notes.md @@ -0,0 +1,18 @@ +# Wave algorithm + +## why echo? +- works for cyclic graphs, tree algo only works in acyclic ones. + +# evaluation metrics# possibe evaluation metrics + +- control packet drop in SF is not a big deal, there are N waves. in DS, just one controller exist (initiator). +- detection lateness in SF > DS (smaller is better) +- detection success SF > DS (bigger is better) + +- CPR : control packet ratio = num(control packages) / num(total packages) +- DL : detection latency = tick(algo done) - tick(termination) => ne kadar erken detect etti +- WPR : wave packet ratio = num(wave packages) / num(total packages) +- CPPN : control packets per node = num(control packages) / num(nodes) +- WPPN : wave packets per node = num(wave packages) / num(nodes) + +- ALSO, these metrics can be analyzed dependent on the network structure!! \ No newline at end of file -- GitLab From ffeb55ad79cf9771ae0886d8d1ecb394e65fd14a Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sun, 23 May 2021 11:23:30 +0300 Subject: [PATCH 35/47] updated Ahc.py --- Ahc.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Ahc.py b/Ahc.py index 95aae4a..cac785c 100644 --- a/Ahc.py +++ b/Ahc.py @@ -302,7 +302,7 @@ class Topology: N = len(self.G.nodes) self.compute_forwarding_table() self.nodecolors = ['b'] * N - self.nodepos = nx.drawing.spring_layout(self.G) + # self.nodepos = nx.drawing.spring_layout(self.G) self.lock = Lock() ComponentRegistry().init() @@ -357,7 +357,7 @@ class Topology: def plot(self): #self.lock.acquire() - nx.draw(self.G, self.nodepos, node_color=self.nodecolors, with_labels=True, font_weight='bold') - plt.draw() + # nx.draw(self.G, self.nodepos, node_color=self.nodecolors, with_labels=True, font_weight='bold') + # plt.draw() print(self.nodecolors) #self.lock.release() -- GitLab From 812d261358dd819585d6916ad922238bdfb04b51 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sun, 23 May 2021 11:28:01 +0300 Subject: [PATCH 36/47] updated run_sim.sh --- run_sim.sh | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100755 run_sim.sh diff --git a/run_sim.sh b/run_sim.sh new file mode 100755 index 0000000..f1b1843 --- /dev/null +++ b/run_sim.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +set -e + +run_sim_ds() { + python3 ../cli.py djikstra-scholten 100 100 --run_until_termination --passiveness_death_thresh 3000 --hard_stop_nodes --hard_stop_min_tick 50 --hard_stop_max_tick 300 --node_package_process_per_tick 3 --node_initial_activeness_prob .5 --node_activeness_communication_prob .5 --wait_ticks_after_termination 200 --only_root_alive_initially --no_realtime_plot "${1}" "${2}" > "DS_${1}_${2}_run-${3}.out" <<< "\n" +} + +run_sim_sf() { + python3 ../cli.py shavit-francez 100 100 --run_until_termination --passiveness_death_thresh 3000 --hard_stop_nodes --hard_stop_min_tick 50 --hard_stop_max_tick 300 --node_package_process_per_tick 3 --node_initial_activeness_prob .5 --node_activeness_communication_prob .5 --wait_ticks_after_termination 200 --only_root_alive_initially --no_realtime_plot "${1}" "${2}" > "SF_${1}_${2}_run-${3}.out" <<< "\n" +} + +for i in {1..10}; do + run_sim_ds "grid" "3" "${i}" + run_sim_ds "grid" "4" "${i}" + run_sim_ds "grid" "5" "${i}" + run_sim_ds "grid" "6" "${i}" + run_sim_ds "grid" "7" "${i}" + run_sim_ds "grid" "8" "${i}" + run_sim_ds "grid" "9" "${i}" + run_sim_ds "grid" "10" "${i}" + run_sim_sf "grid" "3" "${i}" + run_sim_sf "grid" "4" "${i}" + run_sim_sf "grid" "5" "${i}" + run_sim_sf "grid" "6" "${i}" + run_sim_sf "grid" "7" "${i}" + run_sim_sf "grid" "8" "${i}" + run_sim_sf "grid" "9" "${i}" + run_sim_sf "grid" "10" "${i}" +done + +for i in {1..10}; do + run_sim_ds "star" "4" "${i}" + run_sim_ds "star" "9" "${i}" + run_sim_ds "star" "19" "${i}" + run_sim_ds "star" "29" "${i}" + run_sim_ds "star" "39" "${i}" + run_sim_ds "star" "49" "${i}" + run_sim_ds "star" "59" "${i}" + run_sim_sf "star" "4" "${i}" + run_sim_sf "star" "9" "${i}" + run_sim_sf "star" "19" "${i}" + run_sim_sf "star" "29" "${i}" + run_sim_sf "star" "39" "${i}" + run_sim_sf "star" "49" "${i}" + run_sim_sf "star" "59" "${i}" +done + +for i in {1..10}; do + run_sim_ds "erg" "5" "${i}" + run_sim_ds "erg" "10" "${i}" + run_sim_ds "erg" "15" "${i}" + run_sim_ds "erg" "20" "${i}" + run_sim_ds "erg" "25" "${i}" + run_sim_ds "erg" "30" "${i}" + run_sim_ds "erg" "35" "${i}" + run_sim_ds "erg" "40" "${i}" + run_sim_ds "erg" "45" "${i}" + run_sim_ds "erg" "50" "${i}" + run_sim_sf "erg" "5" "${i}" + run_sim_sf "erg" "10" "${i}" + run_sim_sf "erg" "15" "${i}" + run_sim_sf "erg" "20" "${i}" + run_sim_sf "erg" "25" "${i}" + run_sim_sf "erg" "30" "${i}" + run_sim_sf "erg" "35" "${i}" + run_sim_sf "erg" "40" "${i}" + run_sim_sf "erg" "45" "${i}" + run_sim_sf "erg" "50" "${i}" +done \ No newline at end of file -- GitLab From e0ae7a4d67a0a17dcfeb02a34fb903f74d99136f Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sun, 23 May 2021 11:28:16 +0300 Subject: [PATCH 37/47] updated ds_run.sh --- ds_run.sh | 41 ----------------------------------------- 1 file changed, 41 deletions(-) delete mode 100755 ds_run.sh diff --git a/ds_run.sh b/ds_run.sh deleted file mode 100755 index ce7549b..0000000 --- a/ds_run.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -set -e - -run_sim() { - python3 ../cli.py djikstra-scholten 100 100 --run_until_termination --passiveness_death_thresh 3000 --hard_stop_nodes --hard_stop_min_tick 50 --hard_stop_max_tick 250 --node_package_process_per_tick 3 --node_initial_activeness_prob .5 --node_activeness_communication_prob .8 --wait_ticks_after_termination 50 --only_root_alive_initially --no_realtime_plot "${1}" "${2}" > "${1}_${2}_run-${3}.out" <<< "\n" -} - -for i in {1..10}; do - run_sim "grid" "3" "${i}" - run_sim "grid" "4" "${i}" - run_sim "grid" "5" "${i}" - run_sim "grid" "6" "${i}" - run_sim "grid" "7" "${i}" - run_sim "grid" "8" "${i}" - run_sim "grid" "9" "${i}" - run_sim "grid" "10" "${i}" -done - -for i in {1..10}; do - run_sim "star" "4" "${i}" - run_sim "star" "9" "${i}" - run_sim "star" "19" "${i}" - run_sim "star" "29" "${i}" - run_sim "star" "39" "${i}" - run_sim "star" "49" "${i}" - run_sim "star" "59" "${i}" -done - -for i in {1..10}; do - run_sim "erg" "5" "${i}" - run_sim "erg" "10" "${i}" - run_sim "erg" "15" "${i}" - run_sim "erg" "20" "${i}" - run_sim "erg" "25" "${i}" - run_sim "erg" "30" "${i}" - run_sim "erg" "35" "${i}" - run_sim "erg" "40" "${i}" - run_sim "erg" "45" "${i}" - run_sim "erg" "50" "${i}" -done \ No newline at end of file -- GitLab From d771c5eb8fe4a62ae2774b7632cd40d67ca75d87 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sun, 23 May 2021 11:32:22 +0300 Subject: [PATCH 38/47] updated run_sim.sh --- run_sim.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/run_sim.sh b/run_sim.sh index f1b1843..3d55fe6 100755 --- a/run_sim.sh +++ b/run_sim.sh @@ -3,10 +3,12 @@ set -e run_sim_ds() { + echo "++ DS ${1}(${2}) - run ${3}" python3 ../cli.py djikstra-scholten 100 100 --run_until_termination --passiveness_death_thresh 3000 --hard_stop_nodes --hard_stop_min_tick 50 --hard_stop_max_tick 300 --node_package_process_per_tick 3 --node_initial_activeness_prob .5 --node_activeness_communication_prob .5 --wait_ticks_after_termination 200 --only_root_alive_initially --no_realtime_plot "${1}" "${2}" > "DS_${1}_${2}_run-${3}.out" <<< "\n" } run_sim_sf() { + echo "++ SF ${1}(${2}) - run ${3}" python3 ../cli.py shavit-francez 100 100 --run_until_termination --passiveness_death_thresh 3000 --hard_stop_nodes --hard_stop_min_tick 50 --hard_stop_max_tick 300 --node_package_process_per_tick 3 --node_initial_activeness_prob .5 --node_activeness_communication_prob .5 --wait_ticks_after_termination 200 --only_root_alive_initially --no_realtime_plot "${1}" "${2}" > "SF_${1}_${2}_run-${3}.out" <<< "\n" } -- GitLab From 9f220b581e39e7a62f1466c61a0d4a461ff8d9a3 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Sun, 23 May 2021 11:32:24 +0300 Subject: [PATCH 39/47] updated Paper Notes.md --- Paper Notes.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Paper Notes.md b/Paper Notes.md index cb776d4..c9d597e 100644 --- a/Paper Notes.md +++ b/Paper Notes.md @@ -15,4 +15,6 @@ - CPPN : control packets per node = num(control packages) / num(nodes) - WPPN : wave packets per node = num(wave packages) / num(nodes) -- ALSO, these metrics can be analyzed dependent on the network structure!! \ No newline at end of file +- ALSO, these metrics can be analyzed dependent on the network structure!! + +- DS/SF detection latency distribution and standard deviation \ No newline at end of file -- GitLab From 1c7d8dd22a3ccef13b55840d29c28afe1da24e2f Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Mon, 24 May 2021 10:26:02 +0300 Subject: [PATCH 40/47] analysis script --- analyze.py | 203 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 analyze.py diff --git a/analyze.py b/analyze.py new file mode 100644 index 0000000..21a230a --- /dev/null +++ b/analyze.py @@ -0,0 +1,203 @@ +import os +import sys +import time +import json +import pickle +import random +from typing import Text +import pandas as pd +import seaborn as sns +import networkx as nx +import matplotlib.pyplot as plt +from datetime import datetime as dt +from networkx.drawing.nx_pydot import graphviz_layout + +from Ahc import Topology +from graph import ERG, Grid, Star +from shavit_francez import ShavitFrancezAdHocNode, SFAHCNodeSimulationStatus +from Channels import P2PFIFOPerfectChannel + +metrics = { + "DS": { + "erg": [], + "star": [], + "grid": [] + }, + "SF": { + "erg": [], + "star": [], + "grid": [] + } +} + +latency = { + "DS": { + "erg": [], + "star": [], + "grid": [] + }, + "SF": { + "erg": [], + "star": [], + "grid": [] + } +} + +lnr_distr = { + "DS": { + "erg": None, + "star": None, + "grid": None + }, + "SF": { + "erg": None, + "star": None, + "grid": None + } +} + + +for fpath in os.listdir("bench_dump/simdump/"): + if fpath.endswith(".pkl"): + algo, _, topo, nodes, _ = fpath.split("_") + nodes = int(nodes) + + # print(f"++ {algo} {topo} {nodes}") + + with open(f"bench_dump/simdump/{fpath}", "rb") as fp: + data = pickle.load(fp) + + cpr = list(data["stats"]["df"]["control_total_cumulative_ratio"])[-1] + cppn = sum(list(data["stats"]["df"]["control_packets_sent"])) / nodes + + if algo == "SF": + wpr = list(data["stats"]["df"]["wave_total_cumulative_ratio"])[-1] + wppn = sum(list(data["stats"]["df"]["wave_packets_sent"])) / nodes + + metrics["SF"][topo].append((nodes, { + "cpr": cpr, + "wpr": wpr, + "cppn": cppn, + "wppn": wppn + })) + elif algo == "DS": + metrics["DS"][topo].append((nodes, { + "cpr": cpr, + "cppn": cppn, + })) + else: + raise RuntimeError(algo) + +for fpath in os.listdir("bench_dump/"): + if fpath.endswith(".out"): + algo, topo, nodes, _ = fpath.split("_") + nodes = int(nodes) + + if topo == "grid": + nodes = nodes ** 2 + elif topo == "star": + nodes = nodes + 1 + elif topo == "erg": + pass + else: + raise RuntimeError(topo) + + # print(f"## {algo} {topo} {nodes} ({fpath})") + + try: + with open(f"bench_dump/{fpath}", "r") as fp: + lines = fp.readlines() + except UnicodeDecodeError as e: + print(f"[!!!] UnicodeDecodeError ({fpath}): {e}") + continue + + if algo == "SF": + reason = lines[-1].split(" ")[0] + + if reason not in ["wave", "forced"]: + raise RuntimeError(reason) + + if reason == "forced": + latency["SF"][topo].append((False, )) + else: + reason, _, _, _, diff = lines[-1].split() + + assert diff[0] == "[" and diff[-1] == "]" + + if diff[1:-1] != "None": + dif = int(diff[1:-1]) + else: + dif = 0 + + latency["SF"][topo].append((True, dif, dif/nodes)) + elif algo == "DS": + reason = lines[-1].split(" ")[0] + + if reason not in ["root", "forced"]: + raise RuntimeError(reason) + + if reason == "forced": + latency["DS"][topo].append((False, )) + else: + reason, _, _, diff = lines[-1].split() + + assert diff[0] == "[" and diff[-1] == "]" + + if diff[1:-1] != "None": + dif = int(diff[1:-1]) + else: + dif = 0 + + latency["DS"][topo].append((True, dif, dif/nodes)) + else: + raise RuntimeError(algo) + +for algo in lnr_distr: + for topo in lnr_distr[algo]: + lnr_distr[algo][topo] = [x[-1] for x in latency[algo][topo] if x[0] and x[-1] > 0] + +# print(json.dumps({ +# "metrics": metrics, +# "latency": latency, +# "lnr": lnr_distr +# }, indent=4)) + +plot_all = False + +if plot_all: + fig, axes = plt.subplots(2, 3) + fig.set_figheight(10) + fig.set_figwidth(30) + # fig.tight_layout() + + axes[0][0].set_title("Dijkstra-Scholten Grid LNR Distribution") + axes[0][1].set_title("Dijkstra-Scholten Star LNR Distribution") + axes[0][2].set_title("Dijkstra-Scholten ERG LNR Distribution") + axes[1][0].set_title("Shavit-Francez Grid LNR Distribution") + axes[1][1].set_title("Shavit-Francez Star LNR Distribution") + axes[1][2].set_title("Shavit-Francez ERG LNR Distribution") + + sns.histplot(data=lnr_distr["DS"]["grid"], kde=True, ax=axes[0][0]) + sns.histplot(data=lnr_distr["DS"]["star"], kde=True, ax=axes[0][1]) + sns.histplot(data=lnr_distr["DS"]["erg"], kde=True, ax=axes[0][2]) + sns.histplot(data=lnr_distr["SF"]["grid"], kde=True, ax=axes[1][0]) + sns.histplot(data=lnr_distr["SF"]["star"], kde=True, ax=axes[1][1]) + sns.histplot(data=lnr_distr["SF"]["erg"], kde=True, ax=axes[1][2]) +else: + fig, axes = plt.subplots(1, 3) + fig.set_figheight(5) + fig.set_figwidth(25) + + axes[0].set_title("DS/SF Grid LNR Distribution") + axes[1].set_title("DS/SF Star LNR Distribution") + axes[2].set_title("DS/SF ERG LNR Distribution") + axes[0].set_xlabel("Latency/Node Ratio (ticks/node)") + axes[1].set_xlabel("Latency/Node Ratio (ticks/node)") + axes[2].set_xlabel("Latency/Node Ratio (ticks/node)") + + sns.histplot(data={"Dijkstra-Scholten": lnr_distr["DS"]["grid"], "Shavit-Francez": lnr_distr["SF"]["grid"]}, kde=True, ax=axes[0], log_scale=True) + sns.histplot(data={"Dijkstra-Scholten": lnr_distr["DS"]["star"], "Shavit-Francez": lnr_distr["SF"]["star"]}, kde=True, ax=axes[1], log_scale=True) + sns.histplot(data={"Dijkstra-Scholten": lnr_distr["DS"]["erg"], "Shavit-Francez": lnr_distr["SF"]["erg"]}, kde=True, ax=axes[2], log_scale=True) + +sns.despine() +plt.show() -- GitLab From ecdb5d606985aa86eab91a1daccc07c6cbf50ba8 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Mon, 24 May 2021 10:39:14 +0300 Subject: [PATCH 41/47] analysis script --- analyze.py | 128 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 92 insertions(+), 36 deletions(-) diff --git a/analyze.py b/analyze.py index 21a230a..3c0f19e 100644 --- a/analyze.py +++ b/analyze.py @@ -56,6 +56,19 @@ lnr_distr = { } } +snr_distrib = { + "DS": { + "erg": {}, + "star": {}, + "grid": {} + }, + "SF": { + "erg": {}, + "star": {}, + "grid": {} + } +} + for fpath in os.listdir("bench_dump/simdump/"): if fpath.endswith(".pkl"): @@ -119,6 +132,11 @@ for fpath in os.listdir("bench_dump/"): if reason == "forced": latency["SF"][topo].append((False, )) + + if nodes not in snr_distrib["SF"][topo]: + snr_distrib["SF"][topo][nodes] = [] + + snr_distrib["SF"][topo][nodes].append(0) else: reason, _, _, _, diff = lines[-1].split() @@ -130,6 +148,11 @@ for fpath in os.listdir("bench_dump/"): dif = 0 latency["SF"][topo].append((True, dif, dif/nodes)) + + if nodes not in snr_distrib["SF"][topo]: + snr_distrib["SF"][topo][nodes] = [] + + snr_distrib["SF"][topo][nodes].append(1) elif algo == "DS": reason = lines[-1].split(" ")[0] @@ -138,6 +161,11 @@ for fpath in os.listdir("bench_dump/"): if reason == "forced": latency["DS"][topo].append((False, )) + + if nodes not in snr_distrib["DS"][topo]: + snr_distrib["DS"][topo][nodes] = [] + + snr_distrib["DS"][topo][nodes].append(0) else: reason, _, _, diff = lines[-1].split() @@ -149,6 +177,11 @@ for fpath in os.listdir("bench_dump/"): dif = 0 latency["DS"][topo].append((True, dif, dif/nodes)) + + if nodes not in snr_distrib["DS"][topo]: + snr_distrib["DS"][topo][nodes] = [] + + snr_distrib["DS"][topo][nodes].append(1) else: raise RuntimeError(algo) @@ -162,42 +195,65 @@ for algo in lnr_distr: # "lnr": lnr_distr # }, indent=4)) -plot_all = False - -if plot_all: - fig, axes = plt.subplots(2, 3) - fig.set_figheight(10) - fig.set_figwidth(30) - # fig.tight_layout() - - axes[0][0].set_title("Dijkstra-Scholten Grid LNR Distribution") - axes[0][1].set_title("Dijkstra-Scholten Star LNR Distribution") - axes[0][2].set_title("Dijkstra-Scholten ERG LNR Distribution") - axes[1][0].set_title("Shavit-Francez Grid LNR Distribution") - axes[1][1].set_title("Shavit-Francez Star LNR Distribution") - axes[1][2].set_title("Shavit-Francez ERG LNR Distribution") - - sns.histplot(data=lnr_distr["DS"]["grid"], kde=True, ax=axes[0][0]) - sns.histplot(data=lnr_distr["DS"]["star"], kde=True, ax=axes[0][1]) - sns.histplot(data=lnr_distr["DS"]["erg"], kde=True, ax=axes[0][2]) - sns.histplot(data=lnr_distr["SF"]["grid"], kde=True, ax=axes[1][0]) - sns.histplot(data=lnr_distr["SF"]["star"], kde=True, ax=axes[1][1]) - sns.histplot(data=lnr_distr["SF"]["erg"], kde=True, ax=axes[1][2]) -else: - fig, axes = plt.subplots(1, 3) - fig.set_figheight(5) - fig.set_figwidth(25) - - axes[0].set_title("DS/SF Grid LNR Distribution") - axes[1].set_title("DS/SF Star LNR Distribution") - axes[2].set_title("DS/SF ERG LNR Distribution") - axes[0].set_xlabel("Latency/Node Ratio (ticks/node)") - axes[1].set_xlabel("Latency/Node Ratio (ticks/node)") - axes[2].set_xlabel("Latency/Node Ratio (ticks/node)") - - sns.histplot(data={"Dijkstra-Scholten": lnr_distr["DS"]["grid"], "Shavit-Francez": lnr_distr["SF"]["grid"]}, kde=True, ax=axes[0], log_scale=True) - sns.histplot(data={"Dijkstra-Scholten": lnr_distr["DS"]["star"], "Shavit-Francez": lnr_distr["SF"]["star"]}, kde=True, ax=axes[1], log_scale=True) - sns.histplot(data={"Dijkstra-Scholten": lnr_distr["DS"]["erg"], "Shavit-Francez": lnr_distr["SF"]["erg"]}, kde=True, ax=axes[2], log_scale=True) +fig, axes = plt.subplots(2, 3) +fig.set_figheight(5) +fig.set_figwidth(25) + +axes[0][0].set_title("DS/SF Grid LNR Distribution") +axes[0][1].set_title("DS/SF Star LNR Distribution") +axes[0][2].set_title("DS/SF ERG LNR Distribution") +axes[0][0].set_xlabel("Latency/Node Ratio (ticks/node)") +axes[0][1].set_xlabel("Latency/Node Ratio (ticks/node)") +axes[0][2].set_xlabel("Latency/Node Ratio (ticks/node)") + +axes[0][0].set_title("Dijkstra-Scholten SNR Plot") +axes[0][1].set_title("Shavit-Francez SNR Plot") +axes[0][0].set_xlabel("Node Count") +axes[0][1].set_xlabel("Node Count") +axes[0][0].set_ylabel("Successive Simulations") +axes[0][1].set_ylabel("Successive Simulations") + +sns.histplot(data={"Dijkstra-Scholten": lnr_distr["DS"]["grid"], "Shavit-Francez": lnr_distr["SF"]["grid"]}, kde=True, ax=axes[0], log_scale=True) +sns.histplot(data={"Dijkstra-Scholten": lnr_distr["DS"]["star"], "Shavit-Francez": lnr_distr["SF"]["star"]}, kde=True, ax=axes[1], log_scale=True) +sns.histplot(data={"Dijkstra-Scholten": lnr_distr["DS"]["erg"], "Shavit-Francez": lnr_distr["SF"]["erg"]}, kde=True, ax=axes[2], log_scale=True) + +ds_grid_df = pd.DataFrame({ + "succ": [sum(snr_distrib["DS"]["grid"][node_count]) for node_count in snr_distrib["DS"]["grid"]], + "nodes": [node_count for node_count in snr_distrib["DS"]["grid"]] +}) + +ds_star_df = pd.DataFrame({ + "succ": [sum(snr_distrib["DS"]["star"][node_count]) for node_count in snr_distrib["DS"]["star"]], + "nodes": [node_count for node_count in snr_distrib["DS"]["star"]] +}) + +ds_erg_df = pd.DataFrame({ + "succ": [sum(snr_distrib["DS"]["erg"][node_count]) for node_count in snr_distrib["DS"]["erg"]], + "nodes": [node_count for node_count in snr_distrib["DS"]["erg"]] +}) + +sf_grid_df = pd.DataFrame({ + "succ": [sum(snr_distrib["SF"]["grid"][node_count]) for node_count in snr_distrib["SF"]["grid"]], + "nodes": [node_count for node_count in snr_distrib["SF"]["grid"]] +}) + +sf_star_df = pd.DataFrame({ + "succ": [sum(snr_distrib["SF"]["star"][node_count]) for node_count in snr_distrib["SF"]["star"]], + "nodes": [node_count for node_count in snr_distrib["SF"]["star"]] +}) + +sf_erg_df = pd.DataFrame({ + "succ": [sum(snr_distrib["SF"]["erg"][node_count]) for node_count in snr_distrib["SF"]["erg"]], + "nodes": [node_count for node_count in snr_distrib["SF"]["erg"]] +}) + +sns.lineplot(data=ds_grid_df, x="nodes", y="succ", ax=axes[1][0]) +sns.lineplot(data=ds_star_df, x="nodes", y="succ", ax=axes[1][0]) +sns.lineplot(data=ds_erg_df, x="nodes", y="succ", ax=axes[1][0]) + +sns.lineplot(data=ds_grid_df, x="nodes", y="succ", ax=axes[1][0]) +sns.lineplot(data=ds_star_df, x="nodes", y="succ", ax=axes[1][0]) +sns.lineplot(data=ds_erg_df, x="nodes", y="succ", ax=axes[1][0]) sns.despine() plt.show() -- GitLab From c5dd858f93c7c2614aebd0c2deffa6220258bba6 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Mon, 24 May 2021 11:04:57 +0300 Subject: [PATCH 42/47] updated analyze.py --- analyze.py | 82 ++++++++++++++++++++---------------------------------- 1 file changed, 30 insertions(+), 52 deletions(-) diff --git a/analyze.py b/analyze.py index 3c0f19e..4d52b45 100644 --- a/analyze.py +++ b/analyze.py @@ -196,64 +196,42 @@ for algo in lnr_distr: # }, indent=4)) fig, axes = plt.subplots(2, 3) -fig.set_figheight(5) +fig.set_figheight(10) fig.set_figwidth(25) -axes[0][0].set_title("DS/SF Grid LNR Distribution") -axes[0][1].set_title("DS/SF Star LNR Distribution") -axes[0][2].set_title("DS/SF ERG LNR Distribution") +axes[0][0].set_title("DS/SF Grid Topology LNR Distribution") +axes[0][1].set_title("DS/SF Star Topology LNR Distribution") +axes[0][2].set_title("DS/SF ERG Topology LNR Distribution") + axes[0][0].set_xlabel("Latency/Node Ratio (ticks/node)") axes[0][1].set_xlabel("Latency/Node Ratio (ticks/node)") axes[0][2].set_xlabel("Latency/Node Ratio (ticks/node)") -axes[0][0].set_title("Dijkstra-Scholten SNR Plot") -axes[0][1].set_title("Shavit-Francez SNR Plot") -axes[0][0].set_xlabel("Node Count") -axes[0][1].set_xlabel("Node Count") -axes[0][0].set_ylabel("Successive Simulations") -axes[0][1].set_ylabel("Successive Simulations") - -sns.histplot(data={"Dijkstra-Scholten": lnr_distr["DS"]["grid"], "Shavit-Francez": lnr_distr["SF"]["grid"]}, kde=True, ax=axes[0], log_scale=True) -sns.histplot(data={"Dijkstra-Scholten": lnr_distr["DS"]["star"], "Shavit-Francez": lnr_distr["SF"]["star"]}, kde=True, ax=axes[1], log_scale=True) -sns.histplot(data={"Dijkstra-Scholten": lnr_distr["DS"]["erg"], "Shavit-Francez": lnr_distr["SF"]["erg"]}, kde=True, ax=axes[2], log_scale=True) - -ds_grid_df = pd.DataFrame({ - "succ": [sum(snr_distrib["DS"]["grid"][node_count]) for node_count in snr_distrib["DS"]["grid"]], - "nodes": [node_count for node_count in snr_distrib["DS"]["grid"]] -}) - -ds_star_df = pd.DataFrame({ - "succ": [sum(snr_distrib["DS"]["star"][node_count]) for node_count in snr_distrib["DS"]["star"]], - "nodes": [node_count for node_count in snr_distrib["DS"]["star"]] -}) - -ds_erg_df = pd.DataFrame({ - "succ": [sum(snr_distrib["DS"]["erg"][node_count]) for node_count in snr_distrib["DS"]["erg"]], - "nodes": [node_count for node_count in snr_distrib["DS"]["erg"]] -}) - -sf_grid_df = pd.DataFrame({ - "succ": [sum(snr_distrib["SF"]["grid"][node_count]) for node_count in snr_distrib["SF"]["grid"]], - "nodes": [node_count for node_count in snr_distrib["SF"]["grid"]] -}) - -sf_star_df = pd.DataFrame({ - "succ": [sum(snr_distrib["SF"]["star"][node_count]) for node_count in snr_distrib["SF"]["star"]], - "nodes": [node_count for node_count in snr_distrib["SF"]["star"]] -}) - -sf_erg_df = pd.DataFrame({ - "succ": [sum(snr_distrib["SF"]["erg"][node_count]) for node_count in snr_distrib["SF"]["erg"]], - "nodes": [node_count for node_count in snr_distrib["SF"]["erg"]] -}) - -sns.lineplot(data=ds_grid_df, x="nodes", y="succ", ax=axes[1][0]) -sns.lineplot(data=ds_star_df, x="nodes", y="succ", ax=axes[1][0]) -sns.lineplot(data=ds_erg_df, x="nodes", y="succ", ax=axes[1][0]) - -sns.lineplot(data=ds_grid_df, x="nodes", y="succ", ax=axes[1][0]) -sns.lineplot(data=ds_star_df, x="nodes", y="succ", ax=axes[1][0]) -sns.lineplot(data=ds_erg_df, x="nodes", y="succ", ax=axes[1][0]) +sns.histplot(data={"Dijkstra-Scholten": lnr_distr["DS"]["grid"], "Shavit-Francez": lnr_distr["SF"]["grid"]}, kde=True, ax=axes[0][0], log_scale=True) +sns.histplot(data={"Dijkstra-Scholten": lnr_distr["DS"]["star"], "Shavit-Francez": lnr_distr["SF"]["star"]}, kde=True, ax=axes[0][1], log_scale=True) +sns.histplot(data={"Dijkstra-Scholten": lnr_distr["DS"]["erg"], "Shavit-Francez": lnr_distr["SF"]["erg"]}, kde=True, ax=axes[0][2], log_scale=True) + +axes[1][0].set_title("DS/SF Grid SNR Topology Plot") +axes[1][1].set_title("DS/SF Star SNR Topology Plot") +axes[1][2].set_title("DS/SF ERG SNR Topology Plot") + +axes[1][0].set_xlabel("Node Count") +axes[1][1].set_xlabel("Node Count") +axes[1][2].set_xlabel("Node Count") + +axes[1][0].set_ylabel("Successive Simulations (%)") +axes[1][1].set_ylabel("Successive Simulations (%)") +axes[1][2].set_ylabel("Successive Simulations (%)") + +topos = [ + "grid", + "star", + "erg" +] + +for i in range(3): + sns.lineplot(y=[100 * sum(snr_distrib["DS"][topos[i]][node_count]) / len(snr_distrib["DS"][topos[i]][node_count]) for node_count in snr_distrib["DS"][topos[i]]], x=[node_count for node_count in snr_distrib["DS"][topos[i]]], ax=axes[1][i], legend='brief', label="Dijkstra-Scholten") + sns.lineplot(y=[100 * sum(snr_distrib["SF"][topos[i]][node_count]) / len(snr_distrib["SF"][topos[i]][node_count]) for node_count in snr_distrib["SF"][topos[i]]], x=[node_count for node_count in snr_distrib["SF"][topos[i]]], ax=axes[1][i], legend='brief', label="Shavit-Francez") sns.despine() plt.show() -- GitLab From 0d0c3943711184f00de2be3f3a8ee5b9e41ff01d Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Mon, 24 May 2021 11:29:23 +0300 Subject: [PATCH 43/47] updated analyze.py --- analyze.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/analyze.py b/analyze.py index 4d52b45..5480e19 100644 --- a/analyze.py +++ b/analyze.py @@ -234,4 +234,5 @@ for i in range(3): sns.lineplot(y=[100 * sum(snr_distrib["SF"][topos[i]][node_count]) / len(snr_distrib["SF"][topos[i]][node_count]) for node_count in snr_distrib["SF"][topos[i]]], x=[node_count for node_count in snr_distrib["SF"][topos[i]]], ax=axes[1][i], legend='brief', label="Shavit-Francez") sns.despine() -plt.show() +plt.savefig("lnr_snr.png", dpi=200) + -- GitLab From 1d07602372e28287c4e4c4f03b4279e9399c37ff Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Mon, 24 May 2021 11:41:21 +0300 Subject: [PATCH 44/47] updated analyze.py --- analyze.py | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/analyze.py b/analyze.py index 5480e19..1d4d896 100644 --- a/analyze.py +++ b/analyze.py @@ -91,7 +91,8 @@ for fpath in os.listdir("bench_dump/simdump/"): "cpr": cpr, "wpr": wpr, "cppn": cppn, - "wppn": wppn + "wppn": wppn, + "cwpr": cpr + wpr })) elif algo == "DS": metrics["DS"][topo].append((nodes, { @@ -236,3 +237,46 @@ for i in range(3): sns.despine() plt.savefig("lnr_snr.png", dpi=200) +fig, axes = plt.subplots(2, 3) +fig.set_figheight(10) +fig.set_figwidth(25) + +axes[0][0].set_title("DS/SF Grid Control Package Ratio Plot") +axes[0][1].set_title("DS/SF Star Control Package Ratio Plot") +axes[0][2].set_title("DS/SF ERG Control Package Ratio Plot") + +axes[0][0].set_xlabel("Node Count") +axes[0][1].set_xlabel("Node Count") +axes[0][2].set_xlabel("Node Count") + +axes[0][0].set_ylabel("Average CPR") +axes[0][1].set_ylabel("Average CPR") +axes[0][2].set_ylabel("Average CPR") + +for i in range(3): + _top = topos[i] + cprs = {} + c_wprs = {} + + for x in metrics["DS"][_top]: + node_count = x[0] + cpr = x[1]["cpr"] + + if node_count not in cprs: + cprs[node_count] = [] + + cprs[node_count].append(cpr) + + for x in metrics["SF"][_top]: + node_count = x[0] + cw_pr = x[1]["cwpr"] + + if node_count not in c_wprs: + c_wprs[node_count] = [] + + c_wprs[node_count].append(cw_pr) + + sns.lineplot(y=[100 * sum(cprs[node_count]) / len(cprs[node_count]) for node_count in cprs], x=[node_count for node_count in cprs], ax=axes[0][i], legend='brief', label="Dijkstra-Scholten") + sns.lineplot(y=[100 * sum(c_wprs[node_count]) / len(c_wprs[node_count]) for node_count in c_wprs], x=[node_count for node_count in c_wprs], ax=axes[0][i], legend='brief', label="Shavit-Francez") + +plt.plot() \ No newline at end of file -- GitLab From ed932f8b2427a1899dcaddef6bacf321576848ef Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Mon, 24 May 2021 13:11:43 +0300 Subject: [PATCH 45/47] updated analyze.py --- analyze.py | 95 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 87 insertions(+), 8 deletions(-) diff --git a/analyze.py b/analyze.py index 1d4d896..581975e 100644 --- a/analyze.py +++ b/analyze.py @@ -231,8 +231,8 @@ topos = [ ] for i in range(3): - sns.lineplot(y=[100 * sum(snr_distrib["DS"][topos[i]][node_count]) / len(snr_distrib["DS"][topos[i]][node_count]) for node_count in snr_distrib["DS"][topos[i]]], x=[node_count for node_count in snr_distrib["DS"][topos[i]]], ax=axes[1][i], legend='brief', label="Dijkstra-Scholten") - sns.lineplot(y=[100 * sum(snr_distrib["SF"][topos[i]][node_count]) / len(snr_distrib["SF"][topos[i]][node_count]) for node_count in snr_distrib["SF"][topos[i]]], x=[node_count for node_count in snr_distrib["SF"][topos[i]]], ax=axes[1][i], legend='brief', label="Shavit-Francez") + sns.lineplot(y=[100 * sum(snr_distrib["DS"][topos[i]][node_count]) / len(snr_distrib["DS"][topos[i]][node_count]) for node_count in snr_distrib["DS"][topos[i]]], x=[node_count for node_count in snr_distrib["DS"][topos[i]]], ax=axes[1][i], legend='brief', label="Dijkstra-Scholten", alpha=0.7) + sns.lineplot(y=[100 * sum(snr_distrib["SF"][topos[i]][node_count]) / len(snr_distrib["SF"][topos[i]][node_count]) for node_count in snr_distrib["SF"][topos[i]]], x=[node_count for node_count in snr_distrib["SF"][topos[i]]], ax=axes[1][i], legend='brief', label="Shavit-Francez", alpha=0.7) sns.despine() plt.savefig("lnr_snr.png", dpi=200) @@ -249,14 +249,19 @@ axes[0][0].set_xlabel("Node Count") axes[0][1].set_xlabel("Node Count") axes[0][2].set_xlabel("Node Count") -axes[0][0].set_ylabel("Average CPR") -axes[0][1].set_ylabel("Average CPR") -axes[0][2].set_ylabel("Average CPR") +axes[0][0].set_ylabel("Average CPR (%)") +axes[0][1].set_ylabel("Average CPR (%)") +axes[0][2].set_ylabel("Average CPR (%)") + +# axes[0][0].set_yscale("log") +# axes[0][1].set_yscale("log") +# axes[0][2].set_yscale("log") for i in range(3): _top = topos[i] cprs = {} c_wprs = {} + c_prs = {} for x in metrics["DS"][_top]: node_count = x[0] @@ -269,14 +274,88 @@ for i in range(3): for x in metrics["SF"][_top]: node_count = x[0] + cw_pr = x[1]["cwpr"] + c_pr = x[1]["cpr"] if node_count not in c_wprs: c_wprs[node_count] = [] + if node_count not in c_prs: + c_prs[node_count] = [] + c_wprs[node_count].append(cw_pr) + c_prs[node_count].append(c_pr) + + sns.lineplot(y=[sum(cprs[node_count]) / len(cprs[node_count]) for node_count in cprs], x=[node_count for node_count in cprs], ax=axes[0][i], legend='brief', label="Dijkstra-Scholten (CPR)") + sns.lineplot(y=[sum(c_prs[node_count]) / len(c_prs[node_count]) for node_count in c_prs], x=[node_count for node_count in c_prs], ax=axes[0][i], legend='brief', label="Shavit-Francez (CPR)") + sns.lineplot(y=[sum(c_wprs[node_count]) / len(c_wprs[node_count]) for node_count in c_wprs], x=[node_count for node_count in c_wprs], ax=axes[0][i], legend='brief', label="Shavit-Francez (CWPR)") + +axes[1][0].set_title("Dijkstra-Scholten Average CPPN Ratio Plot") +axes[1][1].set_title("Shavit-Francez Average CPPN Ratio Plot") +axes[1][2].set_title("Shavit-Francez Average WPPN Ratio Plot") + +axes[1][0].set_xlabel("Node Count") +axes[1][1].set_xlabel("Node Count") +axes[1][2].set_xlabel("Node Count") + +axes[1][0].set_ylabel("Average CPPN (control packets/node)") +axes[1][1].set_ylabel("Average CPPN (control packets/node)") +axes[1][2].set_ylabel("Average WPPN (wave packets/node)") + +def get_average_cppn(algo, topo): + cppns = {} + + for x in metrics[algo][topo]: + node_count = x[0] + cppn = x[1]["cppn"] + + if node_count not in cppns: + cppns[node_count] = [] + + cppns[node_count].append(cppn) - sns.lineplot(y=[100 * sum(cprs[node_count]) / len(cprs[node_count]) for node_count in cprs], x=[node_count for node_count in cprs], ax=axes[0][i], legend='brief', label="Dijkstra-Scholten") - sns.lineplot(y=[100 * sum(c_wprs[node_count]) / len(c_wprs[node_count]) for node_count in c_wprs], x=[node_count for node_count in c_wprs], ax=axes[0][i], legend='brief', label="Shavit-Francez") + return ([sum(cppns[node_count]) / len(cppns[node_count]) for node_count in cppns], [node_count for node_count in cppns]) + +def get_average_wppn(topo): + wppns = {} + + for x in metrics["SF"][topo]: + node_count = x[0] + wppn = x[1]["wppn"] + + if node_count not in wppns: + wppns[node_count] = [] + + wppns[node_count].append(wppn) + + return ([sum(wppns[node_count]) / len(wppns[node_count]) for node_count in wppns], [node_count for node_count in wppns]) + +ds_grid_cppns = get_average_cppn("DS", "grid") +ds_star_cppns = get_average_cppn("DS", "star") +ds_erg_cppns = get_average_cppn("DS", "erg") + +sf_grid_cppns = get_average_cppn("SF", "grid") +sf_star_cppns = get_average_cppn("SF", "star") +sf_erg_cppns = get_average_cppn("SF", "erg") + +sf_grid_wppns = get_average_wppn("grid") +sf_star_wppns = get_average_wppn("star") +sf_erg_wppns = get_average_wppn("erg") + +sns.lineplot(y=ds_grid_cppns[0], x=ds_grid_cppns[1], ax=axes[1][0], legend='brief', label="Grid") +sns.lineplot(y=ds_star_cppns[0], x=ds_star_cppns[1], ax=axes[1][0], legend='brief', label="Star") +sns.lineplot(y=ds_erg_cppns[0], x=ds_erg_cppns[1], ax=axes[1][0], legend='brief', label="ERG") + +sns.lineplot(y=sf_grid_cppns[0], x=sf_grid_cppns[1], ax=axes[1][1], legend='brief', label="Grid") +sns.lineplot(y=sf_star_cppns[0], x=sf_star_cppns[1], ax=axes[1][1], legend='brief', label="Star") +sns.lineplot(y=sf_erg_cppns[0], x=sf_erg_cppns[1], ax=axes[1][1], legend='brief', label="ERG") + +sns.lineplot(y=sf_grid_wppns[0], x=sf_grid_wppns[1], ax=axes[1][2], legend='brief', label="Grid") +sns.lineplot(y=sf_star_wppns[0], x=sf_star_wppns[1], ax=axes[1][2], legend='brief', label="Star") +sns.lineplot(y=sf_erg_wppns[0], x=sf_erg_wppns[1], ax=axes[1][2], legend='brief', label="ERG") + +sns.despine() -plt.plot() \ No newline at end of file +plt.savefig("cpr_cppn_wpr_wppn.png", dpi=200) +# plt.show() \ No newline at end of file -- GitLab From 0f39ecf14cf370824f196b1fe6eb857f1a7ea4ca Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Mon, 24 May 2021 17:07:11 +0300 Subject: [PATCH 46/47] updated analyze.py --- analyze.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/analyze.py b/analyze.py index 581975e..58befbf 100644 --- a/analyze.py +++ b/analyze.py @@ -4,13 +4,11 @@ import time import json import pickle import random -from typing import Text import pandas as pd import seaborn as sns import networkx as nx import matplotlib.pyplot as plt from datetime import datetime as dt -from networkx.drawing.nx_pydot import graphviz_layout from Ahc import Topology from graph import ERG, Grid, Star @@ -262,6 +260,7 @@ for i in range(3): cprs = {} c_wprs = {} c_prs = {} + wprs = {} for x in metrics["DS"][_top]: node_count = x[0] @@ -277,6 +276,7 @@ for i in range(3): cw_pr = x[1]["cwpr"] c_pr = x[1]["cpr"] + wpr = x[1]["wpr"] if node_count not in c_wprs: c_wprs[node_count] = [] @@ -284,11 +284,16 @@ for i in range(3): if node_count not in c_prs: c_prs[node_count] = [] + if node_count not in wprs: + wprs[node_count] = [] + c_wprs[node_count].append(cw_pr) c_prs[node_count].append(c_pr) + wprs[node_count].append(wpr) sns.lineplot(y=[sum(cprs[node_count]) / len(cprs[node_count]) for node_count in cprs], x=[node_count for node_count in cprs], ax=axes[0][i], legend='brief', label="Dijkstra-Scholten (CPR)") sns.lineplot(y=[sum(c_prs[node_count]) / len(c_prs[node_count]) for node_count in c_prs], x=[node_count for node_count in c_prs], ax=axes[0][i], legend='brief', label="Shavit-Francez (CPR)") + sns.lineplot(y=[sum(wprs[node_count]) / len(wprs[node_count]) for node_count in wprs], x=[node_count for node_count in wprs], ax=axes[0][i], legend='brief', label="Shavit-Francez (WPR)") sns.lineplot(y=[sum(c_wprs[node_count]) / len(c_wprs[node_count]) for node_count in c_wprs], x=[node_count for node_count in c_wprs], ax=axes[0][i], legend='brief', label="Shavit-Francez (CWPR)") axes[1][0].set_title("Dijkstra-Scholten Average CPPN Ratio Plot") -- GitLab From 3439eef2ac88aec4118c228f4bb9fbbbf4da59d9 Mon Sep 17 00:00:00 2001 From: Ozan Sazak Date: Mon, 24 May 2021 21:38:11 +0300 Subject: [PATCH 47/47] gif generation --- cli.py | 6 ++++ simulator_ds.py | 82 ++++++++++++++++++++++++++++++------------------- 2 files changed, 56 insertions(+), 32 deletions(-) diff --git a/cli.py b/cli.py index b238d5f..2f47229 100644 --- a/cli.py +++ b/cli.py @@ -35,6 +35,9 @@ parser.add_argument("--hard_stop_max_tick", type=int, default=300) parser.add_argument("--hard_stop_prob", type=float, default=0.5) parser.add_argument("--no_realtime_plot", action="store_true", default=False) +parser.add_argument("--save_tick_plots", action="store_true", default=False) +parser.add_argument("--tick_plots_save_dir", type=str, default="simdump") +parser.add_argument("--generate_gif", action="store_true", default=False) sp = parser.add_subparsers() @@ -56,4 +59,7 @@ if __name__ == "__main__": args = parser.parse_args() print(f"[+] Network type: {args.network_type}") + if args.generate_gif: + args.save_tick_plots = True + algorithm_handlers[args.algorithm](args) \ No newline at end of file diff --git a/simulator_ds.py b/simulator_ds.py index f9bab88..2b7e4c2 100644 --- a/simulator_ds.py +++ b/simulator_ds.py @@ -16,7 +16,24 @@ from graph import ERG, Grid, Star from dijkstra_scholten import DijkstraScholtenAdHocNode, DSAHCNodeSimulationStatus from Channels import P2PFIFOPerfectChannel +import glob +from PIL import Image + +# # filepaths +# fp_in = "/path/to/image_*.png" +# fp_out = "/path/to/image.gif" + +def make_gif(from_path: str, to_path: str, out_file: str, duration: int) -> None: + # https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif + _images = sorted(glob.glob(from_path)) + print(_images) + img, *imgs = [Image.open(f) for f in _images] + img.save(fp=f"{to_path}/{out_file}", format='GIF', append_images=imgs, + save_all=True, duration=duration, loop=0) + def run_dijkstra_scholten_simulation(args): + ts = dt.now().timestamp() + if args.network_type == "erg": N = ERG(args.node_count, args.node_connectivity) total_nodes = args.node_count @@ -27,6 +44,12 @@ def run_dijkstra_scholten_simulation(args): N = Star(args.slave_count, master_is_root=args.master_is_root) total_nodes = args.slave_count + 1 + if args.save_tick_plots: + tick_plots_save_path = f"{args.tick_plots_save_dir}/DS_{args.network_type}_{total_nodes}_{ts}/" + os.mkdir(tick_plots_save_path) + + print(f"++ Tick plots will be saved to: {tick_plots_save_path}") + if args.run_until_termination: args.simulation_ticks = 10**10 @@ -57,8 +80,6 @@ def run_dijkstra_scholten_simulation(args): } print(topo_context) - # N.plot() - # plt.show() topo = Topology() topo.construct_from_graph(N.G, DijkstraScholtenAdHocNode, P2PFIFOPerfectChannel, context=topo_context) @@ -171,17 +192,12 @@ def run_dijkstra_scholten_simulation(args): (((stats["df"]["control_packets_sent"].sum() + control_packets_sent) / total_pkgs_sent_cum) if total_pkgs_sent_cum > 0 else 0) * 100 ] - # stats["dead_nodes"].append(num_dead_nodes) - # stats["active_nodes"].append(num_nodes_active) - # stats["packages_in_transmit"].append(packages_sent) graphs.append({ "edges": T.edges(), "nodes": T.nodes(), }) - - # axes.scatter(x=t, y=num_nodes_active) - if not args.no_realtime_plot: + if not args.no_realtime_plot or args.save_tick_plots: axes[0][0].cla() axes[0][1].cla() axes[0][2].cla() @@ -189,25 +205,29 @@ def run_dijkstra_scholten_simulation(args): axes[1][1].cla() axes[1][2].cla() - sns.lineplot(data=stats["df"]["active_nodes"], ax=axes[0][0], color="orange") - sns.lineplot(data=stats["df"]["dead_nodes"], ax=axes[0][0], color="blue") - sns.lineplot(data=stats["df"]["packets_in_transmit"], ax=axes[0][1], color="purple") - sns.lineplot(data=stats["df"]["control_packets_sent"], ax=axes[0][1], color="green") - sns.lineplot(data=stats["df"]["control_total_cumulative_ratio"], ax=axes[1][0], color="mediumslateblue") - sns.lineplot(data=stats["df"]["control_basic_instant_ratio"], ax=axes[1][1], color="red") - # sns.lineplot(data=stats["active_nodes"], ax=axes, color="red") - # sns.lineplot(data=stats["dead_nodes"], ax=axes, color="mediumslateblue") - # sns.lineplot(data=stats["packages_in_transmit"], ax=axes, color="green") + axes[0][0].set_title("Active/Dead Nodes") + axes[0][0].set_xlabel(f"Simulation Ticks ({args.ms_per_tick}ms/tick)") + axes[0][0].set_ylabel(f"Node Count") - # pos = nx.spring_layout(T) - # nx.draw_networkx_nodes(T , pos, nodelist=[N.root], node_color='red', ax=axes[0][2]) - # nx.draw_networkx_nodes(T , pos, nodelist=[i for i in T.nodes() if i != N.root], node_color='mediumslateblue', ax=axes[0][2]) - # nx.draw_networkx_edges(T , pos, ax=axes[0][2]) + axes[0][1].set_title("Packets in Transmit") + axes[0][1].set_xlabel(f"Simulation Ticks ({args.ms_per_tick}ms/tick)") + axes[0][1].set_ylabel(f"Packet Count") - # pos = graphviz_layout(T, prog="twopi") - # nx.draw(T, ax=axes[0][2], pos=pos) + axes[1][0].set_title("Control Packet Ratio") + axes[1][0].set_xlabel(f"CPR ({args.ms_per_tick}ms/tick)") + axes[1][0].set_ylabel(f"CPR (control packets/total packets)") + + axes[1][1].set_title("Instant Control Packet Ratio") + axes[1][1].set_xlabel(f"Simulation Ticks ({args.ms_per_tick}ms/tick)") + axes[1][1].set_ylabel(f"CPR (control packets/total packets)") + + sns.lineplot(data=stats["df"]["active_nodes"], ax=axes[0][0], color="orange", legend='brief', label="Active nodes") + sns.lineplot(data=stats["df"]["dead_nodes"], ax=axes[0][0], color="blue", legend='brief', label="Dead nodes") + sns.lineplot(data=stats["df"]["packets_in_transmit"], ax=axes[0][1], color="purple", legend='brief', label="Basic packets") + sns.lineplot(data=stats["df"]["control_packets_sent"], ax=axes[0][1], color="green", legend='brief', label="Control packets") + sns.lineplot(data=stats["df"]["control_total_cumulative_ratio"], ax=axes[1][0], color="mediumslateblue") + sns.lineplot(data=stats["df"]["control_basic_instant_ratio"], ax=axes[1][1], color="red") - # node_color = ["red" if list(T.nodes)[i] == N.root else ("mediumslateblue" if list(T.nodes)[i] not in alive_nodes else "green") for i in range(total_nodes)] nx.draw(T, ax=axes[0][2], with_labels=True, node_color=node_color) if args.network_type == "grid": @@ -218,6 +238,9 @@ def run_dijkstra_scholten_simulation(args): plt.pause(0.0005) + if args.save_tick_plots: + plt.savefig(tick_plots_save_path + f"{str(t).zfill(3)}.png", dpi=160) + if break_this_tick: break @@ -225,14 +248,6 @@ def run_dijkstra_scholten_simulation(args): except KeyboardInterrupt: pass - ts = dt.now().timestamp() - - # axes.cla() - # sns.lineplot(data=stats["active_nodes"], ax=axes) - # sns.kdeplot(data=stats["active_nodes"], ax=axes) - - #plt.plot(stats["packages_in_transmit"]) - axes[0][0].cla() axes[0][1].cla() axes[0][2].cla() @@ -269,3 +284,6 @@ def run_dijkstra_scholten_simulation(args): plt.show() print(f"\n{reason} [{t - stats['terminated_on_tick'] if stats['terminated_on_tick'] is not None else None}]") + + if args.generate_gif: + make_gif(f"{tick_plots_save_path}/*.png", tick_plots_save_path, "animation.gif", t * 20) \ No newline at end of file -- GitLab