Init ESDS repository

This commit is contained in:
Loic Guegan 2022-06-09 21:48:32 +02:00
commit c2e6aad09f
106 changed files with 2638 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
__pycache__
esds.debug

30
README.md Normal file
View file

@ -0,0 +1,30 @@
# ESDS: An Extensible Simulator For Distributed Systems and Cyber-Physical Systems
**What is ESDS ?**
It is a short learning curve and coarse-grain network simulator. It contains the essential building blocks for the simulation of *Cyber-Physical Systems* (CPS) and *Wireless Sensors Networks* (WSN) scenarios. It was originally designed to improve node implementation flexibility/faithfulness and mitigate the learning curve compare to existing network simulators.
**What ESDS does not implements?**
- Network protocols (such as IP/TCP/UDP)
- Wireless physical layer models
- Routing algorithms
- And much more!
**Features:**
- The implementation of node behavior can be any python file that you have wrote
- Wireless interferences detection (not modelization)
- Simulation can be interrupted at constant intervals to perform custom actions (such as implement nodes mobility)
**Current API:**
- `api.args`
- `api.send(interface, data,size, dst)`
- `api.sendt(interface, data,size, dst,timeout)`
- `api.receive(interface)`
- `api.receivet(interface,timeout)`
- `api.clock()`
- `api.log(msg)`
- `api.wait(duration)`
- `api.turn_off(duration)`
- *More details in [example/sender.py](example/sender.py)*
**Documentation:** cf. `example/` and `tests/`

581
esds.py Normal file
View file

@ -0,0 +1,581 @@
#!/usr/bin/env python
import numpy as np
import threading,importlib,queue,sys,time
class Node:
available_node_id=0
def __init__(self,src):
"""
"""
self.node_id=Node.available_node_id
Node.available_node_id+=1 # Refresh node id
self.src=src # Store the node source code
self.args=None # Store the node arguments (passed through Simulator.create_node()
self.rargs=None # Store the requests arguments
self.plugins=list() # Contains all registered node plugins
self.rqueue=queue.Queue() # Receive simulator acknowledgments
self.chest={"state":"running", "turned_on":True, "request": None, "interfaces":{"wlan0":queue.Queue(), "eth0":queue.Queue()}, "interfaces_queue_size":{"wlan0":0,"eth0":0}}
self.chest_lock=threading.Lock() # To access/modify self.chest
def plugin_register(self,plugin):
self.plugins.append(plugin)
def plugin_notify(self,reason,args):
"""
This function strives to avoid using Python specific features
"""
for p in self.plugins:
if reason == "receive_return" or reason == "receivet_return":
p.on_receive_return(args[0],args[1],args[2],args[3])
if reason == "send_call":
p.on_send_call(args[0],args[1],args[2],args[3])
if reason == "send_return":
p.on_send_return(args[0],args[1],args[2],args[3],args[4])
if reason == "terminated":
p.on_terminated()
def __getitem__(self,key):
self.chest_lock.acquire()
value=self.chest[key]
self.chest_lock.release()
return value
def __setitem__(self,key,value):
self.chest_lock.acquire()
value=self.chest[key]=value
self.chest_lock.release()
def log(self,msg):
self.rargs=msg
self["request"]="log"
self["state"]="call"
self.wait_ack(["log"])
def read(self, register):
self["request"]="read"
self.rargs=register
self["state"]="call"
ack=self.wait_ack(["read"])
return ack[1]
def wait(self,duration):
self.rargs=duration
self["request"]="timeout_add"
self["state"]="call"
self.wait_ack(["timeout_add"])
self["state"]="pending"
self.wait_ack(["timeout"])
def wait_end(self):
self["request"]="wait_end"
self["state"]="request"
self.wait_ack(["wait_end"])
self.wait_ack(["sim_end"])
def turn_off(self):
self["turned_on"]=False
self["request"]="turn_off"
self["state"]="call"
self.wait_ack(["turn_off"])
def turn_on(self):
self["turned_on"]=True
self["request"]="turn_on"
self["state"]="call"
self.wait_ack(["turn_on"])
def send(self, interface, data, datasize, dst):
self.plugin_notify("send_call",(interface,data,datasize,dst))
self.rargs=(interface, data, datasize, dst)
self["request"]="send"
self["state"]="request"
ack=self.wait_ack(["send","send_cancel"])
self.plugin_notify("send_return",(interface,data,datasize,dst,ack[1]))
return ack[1]
def receive(self,interface):
self["request"]="receive"
self.rargs=interface
self["state"]="request"
self.wait_ack(["receive"])
data,start_at,end_at=self["interfaces"][interface].get()
self.plugin_notify("receive_return",(interface,data,start_at,end_at))
return (0,data)
def sendt(self, interface, data, datasize, dst, timeout):
self.rargs=timeout
self["request"]="timeout_add"
self["state"]="call"
self.wait_ack(["timeout_add"])
self.rargs=(interface, data, datasize, dst)
self["request"]="send"
self["state"]="request"
ack=self.wait_ack(["send","timeout","send_cancel"])
if ack[0] == "timeout":
self["request"]="send_cancel"
self["state"]="call"
self.wait_ack(["send_cancel"])
return -1
self["request"]="timeout_remove"
self["state"]="call"
self.wait_ack(["timeout_remove"])
return ack[1]
def receivet(self,interface, timeout):
self.rargs=timeout
self["request"]="timeout_add"
self["state"]="call"
self.wait_ack(["timeout_add"])
self["request"]="receive"
self.rargs=interface
self["state"]="request"
ack=self.wait_ack(["receive","timeout"])
if ack[0] == "timeout":
return (-1,None)
self["request"]="timeout_remove"
self["state"]="call"
self.wait_ack(["timeout_remove"])
data,start_at,end_at=self["interfaces"][interface].get()
self.plugin_notify("receivet_return",(interface,data,start_at,end_at))
return (0,data)
def wait_ack(self, ack_types):
"""
Wait for specific acks from the request queue (rqueue)
"""
ack_buffer=list() # To filter ack
ack=None
while True:
ack=self.rqueue.get() # Wait for simulator acknowledgments
if ack[0] not in ack_types:
ack_buffer.append(ack)
else:
break
# Push back the filtered ack
for cur_ack in ack_buffer:
self.rqueue.put(cur_ack)
return(ack)
def sync(self):
"""
Wait until node stop running
"""
while self["state"] == "running":
pass
def run(self,args):
"""
Load and run the user program
"""
self.node=importlib.import_module(self.src)
self.args=args # Allow access to arguments
self.node.execute(self)
self["state"]="terminated"
class Simulator:
"""
Flow-Level Discrete Event Simulator for Cyber-Physical Systems
The general format for an event is (type,timestamp,event,priority)
Event types:
- 0 send (0,timestamp,(src,dst,interface,data,datasize,duration,datasize_remaining), 1)
- 1 timeout (1,timestamp,node_id,4)
- 2 breakpoint_manual (3,timestamp,0,0)
- 3 breakpoint_auto (4,timestamp,0,0)
Very important: when the simulator wakes up a node (changing is state to running)
data that should be received by that node on the current simulated time SHOULD be in the queue!
Thus, the send event must be handle before the other event (priority equals to 1). Otherwise plugings such as the power states
one may not gives accurate results because of missing entries in the nodes received queues.
"""
def __init__(self,B,L):
self.B=B
self.L=L
self.nodes=list()
self.sharing=np.zeros(len(B))
self.events=np.empty((0,4),dtype=object)
self.events_dirty=True # For optimization reasons
self.startat=-1
self.time=0
self.debug_file_path="./esds.debug"
self.precision=".3f"
self.interferences=True
self.wait_end_nodes=list() # Keep track of nodes that wait for the end of the simulation
self.time_truncated=format(self.time,self.precision) # Truncated version is used in log print
def update_network(self,B,L):
for event in self.events:
if int(event[0]) == 0:
cur_event=event[2]
ts=float(event[1])
src_id,dst_id,interface, data, datasize,duration, datasize_remaining,start_at=cur_event
new_bw=B[int(src_id),int(dst_id)]
old_bw=self.B[int(src_id),int(dst_id)]
new_lat=L[int(src_id),int(dst_id)]
old_lat=self.L[int(src_id),int(dst_id)]
if new_bw != old_bw or new_lat != old_lat:
new_datasize_remaining=float(datasize_remaining)*((ts-self.time)/float(duration))
if new_datasize_remaining > 0:
latency_factor=new_datasize_remaining/float(datasize)
if interface == "wlan0":
new_duration=new_datasize_remaining*8/new_bw+new_lat*latency_factor
else:
new_duration=new_datasize_remaining*8/(new_bw/self.sharing[int(dst_id)])+new_lat*latency_factor
# print("DataSize {}B | DataSize Remaining {}B | Old duration {}s | New duration {}s | Latency {}s".format(datasize,new_datasize_remaining,duration,new_duration,new_lat))
event[1]=self.time+new_duration
event[2][6]=new_datasize_remaining
event[2][5]=new_duration
self.B=B
self.L=L
def debug(self):
"""
Log all the informations for debugging
"""
stdout_save = sys.stdout
with open(self.debug_file_path, "a") as debug_file:
sys.stdout = debug_file
print("-----------------------------------------------")
print("Started since {}s".format(round(time.time()-self.startat,2)))
print("Simulated time {}s (or more precisely {}s)".format(self.time_truncated,self.time))
states=dict()
timeout_mode=list()
sharing=dict()
for node in self.nodes:
s=node["state"]
states[s]=states[s]+1 if s in states else 1
if self.sharing[node.node_id] > 0:
sharing["n"+str(node.node_id)]=str(int(self.sharing[node.node_id]))
print("Node number per state: ",end="")
for key in states:
print(key+"="+str(states[key]), end=" ")
print("\nNode sharing: ",end="")
for node_id in sharing:
print(node_id+"="+sharing[node_id], end=" ")
print("\nIds of node in timeout mode: ", end="")
for n in timeout_mode:
print(n,end=" ")
print("\nSorted events list:")
print(self.events)
sys.stdout = stdout_save
def create_node(self, src, args=None):
"""
Create a node thread and run it
"""
node=Node(src)
self.nodes.append(node)
thread=threading.Thread(target=node.run, daemon=False,args=[args])
thread.start()
def log(self,msg,node=None):
src = "esds" if node is None else "n"+str(node)
print("[t="+str(self.time_truncated)+",src="+src+"] "+msg)
def sort_events(self):
"""
Sort the events by timestamp and priorities
"""
sorted_indexes=np.lexsort((self.events[:,3],self.events[:,1]))
self.events=self.events[sorted_indexes]
def sync_node(self,node):
"""
Process all call request and wait for Node.sync() to return
"""
node.sync()
while node["state"] == "call":
if node["request"] == "log":
self.log(node.rargs,node=node.node_id)
node["state"]="running"
node.rqueue.put(("log",0))
elif node["request"] == "timeout_add":
self.add_event(1,self.time+node.rargs,node.node_id,priority=3)
node["state"]="running"
node.rqueue.put(("timeout_add",0))
elif node["request"] == "timeout_remove":
selector=list()
for event in self.events:
if event[0] == 1 and event[2]==node.node_id:
selector.append(True)
else:
selector.append(False)
self.events=self.events[~np.array(selector)]
node["state"]="running"
node.rqueue.put(("timeout_remove",0))
elif node["request"] == "read":
node["state"]="running"
if node.rargs == "clock":
node.rqueue.put(("read",self.time))
elif node.rargs == "wlan0_ncom":
count=0
# Count number of communication on wlan0
for event in self.events:
if event[0] == 0 and event[2][1] == node.node_id and event[2][2] == "wlan0":
count+=1
node.rqueue.put(("read",count))
elif node.rargs == "eth0_ncom":
count=0
# Count number of communication on eth0
for event in self.events:
if event[0] == 0 and event[2][1] == node.node_id and event[2][2] == "eth0":
count+=1
node.rqueue.put(("read",count))
else:
node.rqueue.put(("read",0)) # Always return 0 if register is unknown
elif node["request"] == "turn_on":
node["state"]="running"
node.rqueue.put(("turn_on",0))
self.log("Turned on",node=node.node_id)
elif node["request"] == "turn_off":
selector_wlan0=list()
selector_other=list()
for event in self.events:
if event[0]==0 and int(event[2][1])==node.node_id:
if event[2][2] == "wlan0":
selector_wlan0.append(True)
selector_other.append(False)
else:
selector_wlan0.append(False)
selector_other.append(True)
else:
selector_wlan0.append(False)
selector_other.append(False)
# Informed sender to cancel send
for event in self.events[selector_other]:
sender=self.nodes[int(event[2][0])]
sender["state"]="running"
sender.rqueue.put(("send_cancel",2))
# Remove communications
if(len(self.events) != 0):
self.events=self.events[~(np.array(selector_wlan0)|np.array(selector_other))]
self.sharing[node.node_id]=0 # Sharing goes back to zero
node["state"]="running"
node.rqueue.put(("turn_off",0))
self.log("Turned off",node=node.node_id)
elif node["request"] == "send_cancel":
selector=list()
for event in self.events:
if event[0]==0 and int(event[2][0]) == node.node_id:
selector.append(True)
if event[2][2] != "wlan0":
self.update_sharing(int(event[2][1]),-1)
else:
selector.append(False)
self.events=self.events[~np.array(selector)]
node["state"]="running"
node.rqueue.put(("send_cancel",0))
node.sync()
def update_sharing(self, dst, amount):
"""
Manage bandwidth sharing on wired interfaces
"""
sharing=self.sharing[dst]
new_sharing=sharing+amount
for event in self.events:
if event[0] == 0 and event[2][2] != "wlan0" and int(event[2][1]) == dst:
remaining=event[1]-self.time
if remaining > 0:
remaining=remaining/sharing if sharing>1 else remaining # First restore sharing
remaining=remaining*new_sharing if new_sharing > 1 else remaining # Then apply new sharing
event[2][5]=remaining # Update duration
event[1]=self.time+remaining # Update timestamp
self.sharing[dst]=new_sharing
self.sort_events()
def handle_interferences(self,sender,receiver):
"""
Interferences are detected by looking for conflicts between
new events and existing events.
"""
status=False
selector=list()
notify=set()
for event in self.events:
event_type=event[0]
com=event[2]
if event_type==0 and com[2] == "wlan0":
com_sender=int(com[0])
com_receiver=int(com[1])
select=False
if receiver==com_sender:
status=True
notify.add(receiver)
elif receiver==com_receiver:
status=True
select=True
notify.add(receiver)
if sender==com_receiver and com_sender != com_receiver:
select=True
notify.add(sender)
selector.append(select)
else:
selector.append(False)
if len(selector) != 0:
self.events=self.events[~np.array(selector)]
for node in notify:
self.log("Interferences on wlan0",node=node)
return status
def sync_event(self, node):
"""
Collect events from the nodes
"""
if node["state"] == "request":
if node["request"] == "send":
node["state"]="pending"
interface, data, datasize, dst=node.rargs
self.communicate(interface, node.node_id, dst, data, datasize)
elif node["request"] == "receive":
interface=node.rargs
if node["interfaces_queue_size"][interface] > 0:
node["interfaces_queue_size"][interface]-=1
node.rqueue.put(("receive",0))
node["state"]="running"
# Do not forget to collect the next event. This is the only request which is processed here
self.sync_node(node)
self.sync_event(node)
elif node["request"] == "wait_end":
node["state"]="pending"
node.rqueue.put(("wait_end",0))
self.wait_end_nodes.append(node.node_id)
def communicate(self, interface, src, dst, data, datasize):
"""
Create communication event between src and dst
"""
nsrc=self.nodes[src]
if interface=="wlan0":
self.log("Send "+str(datasize)+" bytes on "+interface,node=src)
for dst in self.list_receivers(nsrc):
if self.nodes[dst]["turned_on"]:
duration=datasize*8/self.B[src,dst]+self.L[src,dst]
if src == dst:
self.add_event(0,duration+self.time,(src,dst,interface,data,datasize,duration,datasize,self.time))
elif not self.interferences:
self.add_event(0,duration+self.time,(src,dst,interface,data,datasize,duration,datasize,self.time))
elif not self.handle_interferences(src,dst):
self.add_event(0,duration+self.time,(src,dst,interface,data,datasize,duration,datasize,self.time))
else:
if self.nodes[dst]["turned_on"]:
self.log("Send "+str(datasize)+" bytes to n"+str(dst)+" on "+interface,node=src)
self.update_sharing(dst,1) # Update sharing first
# Note that in the following we send more data than expected to handle bandwidth sharing (datasize*8*sharing):
duration=datasize*8/(self.B[src,dst]/self.sharing[dst])+self.L[src,dst]
self.add_event(0,duration+self.time,(src,dst,interface,data,datasize,duration,datasize,self.time))
else:
nsrc["state"]="request" # Try later when node is on
def list_receivers(self,node):
"""
Deduce reachable receivers from the bandwidth matrix
"""
selector = self.B[node.node_id,] > 0
return np.arange(0,selector.shape[0])[selector]
def add_event(self,event_type,event_ts,event,priority=1):
"""
Call this function with sort=True the least amount of time possible
"""
self.events=np.concatenate([self.events,[np.array([event_type,event_ts,np.array(event,dtype=object),priority],dtype=object)]]) # Add new events
self.sort_events()
def run(self, breakpoints=[],breakpoint_callback=lambda s:None,breakpoints_every=None,debug=False,interferences=True):
"""
Run the simulation with the created nodes
"""
##### Setup simulation
self.startat=time.time()
self.interferences=interferences
for bp in breakpoints:
self.add_event(2,bp,0,0)
if breakpoints_every != None:
self.add_event(3,breakpoints_every,0,0)
if debug:
with open(self.debug_file_path, "w") as f:
f.write("Python version {}\n".format(sys.version))
f.write("Simulation started at {}\n".format(self.startat))
f.write("Number of nodes is "+str(len(self.nodes))+"\n")
f.write("Manual breakpoints list: "+str(breakpoints)+"\n")
f.write("Breakpoints every "+str(breakpoints_every)+"s\n")
##### Simulation loop
while True:
# Synchronize every nodes
for node in self.nodes:
self.sync_node(node)
# Manage events
for node in self.nodes:
self.sync_event(node)
# Generate debug logs
if debug:
self.debug()
# Simulation end
if len(self.events) <= 0 or len(self.events) == 1 and self.events[0,0] == 3:
# Notify nodes that wait for the end of the simulation
# Note that we do not allow them to create new events (even if they try, they will not be processed)
for node_id in self.wait_end_nodes:
self.nodes[node_id].rqueue.put(("sim_end",0))
self.nodes[node_id]["state"]="running"
self.sync_node(self.nodes[node_id]) # Allow them for make call requests (printing logs for example)
break # End the event processing loop
# Update simulation time
self.time=self.events[0,1]
self.time_truncated=format(self.time,self.precision) # refresh truncated time
# Process events
while len(self.events) > 0 and self.events[0,1] == self.time:
event_type=int(self.events[0,0])
ts=self.events[0,1]
event=self.events[0,2]
self.events=np.delete(self.events,0,0) # Consume events NOW! not at the end of the loop (event list may change in between)
if event_type == 0:
src_id,dst_id,interface, data, datasize,duration,datasize_remaining,start_at=event
src=self.nodes[int(src_id)]
dst=self.nodes[int(dst_id)]
if interface == "wlan0":
if src.node_id != dst.node_id:
dst["interfaces"][interface].put((data,start_at,self.time))
dst["interfaces_queue_size"][interface]+=1
self.log("Receive "+str(datasize)+" bytes on "+interface,node=int(dst_id))
# If node is receiving makes it consume (this way if there is a timeout, it will be removed!)
if dst["state"] == "request" and dst["request"] == "receive":
dst["interfaces_queue_size"][interface]-=1
dst.rqueue.put(("receive",0))
dst["state"]="running"
self.sync_node(dst)
else:
src["state"]="running"
src.rqueue.put(("send",0))
else:
dst["interfaces"][interface].put((data,start_at,self.time))
dst["interfaces_queue_size"][interface]+=1
self.update_sharing(dst.node_id,-1)
self.log("Receive "+str(datasize)+" bytes on "+interface,node=int(dst_id))
# If node is receiving makes it consume (this way if there is a timeout, it will be removed!)
if dst["state"] == "request" and dst["request"] == "receive":
dst["interfaces_queue_size"][interface]-=1
dst.rqueue.put(("receive",0))
dst["state"]="running"
self.sync_node(dst)
src["state"]="running"
src.rqueue.put(("send",0))
elif event_type == 1:
node=self.nodes[int(event)]
node["state"]="running"
node.rqueue.put(("timeout",0))
self.sync_node(node)
elif event_type == 2 or event_type == 3:
breakpoint_callback(self)
if event_type == 3:
self.add_event(3,self.time+breakpoints_every,0,0)
##### Simulation ends
self.log("Simulation ends")

28
example/receiver.py Normal file
View file

@ -0,0 +1,28 @@
#!/usr/bin/env python
import sys, random, time
lr=random.Random(6)
def execute(api):
uptime=api.args
endoff=0
for i in range(0,24):
startoff=random.randint(0,3600-uptime)
api.turn_off()
api.wait(startoff+endoff)
api.turn_on()
wakeat=api.read("clock")
wakeuntil=wakeat+uptime
# Receive until uptime seconds if elapsed
while api.read("clock") < wakeuntil:
code, data=api.receivet("wlan0",wakeuntil-api.read("clock"))
if code == 0:
api.log("Receive "+data)
api.log("Was up for {}s".format(api.read("clock")-wakeat))
endoff=3600*(i+1)-api.read("clock")
api.turn_off()
api.wait(endoff)
api.turn_on()

47
example/sender.py Normal file
View file

@ -0,0 +1,47 @@
#!/usr/bin/env python
######################
# _ ____ ___ #
# / \ | _ \_ _| #
# / _ \ | |_) | | #
# / ___ \| __/| | #
# /_/ \_\_| |___| #
# #
######################
# api.args # Contains node arguments
# api.send(interface, data,size, dst) # If interface is "wlan0" dst is not used
# api.sendt(interface, data,size, dst,timeout) # Similar to api.send() but with timeout
# api.receive(interface) # Receive the data by returning the following tuple (code,data) if code is 0 receive succeed
# api.receivet(interface,timeout) # Similar to api.receive() but with timeout
# api.read(register) # Read from the simulator registers (ex: clock)
# api.log(msg) # Print log in the simulation console
# api.wait(duration) # Wait for "duration" seconds of simulated time
# api.turn_off(duration) # Turn the node off for "duration" seconds (no data can be receive during this time period)
import sys, random
# Note that the following is required to have different instance from thread to thread
lr=random.Random(6)
def execute(api):
uptime=api.args
endoff=0
for i in range(0,24):
startoff=random.randint(0,3600-uptime)
api.turn_off()
api.wait(startoff+endoff)
api.turn_on()
wakeat=api.read("clock")
wakeuntil=wakeat+uptime
# Send until uptime seconds if elapsed
while api.read("clock") < wakeuntil:
api.sendt("wlan0","hello",10,None, wakeuntil-api.read("clock"))
api.log("Was up for {}s".format(api.read("clock")-wakeat))
endoff=3600*(i+1)-api.read("clock")
api.turn_off()
api.wait(endoff)
api.turn_on()

41
example/simulator.py Executable file
View file

@ -0,0 +1,41 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../")
import esds
# Use numpy to construct bandwidth and latencies matrix
import numpy as np
##### Scenario
# The simulated scenario comprises 1 that wakes up randomly
# for a duration called "uptime" every hour. The sender try to transmit
# his data during that uptime. Other nodes are receivers that have similar
# random wake up parterns and strive to receive data from the sender.
##### Bandwidth matrix
# Bandwidth value can be 0 for unreachable nodes
# Diagonal entries impact the transmission duration for wireless transmissions (wlan0)
n=2 # Number of nodes including the sender
B=np.full((n,n),5) # 5Mbps
##### Latency matrix
# If the latency entries match one with a bandwidth of 0
# then it will be ignore since node is unreachable.
L=np.full((n,n),0) # 0s
##### Create the simulator
s=esds.Simulator(B,L)
##### Instantiate nodes
uptime=180 # 180s uptime
s.create_node("sender",args=uptime) # Load sender.py for the first node with 5 as argument (first row in B and L)
# Aguments can be passed to nodes via: s.create_node("sender",args="my argument")
for n in range(0,n-1): # Load receiver.py for the remaining nodes
s.create_node("receiver",args=uptime)
##### Run the simulation
#s.run(debug=True) # Generate a "esds.debug" file
s.run()

251
icon.svg Normal file
View file

@ -0,0 +1,251 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="210mm"
height="297mm"
viewBox="0 0 210 297"
version="1.1"
id="svg5"
inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)"
sodipodi:docname="icon.svg"
inkscape:export-filename="/home/loic/bitmap.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="1.4274173"
inkscape:cx="375.85366"
inkscape:cy="592.32856"
inkscape:window-width="2548"
inkscape:window-height="1390"
inkscape:window-x="0"
inkscape:window-y="38"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
inkscape:snap-object-midpoints="true" />
<defs
id="defs2" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g2217"
transform="rotate(90,96.944432,135.97703)">
<g
id="g2201">
<path
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.99158;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1"
d="M 96.944421,117.45824 V 102.56952"
id="path2189" />
<path
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.99158;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1"
d="M 112.53423,117.45824 V 102.56952"
id="path2191" />
<path
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.99158;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1"
d="M 81.354608,117.45824 V 102.56952"
id="path2193" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000"
id="rect2195"
width="9.4016829"
height="9.4016857"
x="96.596527"
y="-117.23508"
ry="0.80720627"
transform="rotate(90)" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000"
id="rect2197"
width="9.4016829"
height="9.4016857"
x="96.596527"
y="-101.64526"
ry="0.80720627"
transform="rotate(90)" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000"
id="rect2199"
width="9.4016829"
height="9.4016857"
x="96.596527"
y="-86.05545"
ry="0.80720627"
transform="rotate(90)" />
</g>
<g
id="g2215">
<path
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.99158;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1"
d="M 96.944436,165.95584 V 151.06712"
id="path2203" />
<path
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.99158;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1"
d="M 112.53426,165.95584 V 151.06712"
id="path2205" />
<path
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.99158;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1"
d="M 81.35463,165.95584 V 151.06712"
id="path2207" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000"
id="rect2209"
width="9.4016829"
height="9.4016857"
x="165.95584"
y="-117.2351"
ry="0.80720627"
transform="rotate(90)" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000"
id="rect2211"
width="9.4016829"
height="9.4016857"
x="165.95584"
y="-101.64528"
ry="0.80720627"
transform="rotate(90)" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000"
id="rect2213"
width="9.4016829"
height="9.4016857"
x="165.95584"
y="-86.055473"
ry="0.80720627"
transform="rotate(90)" />
</g>
</g>
<g
id="g2187">
<g
id="g2171">
<path
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.99158;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1"
d="M 96.944421,117.45824 V 102.56952"
id="path2136" />
<path
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.99158;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1"
d="M 112.53423,117.45824 V 102.56952"
id="path2138" />
<path
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.99158;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1"
d="M 81.354608,117.45824 V 102.56952"
id="path1948" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000"
id="rect1312"
width="9.4016829"
height="9.4016857"
x="96.596527"
y="-117.23508"
ry="0.80720627"
transform="rotate(90)" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000"
id="rect1314"
width="9.4016829"
height="9.4016857"
x="96.596527"
y="-101.64526"
ry="0.80720627"
transform="rotate(90)" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000"
id="rect1316"
width="9.4016829"
height="9.4016857"
x="96.596527"
y="-86.05545"
ry="0.80720627"
transform="rotate(90)" />
</g>
<g
id="g2163">
<path
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.99158;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1"
d="M 96.944436,165.95584 V 151.06712"
id="path1914" />
<path
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.99158;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1"
d="M 112.53426,165.95584 V 151.06712"
id="path1916" />
<path
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.99158;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1"
d="M 81.35463,165.95584 V 151.06712"
id="path1537" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000"
id="rect1320"
width="9.4016829"
height="9.4016857"
x="165.95584"
y="-117.2351"
ry="0.80720627"
transform="rotate(90)" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000"
id="rect1322"
width="9.4016829"
height="9.4016857"
x="165.95584"
y="-101.64528"
ry="0.80720627"
transform="rotate(90)" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000"
id="rect1324"
width="9.4016829"
height="9.4016857"
x="165.95584"
y="-86.055473"
ry="0.80720627"
transform="rotate(90)" />
</g>
</g>
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2.99158;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000"
id="rect1030"
width="47.008419"
height="47.008415"
x="73.440231"
y="112.47282"
ry="4.0360303" />
<path
style="font-variation-settings:normal;opacity:1;fill:#ffffff;fill-opacity:0;stroke:#4d4d4d;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1"
d="M 107.5001,136.0153 83.837287,122.26787 108.60262,149.76274 Z"
id="path2632" />
<circle
style="font-variation-settings:normal;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1"
id="path2475"
cx="83.837288"
cy="122.26787"
r="4.7406592" />
<circle
style="font-variation-settings:normal;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1"
id="circle2557"
cx="108.60262"
cy="149.76274"
r="3.1051633" />
<circle
style="font-variation-settings:normal;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1"
id="circle2559"
cx="107.5001"
cy="136.0153"
r="4.7406592" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

1
plugins/__init__.py Normal file
View file

@ -0,0 +1 @@
__all__ = [ "node_plugin", "power_states" ]

29
plugins/node_plugin.py Normal file
View file

@ -0,0 +1,29 @@
class NodePlugin:
"""
Node plugins get register to the node API get notified when events occurs.
The call and return suffixes are used for methods that are called at the beginning
and the end, respectively, of API calls triggered by the node source code.
Changing this API could brake most of the node plugins.
"""
def __init__(self,plugin_name,api):
self.api=api
self.plugin_name=plugin_name
api.plugin_register(self)
def on_send_call(self,interface,data,datasize,dst):
pass
def on_send_return(self,interface,data,datasize,dst,code):
pass
def on_receive_return(self,interface,data,start_at,end_at):
pass
def on_terminated(self):
pass
def log(self,msg):
self.api.log(self.plugin_name+"(NP) "+msg)

View file

@ -0,0 +1,66 @@
#!/usr/bin/env python
from plugins.node_plugin import *
######################
# _ ____ ___ #
# / \ | _ \_ _| #
# / _ \ | |_) | | #
# / ___ \| __/| | #
# /_/ \_\_| |___| #
# #
######################
# import plugins.operating_states as op
# # Load the directional transition graph from graph.txt starting at the "vertex1" state
# opstate=op.OperatingStates(api,"graph.txt","vertex1")
# Format of the graph.txt file consists in one edge per line
# that consists on the source vertex and destination vertex sperated by a space
# As an example:
# vertex1 vertex2
# vertex1 vertex3
# vertex3 vertex2
# vertex2 vertex1
#
# opstate.register_callback(boom)
# # On each state transition boom will be called as boom(src_state,dst_state)
# # This way the boom callback can contains power_state transitions for examples
# opstate.goto("vertex2") # works
# opstate.goto("vertex3") # wont work
# opstate.goto("vertex1") # work since we are on vertex2
class OperatingStates(NodePlugin):
"""
OperatingStates plugin
"""
def __init__(self,api, state_file, initial_state):
self.transitions=list()
self.callbacks=list()
self.state=initial_state
with open(state_file) as fp:
for i, line in enumerate(fp):
self.transitions.append(line)
super().__init__("OperatingStates",api)
def goto(self,state):
if (self.state+" "+state) in self.transitions:
old_state=self.state
self.state=state
for c in self.callbacks:
c(old_state,state)
else:
self.log("Invalid transition "+self.state+" => "+state)
def get_state(self):
return(self.state)
def register_callback(self,callback):
"""
The callback will be called on each state transition
Callback takes two arguments which are:
- The source state
- The destination state
"""
self.callbacks.append(callback)

164
plugins/power_states.py Normal file
View file

@ -0,0 +1,164 @@
#!/usr/bin/env python
from plugins.node_plugin import *
# PowerStates allows you to measure the energy consumption of a
# node that go through several power states during the simulation
# Two version of Powerstates is provided by mean of two classes:
# - Powerstates: Allow you to set power to any user's defined values
# - PowerstatesFromFile: Allow you to set power from states defined in a file
######################
# _ ____ ___ #
# / \ | _ \_ _| #
# / _ \ | |_) | | #
# / ___ \| __/| | #
# /_/ \_\_| |___| #
# #
######################
# #Regarding PowerStates:
# import Powerstates as ps
# pstates=ps.PowerStates(<node>,<power_init>)
# pstates.set_power(<power>) # Switch the power consumption to <power>
# pstates.report_energy() # Display the current node energy consumption up to the current simulated time
# pstates.report_power_changes() # Display all the power changes up to the current simulated time
# #Regarding PowerStatesFromFile:
# #Format of <file> is one <entry> per line that follow this format <state-0>:<state-1>:...:<state-n>
# #Each line can corresponds to one node
# import Powerstates as ps
# pstates=ps.PowerStatesFromFile(<node>,<file>,<entry-line>) # Create a power states on node <node> using line <entry-line> of file <file>
# pstates.set_state(<id>) # Switch to the <id> power states
# pstates.report_energy() # Display the current node energy consumption up to the current simulated time
# pstates.report_power_changes() # Display all the power changes up to the current simulated time
# pstates.report_state_changes() # Display all the states changes up to the current simulated time
class PowerStates(NodePlugin):
"""
PowerStates model the energy consumed by the various changes of power consumption of a node over time.
"""
def __init__(self,node,power_init):
self.node=node
self.clock=self.node.clock()
self.energy=0
self.power=power_init
self.power_changes=dict()
self.set_power(power_init)
super().__init__("Powerstates",api)
def set_power(self,power_watt):
cur_clock=self.node.clock()
self.energy+=self.power*(cur_clock-self.clock)
self.clock=cur_clock
if self.power != power_watt:
self.power_changes[cur_clock]=power_watt
self.power=power_watt
return cur_clock
def report_energy(self):
self.set_power(self.power)
self.node.log("[PowerStates Plugin] Consumed "+str(self.energy) +"J")
def report_power_changes(self):
self.set_power(self.power)
for key in self.power_changes.keys():
self.node.log("[PowerStates Plugin] At t="+str(key)+" power is "+str(self.power_changes[key])+"W")
class PowerStatesFromFile(PowerStates):
"""
A version of Powerstates that load the power values from a file.
"""
def __init__(self,node,state_file,entry_line=1):
self.node=node
self.state_changes=dict()
self.states=[]
self.state=0
with open(state_file) as fp:
for i, line in enumerate(fp):
if i+1 == entry_line:
self.states=line.split(":")
self.states=[float(i) for i in self.states]
assert len(self.states) > 0
super().__init__(node,self.states[0])
self.set_state(0)
def set_state(self,state_id):
assert state_id < len(self.states)
clock=super().set_power(self.states[state_id])
if self.state != state_id:
self.state_changes[clock]=state_id
self.state=state_id
def report_state_changes(self):
self.set_state(self.state)
for key in self.state_changes.keys():
self.node.log("[PowerStates Plugin] At t="+str(key)+" state is "+str(self.state_changes[key]))
class PowerStatesComms(NodePlugin):
"""
Monitor the energy consumed by the network interfaces by mean of power states.
Note that for finer grained predictions, bytes and packet power consumption must be accounted.
Which is not the case with these power states.
"""
def __init__(self,api):
super().__init__("PowerStatesComms",api)
self.energy_dynamic=0.0 # Store the dynamic part of the energy consumption
self.power=dict() # Store the power states
self.tx_clock=0 # Dynamic clock (store the time at which a the last tx starts
self.idle_clock=api.clock() # Store the start time (to compute the idle part of the energy consumption)
def on_receive_return(self,interface,data,start_at,end_at):
duration=float(end_at)-float(start_at)
self.energy_dynamic+=self.power[interface]["rx"]*duration
def on_send_call(self,interface,data,datasize,dst):
self.tx_clock=self.api.clock()
def on_send_return(self,interface,data,datasize,dst,code):
clock=self.api.clock()
duration=(clock-float(self.tx_clock))
self.energy_dynamic+=self.power[interface]["tx"]*duration
self.tx_clock=clock # Any value could be use here
def set_power(self,interface,idle,tx,rx):
self.power[interface]=dict()
self.power[interface]["idle"]=idle
self.power[interface]["rx"]=rx
self.power[interface]["tx"]=tx
def get_idle(self):
clock=self.api.clock()
idle=0
for interface in self.power.keys():
idle+=(clock-self.idle_clock)*self.power[interface]["idle"]
return idle
def get_receive_queue_energy(self,interface):
"""
Not that call to on_receive_return may not have happened yet (or never).
Thus we should manually compute the energy consumption stored in each queues of the node.
"""
energy=0
# For each interface we should check if there is received data that has not been consumed
for data in list(self.api["interfaces"][interface].queue):
start_at=float(data[1])
end_at=float(data[2])
energy+=(end_at-start_at)*self.power[interface]["rx"]
return energy
def get_energy(self):
queue_energy=0
for interface in self.power.keys():
queue_energy+=self.get_receive_queue_energy(interface)
return self.get_idle()+self.energy_dynamic+queue_energy
def report_energy(self):
self.log("Communications consumed "+str(round(self.get_energy(),2))+"J")

71
plugins/wireless_area.py Normal file
View file

@ -0,0 +1,71 @@
import math
import numpy as np
class WirelessArea:
def __init__(self):
self.nodes=list()
def dump_nodes(self):
i=0
for node in self.nodes:
x,y,z,com_range=node
print("Node {} at ({},{},{}) with a communication range of {}m".format(i,x,y,z,com_range))
i+=1
def dump_infos(self):
print("Number of nodes {}".format(len(self.nodes)))
adjacency=self.generate_adjacency_matrix(fill_diagonal=False)
print("Nodes average degree is {}".format(np.mean(np.sum(adjacency,axis=0))))
x = [node[0] for node in self.nodes]
y = [node[1] for node in self.nodes]
z = [node[2] for node in self.nodes]
com_range = [node[3] for node in self.nodes]
print("Nodes locations ranges: x in [{},{}] y in [{},{}] z in [{},{}]".format(min(x),max(x),min(y),max(y),min(z),max(z)))
print("Node communication ranges in [{},{}]".format(min(com_range),max(com_range)))
def add_node(self,x,y,z,com_range):
self.nodes.append((x,y,z,com_range))
def get_neighbours(self,node_id):
node=self.nodes[node_id]
neighbours=list()
for i in range(0,len(self.nodes)):
if i != node_id:
neighbour=self.nodes[i]
if math.dist(node[0:3],neighbour[0:3]) <= node[3]:
neighbours.append(i)
return neighbours
def generate_dot(self,filepath):
is_strict=False
com_range=self.nodes[0][3]
for node in self.nodes:
if node[3] != com_range:
is_strict=True
break
with open(filepath, "w") as f:
if is_strict:
f.write("digraph G {\n")
else:
f.write("strict graph G {\n")
for i in range(0,len(self.nodes)):
neighbours=self.get_neighbours(i)
for n in neighbours:
if is_strict:
f.write("{}->{}\n".format(i,n))
else:
f.write("{}--{}\n".format(i,n))
f.write("}")
def generate_adjacency_matrix(self,fill_diagonal=True):
matrix=np.full((len(self.nodes),len(self.nodes)),0)
if fill_diagonal:
np.fill_diagonal(matrix,1) # Required by ESDS
for i in range(0,len(self.nodes)):
neighbours=self.get_neighbours(i)
for n in neighbours:
matrix[i,n]=1
return matrix

6
tests/README.md Normal file
View file

@ -0,0 +1,6 @@
# Tests
**Test folders names convention:**
- **m** senders and **n** receivers is written `<m>s<n>r` *(ex: 1s5r)*
- **n** nodes is written `<n>n` *(ex: 5n)*
- Tests names follow the following format `<title>_<m>s<n>r` or `<title>_<n>n` *(ex: simple_send_rcv_1s5r, ping_pong_2n)*
- Tests that test **elementary API functions** should start with the **simple** keyword

View file

@ -0,0 +1,4 @@
[t=0.000,src=n0] Send 1 bytes on wlan0
[t=0.000,src=n2] Send 1 bytes on wlan0
[t=0.000,src=n1] Interferences on wlan0
[t=1.000,src=esds] Simulation ends

View file

@ -0,0 +1,5 @@
#!/usr/bin/env python
def execute(api):
pass

View file

@ -0,0 +1,4 @@
#!/usr/bin/env python
def execute(api):
api.send("wlan0","Hello World!",1,1)

View file

@ -0,0 +1,22 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
B=np.full((3,3),8)
# Hide the nodes from each others
B[0,2]=0
B[2,0]=0
L=np.full((3,3),0)
s=esds.Simulator(B,L)
s.create_node("sender")
s.create_node("receiver")
s.create_node("sender")
s.run()

View file

@ -0,0 +1,4 @@
[t=0.000,src=n0] Send 1 bytes to n1 on eth0
[t=0.500,src=esds] Network update!
[t=0.750,src=n1] Receive 1 bytes on eth0
[t=0.750,src=esds] Simulation ends

View file

@ -0,0 +1,5 @@
#!/usr/bin/env python
def execute(api):
pass

View file

@ -0,0 +1,4 @@
#!/usr/bin/env python
def execute(api):
api.send("eth0","Hello World!",1,1)

View file

@ -0,0 +1,38 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
########## Scenario ##########
# Notations:
# - Remaining communication duration (last communication ends minus current simulated time) = C
# - Last communication duration (previous row) = U
# - Last remaining data size (previous row) = D
# - Current remaining data (current row) = R
# - Initial data size (first row) = I
# - Bandwidth = BW
# - Latency = L
# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------|
# | Simulated time(s) | Latency(s) | Bandwidth(bps) | Remaining data (bit) | Communcation duration(s) | Communcation ends at(s) |
# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------|
# | 0 | 0 | 8 | 8 | 1 | 1 |
# | 0.5 | 0 | 16 | C/U*D = 4 | R/I * L + R/BW = 0.25 | 0.75 |
# | 0.75 | 0 | 16 | | | |
# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------|
##############################
B=np.full((2,2),8)
L=np.full((2,2),0)
s=esds.Simulator(B,L)
s.create_node("sender")
s.create_node("receiver")
def callback(simulator):
simulator.log("Network update!")
simulator.update_network(simulator.B*2,simulator.L)
s.run(breakpoints_every=1/2,breakpoint_callback=callback)

View file

@ -0,0 +1,6 @@
[t=0.000,src=n0] Send 1 bytes to n2 on eth0
[t=0.000,src=n1] Send 1 bytes to n2 on eth0
[t=1.000,src=esds] Network update!
[t=1.500,src=n2] Receive 1 bytes on eth0
[t=1.500,src=n2] Receive 1 bytes on eth0
[t=1.500,src=esds] Simulation ends

View file

@ -0,0 +1,5 @@
#!/usr/bin/env python
def execute(api):
pass

View file

@ -0,0 +1,4 @@
#!/usr/bin/env python
def execute(api):
api.send("eth0","Hello World!",1,2)

View file

@ -0,0 +1,41 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
########## Scenario ##########
# Notations:
# - Remaining communication duration (last communication ends minus current simulated time) = C
# - Last communication duration (previous row) = U
# - Last remaining data size (previous row) = D
# - Current remaining data (current row) = R
# - Initial data size (first row) = I
# - Bandwidth = BW
# - Latency = L
# |----------------------------------------+------------+----------------+----------------------+---------------------------+-------------------------|
# | This table is the same for both sender | | | | | |
# |----------------------------------------+------------+----------------+----------------------+---------------------------+-------------------------|
# | Simulated time(s) | Latency(s) | Bandwidth(bps) | Remaining data (bit) | Communication duration(s) | Communcation ends at(s) |
# |----------------------------------------+------------+----------------+----------------------+---------------------------+-------------------------|
# | 0 | 0 | 8/2 | 8 | 2 | 2 |
# | 1 | 0 | 16/2 | C/U*D = 4 | 0.5 | 1.5 |
# | 1.5 | 0 | 16/2 | 0 | | |
# |----------------------------------------+------------+----------------+----------------------+---------------------------+-------------------------|
##############################
B=np.full((3,3),8)
L=np.full((3,3),0)
s=esds.Simulator(B,L)
s.create_node("sender")
s.create_node("sender")
s.create_node("receiver")
def callback(simulator):
simulator.log("Network update!")
simulator.update_network(simulator.B*2,simulator.L)
s.run(breakpoints_every=1,breakpoint_callback=callback,debug=True)

View file

@ -0,0 +1,37 @@
Python version 3.10.5 (main, Jun 6 2022, 18:49:26) [GCC 12.1.0]
Simulation started at 1654802959.3233912
Number of nodes is 3
Manual breakpoints list: []
Breakpoints every 1s
-----------------------------------------------
Started since 0.04s
Simulated time 0.000s (or more precisely 0s)
Node number per state: pending=2 terminated=1
Node sharing: n2=2
Ids of node in timeout mode:
Sorted events list:
[[3 1 array(0, dtype=object) 0]
[0 2.0 array([0, 2, 'eth0', 'Hello World!', 1, 2.0, 1, 0], dtype=object)
1]
[0 2.0 array([1, 2, 'eth0', 'Hello World!', 1, 2.0, 1, 0], dtype=object)
1]]
-----------------------------------------------
Started since 0.04s
Simulated time 1.000s (or more precisely 1s)
Node number per state: pending=2 terminated=1
Node sharing: n2=2
Ids of node in timeout mode:
Sorted events list:
[[0 1.5
array([0, 2, 'eth0', 'Hello World!', 1, 0.5, 0.5, 0], dtype=object) 1]
[0 1.5
array([1, 2, 'eth0', 'Hello World!', 1, 0.5, 0.5, 0], dtype=object) 1]
[3 2 array(0, dtype=object) 0]]
-----------------------------------------------
Started since 0.05s
Simulated time 1.500s (or more precisely 1.5s)
Node number per state: terminated=3
Node sharing:
Ids of node in timeout mode:
Sorted events list:
[[3 2 array(0, dtype=object) 0]]

View file

@ -0,0 +1,5 @@
[t=0.000,src=n0] Send 1 bytes to n1 on eth0
[t=0.500,src=esds] Network update!
[t=1.000,src=esds] Network update!
[t=1.333,src=n1] Receive 1 bytes on eth0
[t=1.333,src=esds] Simulation ends

View file

@ -0,0 +1,5 @@
#!/usr/bin/env python
def execute(api):
pass

View file

@ -0,0 +1,4 @@
#!/usr/bin/env python
def execute(api):
api.send("eth0","Hello World!",1,1)

View file

@ -0,0 +1,39 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
########## Scenario ##########
# Notations:
# - Remaining communication duration (last communication ends minus current simulated time) = C
# - Last communication duration (previous row) = U
# - Last remaining data size (previous row) = D
# - Current remaining data (current row) = R
# - Initial data size (first row) = I
# - Bandwidth = BW
# - Latency = L
# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------|
# | Simulated time(s) | Latency(s) | Bandwidth(bps) | Remaining data (bit) | Communcation duration(s) | Communcation ends at(s) |
# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------|
# | 0 | 0 | 8 | 8 | 1 | 1 |
# | 0.5 | 0.5 | 8 | C/U*D = 4 | R/I * L + R/BW = 0.75 | 1.25 |
# | 1 | 1 | 8 | C/U*D = 1.33 | R/I * L + R/BW = 0.33 | 1.33 |
# | 1.33 | 1 | 8 | | | |
# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------|
##############################
B=np.full((2,2),8)
L=np.full((2,2),0)
s=esds.Simulator(B,L)
s.create_node("sender")
s.create_node("receiver")
def callback(simulator):
simulator.log("Network update!")
simulator.update_network(simulator.B,simulator.L+1/2)
s.run(breakpoints_every=1/2,breakpoint_callback=callback)

View file

@ -0,0 +1,7 @@
[t=0.000,src=n0] Send 1 bytes to n2 on eth0
[t=0.000,src=n1] Send 1 bytes to n2 on eth0
[t=1.000,src=esds] Network update!
[t=2.000,src=esds] Network update!
[t=2.300,src=n2] Receive 1 bytes on eth0
[t=2.300,src=n2] Receive 1 bytes on eth0
[t=2.300,src=esds] Simulation ends

View file

@ -0,0 +1,5 @@
#!/usr/bin/env python
def execute(api):
pass

View file

@ -0,0 +1,4 @@
#!/usr/bin/env python
def execute(api):
api.send("eth0","Hello World!",1,2)

View file

@ -0,0 +1,42 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
########## Scenario ##########
# Notations:
# - Remaining communication duration (last communication ends minus current simulated time) = C
# - Last communication duration (previous row) = U
# - Last remaining data size (previous row) = D
# - Current remaining data (current row) = R
# - Initial data size (first row) = I
# - Bandwidth = BW
# - Latency = L
# |----------------------------------------+------------+----------------+----------------------+---------------------------+-------------------------|
# | This table is the same for both sender | | | | | |
# |----------------------------------------+------------+----------------+----------------------+---------------------------+-------------------------|
# | Simulated time(s) | Latency(s) | Bandwidth(bps) | Remaining data (bit) | Communication duration(s) | Communcation ends at(s) |
# |----------------------------------------+------------+----------------+----------------------+---------------------------+-------------------------|
# | 0 | 0 | 8/2 | 8 | 2 | 2 |
# | 1 | 0.5 | 8/2 | C/U*D=4 | R/BW + R/I*L = 1.25 | 2.25 |
# | 2 | 1 | 8/2 | C/U*D=0.8 | R/BW + R/I*L = 0.3 | 2.3 |
# | 2.3 | 1 | 8/2 | 0 | | |
# |----------------------------------------+------------+----------------+----------------------+---------------------------+-------------------------|
##############################
B=np.full((3,3),8)
L=np.full((3,3),0)
s=esds.Simulator(B,L)
s.create_node("sender")
s.create_node("sender")
s.create_node("receiver")
def callback(simulator):
simulator.log("Network update!")
simulator.update_network(simulator.B,simulator.L+0.5)
s.run(breakpoints_every=1,breakpoint_callback=callback,debug=True)

View file

@ -0,0 +1,51 @@
Python version 3.10.5 (main, Jun 6 2022, 18:49:26) [GCC 12.1.0]
Simulation started at 1654802960.9297695
Number of nodes is 3
Manual breakpoints list: []
Breakpoints every 1s
-----------------------------------------------
Started since 0.08s
Simulated time 0.000s (or more precisely 0s)
Node number per state: pending=2 terminated=1
Node sharing: n2=2
Ids of node in timeout mode:
Sorted events list:
[[3 1 array(0, dtype=object) 0]
[0 2.0 array([0, 2, 'eth0', 'Hello World!', 1, 2.0, 1, 0], dtype=object)
1]
[0 2.0 array([1, 2, 'eth0', 'Hello World!', 1, 2.0, 1, 0], dtype=object)
1]]
-----------------------------------------------
Started since 0.08s
Simulated time 1.000s (or more precisely 1s)
Node number per state: pending=2 terminated=1
Node sharing: n2=2
Ids of node in timeout mode:
Sorted events list:
[[3 2 array(0, dtype=object) 0]
[0 2.25
array([0, 2, 'eth0', 'Hello World!', 1, 1.25, 0.5, 0], dtype=object) 1]
[0 2.25
array([1, 2, 'eth0', 'Hello World!', 1, 1.25, 0.5, 0], dtype=object) 1]]
-----------------------------------------------
Started since 0.08s
Simulated time 2.000s (or more precisely 2s)
Node number per state: pending=2 terminated=1
Node sharing: n2=2
Ids of node in timeout mode:
Sorted events list:
[[0 2.3
array([0, 2, 'eth0', 'Hello World!', 1, 0.30000000000000004, 0.1, 0],
dtype=object) 1]
[0 2.3
array([1, 2, 'eth0', 'Hello World!', 1, 0.30000000000000004, 0.1, 0],
dtype=object) 1]
[3 3 array(0, dtype=object) 0]]
-----------------------------------------------
Started since 0.09s
Simulated time 2.300s (or more precisely 2.3s)
Node number per state: terminated=3
Node sharing:
Ids of node in timeout mode:
Sorted events list:
[[3 3 array(0, dtype=object) 0]]

View file

@ -0,0 +1,4 @@
[t=0.000,src=n0] Send 1 bytes on wlan0
[t=0.500,src=esds] Network update!
[t=0.750,src=n1] Receive 1 bytes on wlan0
[t=0.750,src=esds] Simulation ends

View file

@ -0,0 +1,5 @@
#!/usr/bin/env python
def execute(api):
pass

View file

@ -0,0 +1,4 @@
#!/usr/bin/env python
def execute(api):
api.send("wlan0","Hello World!",1,1)

View file

@ -0,0 +1,38 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
########## Scenario ##########
# Notations:
# - Remaining communication duration (last communication ends minus current simulated time) = C
# - Last communication duration (previous row) = U
# - Last remaining data size (previous row) = D
# - Current remaining data (current row) = R
# - Initial data size (first row) = I
# - Bandwidth = BW
# - Latency = L
# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------|
# | Simulated time(s) | Latency(s) | Bandwidth(bps) | Remaining data (bit) | Communcation duration(s) | Communcation ends at(s) |
# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------|
# | 0 | 0 | 8 | 8 | 1 | 1 |
# | 0.5 | 0 | 16 | C/U*D = 4 | R/I * L + R/BW = 0.25 | 0.75 |
# | 0.75 | 0 | 16 | | | |
# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------|
##############################
B=np.full((2,2),8)
L=np.full((2,2),0)
s=esds.Simulator(B,L)
s.create_node("sender")
s.create_node("receiver")
def callback(simulator):
simulator.log("Network update!")
simulator.update_network(simulator.B*2,simulator.L)
s.run(breakpoints_every=1/2,breakpoint_callback=callback)

View file

@ -0,0 +1,5 @@
[t=0.000,src=n0] Send 1 bytes on wlan0
[t=0.500,src=esds] Network update!
[t=1.000,src=esds] Network update!
[t=1.333,src=n1] Receive 1 bytes on wlan0
[t=1.333,src=esds] Simulation ends

View file

@ -0,0 +1,5 @@
#!/usr/bin/env python
def execute(api):
pass

View file

@ -0,0 +1,4 @@
#!/usr/bin/env python
def execute(api):
api.send("wlan0","Hello World!",1,1)

View file

@ -0,0 +1,39 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
########## Scenario ##########
# Notations:
# - Remaining communication duration (last communication ends minus current simulated time) = C
# - Last communication duration (previous row) = U
# - Last remaining data size (previous row) = D
# - Current remaining data (current row) = R
# - Initial data size (first row) = I
# - Bandwidth = BW
# - Latency = L
# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------|
# | Simulated time(s) | Latency(s) | Bandwidth(bps) | Remaining data (bit) | Communcation duration(s) | Communcation ends at(s) |
# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------|
# | 0 | 0 | 8 | 8 | 1 | 1 |
# | 0.5 | 0.5 | 8 | C/U*D = 4 | R/I * L + R/BW = 0.75 | 1.25 |
# | 1 | 1 | 8 | C/U*D = 1.33 | R/I * L + R/BW = 0.33 | 1.33 |
# | 1.33 | 1 | 8 | | | |
# |-------------------+------------+----------------+----------------------+--------------------------+-------------------------|
##############################
B=np.full((2,2),8)
L=np.full((2,2),0)
s=esds.Simulator(B,L)
s.create_node("sender")
s.create_node("receiver")
def callback(simulator):
simulator.log("Network update!")
simulator.update_network(simulator.B,simulator.L+1/2)
s.run(breakpoints_every=1/2,breakpoint_callback=callback)

48
tests/run.sh Executable file
View file

@ -0,0 +1,48 @@
#!/usr/bin/env bash
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BOLD='\033[1m'
NC='\033[0m' # No Color
wai=$(dirname $(readlink -f "$0")) # Current script directory
tests=$(find ${wai}/ -maxdepth 1 -mindepth 1 -type d) # Find tests
out=$(mktemp)
test_timeout=20
for test in ${tests}
do
printf "%-50s%s %s" "- $(basename $test)" "=>"
cd $test
timeout $test_timeout ./simulator.py &> "$out"
# Ensure timeout
if [ $? -eq 124 ]
then
echo -e "${RED}${BOLD}failed${NC}"
echo "------------- Test timeout (should not exceed ${test_timeout}s) -------------"
cat "$out";
rm "$out"
exit 2
fi
# Ensure test output
if $(diff "$out" ./out &>/dev/null)
then
echo -e "${GREEN}${BOLD}passed${NC}"
else
echo -e "${RED}${BOLD}failed${NC}"
echo "------------- Expected -------------"
cat out
echo "------------- Got -------------"
cat "$out";
rm "$out"
exit 1
fi
# Prepare for next test
cd - &>/dev/null
done
rm "$out"

View file

@ -0,0 +1,8 @@
#!/usr/bin/env python
def execute(api):
if api.node_id == 0:
api.send("eth0","Hello",5,1)
else:
api.receive("eth0")

View file

@ -0,0 +1,9 @@
[t=0.000,src=n0] Send 5 bytes to n1 on eth0
[t=3.300,src=esds] Hello Callback!
[t=6.600,src=esds] Hello Callback!
[t=9.900,src=esds] Hello Callback!
[t=13.200,src=esds] Hello Callback!
[t=16.500,src=esds] Hello Callback!
[t=19.800,src=esds] Hello Callback!
[t=20.000,src=n1] Receive 5 bytes on eth0
[t=20.000,src=esds] Simulation ends

View file

@ -0,0 +1,20 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
n=2
B=np.full((2,2),n)
L=np.full((2,2),0)
s=esds.Simulator(B,L)
s.create_node("node")
s.create_node("node")
def callback(simulator):
simulator.log("Hello Callback!")
s.run(breakpoints_every=3.3,breakpoint_callback=callback)

View file

@ -0,0 +1,4 @@
#!/usr/bin/env python
def execute(api):
api.log("Running")

View file

@ -0,0 +1,7 @@
[t=0.000,src=n0] Running
[t=0.000,src=n1] Running
[t=1.000,src=esds] Hello Callback!
[t=2.000,src=esds] Hello Callback!
[t=3.000,src=esds] Hello Callback!
[t=10.000,src=esds] Hello Callback!
[t=10.000,src=esds] Simulation ends

View file

@ -0,0 +1,20 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
n=2
B=np.full((n,n),n)
L=np.full((n,n),0)
s=esds.Simulator(B,L)
s.create_node("node")
s.create_node("node")
def callback(simulator):
simulator.log("Hello Callback!")
s.run(breakpoints=[1,2,3,10],breakpoint_callback=callback)

View file

@ -0,0 +1,4 @@
#!/usr/bin/env python
def execute(api):
api.log("Running")

View file

@ -0,0 +1,3 @@
[t=0.000,src=n0] Running
[t=0.000,src=n1] Running
[t=10.000,src=esds] Simulation ends

View file

@ -0,0 +1,17 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
n=2
B=np.full((n,n),n)
L=np.full((n,n),0)
s=esds.Simulator(B,L)
s.create_node("node")
s.create_node("node")
s.run(breakpoints=[1,2,3,10])

View file

@ -0,0 +1,7 @@
#!/usr/bin/env python
def execute(api):
api.log("A")
api.log("B")
api.log("C")
api.log("D")

21
tests/simple_log_5n/out Normal file
View file

@ -0,0 +1,21 @@
[t=0.000,src=n0] A
[t=0.000,src=n0] B
[t=0.000,src=n0] C
[t=0.000,src=n0] D
[t=0.000,src=n1] A
[t=0.000,src=n1] B
[t=0.000,src=n1] C
[t=0.000,src=n1] D
[t=0.000,src=n2] A
[t=0.000,src=n2] B
[t=0.000,src=n2] C
[t=0.000,src=n2] D
[t=0.000,src=n3] A
[t=0.000,src=n3] B
[t=0.000,src=n3] C
[t=0.000,src=n3] D
[t=0.000,src=n4] A
[t=0.000,src=n4] B
[t=0.000,src=n4] C
[t=0.000,src=n4] D
[t=0.000,src=esds] Simulation ends

View file

@ -0,0 +1,19 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
B=np.full((5,5),5)
L=np.full((5,5),0)
s=esds.Simulator(B,L)
s.create_node("node")
s.create_node("node")
s.create_node("node")
s.create_node("node")
s.create_node("node")
s.run()

View file

@ -0,0 +1,7 @@
#!/usr/bin/env python
def execute(api):
api.log("Clock is {}s".format(api.read("clock")))
api.wait(5698.1256)
api.log("Clock is {}s".format(api.read("clock")))
api.log("Clock is {}s".format(api.read("clock")))

View file

@ -0,0 +1,7 @@
[t=0.000,src=n0] Clock is 0s
[t=0.000,src=n1] Clock is 0s
[t=5698.126,src=n0] Clock is 5698.1256s
[t=5698.126,src=n0] Clock is 5698.1256s
[t=5698.126,src=n1] Clock is 5698.1256s
[t=5698.126,src=n1] Clock is 5698.1256s
[t=5698.126,src=esds] Simulation ends

View file

@ -0,0 +1,16 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
B=np.full((2,2),2)
L=np.full((2,2),0)
s=esds.Simulator(B,L)
s.create_node("node")
s.create_node("node")
s.run()

View file

@ -0,0 +1,9 @@
[t=0.000,src=n2] eth0 is 0
[t=624.000,src=n2] eth0 is 0
[t=1248.000,src=n0] Send 50 bytes to n2 on eth0
[t=1249.000,src=n2] eth0 is 1
[t=1249.000,src=n1] Send 50 bytes to n2 on eth0
[t=1250.000,src=n2] eth0 is 2
[t=1513.667,src=n2] Receive 50 bytes on eth0
[t=1514.667,src=n2] Receive 50 bytes on eth0
[t=1514.667,src=esds] Simulation ends

View file

@ -0,0 +1,12 @@
#!/usr/bin/env python
def execute(api):
api.log("eth0 is {}".format(api.read("eth0_ncom")))
api.wait(624)
api.log("eth0 is {}".format(api.read("eth0_ncom")))
api.wait(624)
# Now we are at 624*2=1248 (first sender start a communication)
api.wait(1) # Let the communication starts
api.log("eth0 is {}".format(api.read("eth0_ncom"))) # Should print 1
api.wait(1) # Now second sender start a communication
api.log("eth0 is {}".format(api.read("eth0_ncom"))) # Should print 2

View file

@ -0,0 +1,9 @@
#!/usr/bin/env python
def execute(api):
api.wait(1248)
if api.node_id==0:
api.send("eth0","hello",50,2)
else:
api.wait(1)
api.send("eth0","hello",50,2)

View file

@ -0,0 +1,17 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
B=np.full((3,3),3)
L=np.full((3,3),0)
s=esds.Simulator(B,L)
s.create_node("sender")
s.create_node("sender")
s.create_node("receiver")
s.run(interferences=False)

View file

@ -0,0 +1,11 @@
[t=0.000,src=n2] wlan0 is 0
[t=624.000,src=n2] wlan0 is 0
[t=1248.000,src=n0] Send 50 bytes on wlan0
[t=1249.000,src=n2] wlan0 is 1
[t=1249.000,src=n1] Send 50 bytes on wlan0
[t=1250.000,src=n2] wlan0 is 2
[t=1381.333,src=n1] Receive 50 bytes on wlan0
[t=1381.333,src=n2] Receive 50 bytes on wlan0
[t=1382.333,src=n0] Receive 50 bytes on wlan0
[t=1382.333,src=n2] Receive 50 bytes on wlan0
[t=1382.333,src=esds] Simulation ends

View file

@ -0,0 +1,12 @@
#!/usr/bin/env python
def execute(api):
api.log("wlan0 is {}".format(api.read("wlan0_ncom")))
api.wait(624)
api.log("wlan0 is {}".format(api.read("wlan0_ncom")))
api.wait(624)
# Now we are at 624*2=1248 (first sender start a communication)
api.wait(1) # Let the communication starts
api.log("wlan0 is {}".format(api.read("wlan0_ncom"))) # Should print 1
api.wait(1) # Second sender start a communication
api.log("wlan0 is {}".format(api.read("wlan0_ncom"))) # Should print 2

View file

@ -0,0 +1,9 @@
#!/usr/bin/env python
def execute(api):
api.wait(1248)
if api.node_id==0:
api.send("wlan0","hello",50,None)
else:
api.wait(1)
api.send("wlan0","hello",50,None)

View file

@ -0,0 +1,17 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
B=np.full((3,3),3)
L=np.full((3,3),0)
s=esds.Simulator(B,L)
s.create_node("sender")
s.create_node("sender")
s.create_node("receiver")
s.run(interferences=False)

View file

@ -0,0 +1,8 @@
[t=0.000,src=n0] Send 1 bytes to n1 on eth0
[t=1.000,src=n1] Receive 1 bytes on eth0
[t=1.000,src=n1] Received: Hello World!
[t=1.000,src=n0] Send 1 bytes to n1 on eth0
[t=1.500,src=n1] Receive failed code=-1
[t=2.000,src=n1] Receive 1 bytes on eth0
[t=2.000,src=n1] Received: Hello World!
[t=2.000,src=esds] Simulation ends

View file

@ -0,0 +1,15 @@
#!/usr/bin/env python
def receivet(node,timeout):
##### Simple receive
code, data=node.receivet("eth0",timeout)
msg="Received: "+data if code == 0 else "Receive failed code="+str(code)
node.log(msg)
def execute(api):
# Should works
receivet(api,2)
# Should failed
receivet(api,0.5) # At t=1.5s
# Should works (priorities says that communications should occurs before timeout)
receivet(api,0.5) # At t=2s (timeout+receive should occur)

View file

@ -0,0 +1,6 @@
#!/usr/bin/env python
def execute(api):
api.send("eth0","Hello World!",1,1)
api.send("eth0","Hello World!",1,1)

View file

@ -0,0 +1,16 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
B=np.full((2,2),8)
L=np.full((2,2),0)
s=esds.Simulator(B,L)
s.create_node("sender")
s.create_node("receiver")
s.run(debug=True)

View file

@ -0,0 +1,43 @@
Python version 3.10.5 (main, Jun 6 2022, 18:49:26) [GCC 12.1.0]
Simulation started at 1654802960.7880125
Number of nodes is 2
Manual breakpoints list: []
Breakpoints every Nones
-----------------------------------------------
Started since 0.02s
Simulated time 0.000s (or more precisely 0s)
Node number per state: pending=1 request=1
Node sharing: n1=1
Ids of node in timeout mode:
Sorted events list:
[[0 1.0 array([0, 1, 'eth0', 'Hello World!', 1, 1.0, 1, 0], dtype=object)
1]
[1 2 array(1, dtype=object) 3]]
-----------------------------------------------
Started since 0.04s
Simulated time 1.000s (or more precisely 1.0s)
Node number per state: pending=1 request=1
Node sharing: n1=1
Ids of node in timeout mode:
Sorted events list:
[[1 1.5 array(1, dtype=object) 3]
[0 2.0
array([0, 1, 'eth0', 'Hello World!', 1, 1.0, 1, 1.0], dtype=object) 1]]
-----------------------------------------------
Started since 0.06s
Simulated time 1.500s (or more precisely 1.5s)
Node number per state: pending=1 request=1
Node sharing: n1=1
Ids of node in timeout mode:
Sorted events list:
[[0 2.0
array([0, 1, 'eth0', 'Hello World!', 1, 1.0, 1, 1.0], dtype=object) 1]
[1 2.0 array(1, dtype=object) 3]]
-----------------------------------------------
Started since 0.08s
Simulated time 2.000s (or more precisely 2.0s)
Node number per state: terminated=2
Node sharing:
Ids of node in timeout mode:
Sorted events list:
[]

View file

@ -0,0 +1,11 @@
[t=0.000,src=n0] Send 1 bytes to n1 on eth0
[t=1.000,src=n1] Receive 1 bytes on eth0
[t=1.000,src=n1] Received: Hello World!
[t=1.000,src=n0] Send 1 bytes to n1 on eth0
[t=2.000,src=n1] Receive 1 bytes on eth0
[t=3.000,src=n0] Send 1 bytes to n1 on eth0
[t=3.000,src=n1] Received: Hello World!
[t=3.000,src=n1] Turned off
[t=4.000,src=n1] Turned on
[t=5.000,src=n1] Receive failed code=-1
[t=5.000,src=esds] Simulation ends

View file

@ -0,0 +1,20 @@
#!/usr/bin/env python
def execute(api):
##### Simple receive
code, data=api.receive("eth0")
msg="Received: "+data if code == 0 else "Receive failed code="+str(code)
api.log(msg)
##### Test if we still receive the data when we are not receiving
api.wait(2)
code, data=api.receive("eth0")
msg="Received: "+data if code == 0 else "Receive failed code="+str(code)
api.log(msg)
##### Ensure data is not receive when turned off
api.turn_off()
api.wait(1)
api.turn_on()
code, data=api.receivet("eth0",1)
msg="Received: "+data if code == 0 else "Receive failed code="+str(code)
api.log(msg)

View file

@ -0,0 +1,7 @@
#!/usr/bin/env python
def execute(api):
api.send("eth0","Hello World!",1,1)
api.send("eth0","Hello World!",1,1)
api.wait(1) # Goto 3 seconds
api.send("eth0","Hello World!",1,1)

View file

@ -0,0 +1,16 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
B=np.full((2,2),8)
L=np.full((2,2),0)
s=esds.Simulator(B,L)
s.create_node("sender")
s.create_node("receiver")
s.run()

View file

@ -0,0 +1,7 @@
[t=0.000,src=n0] Send 1 bytes to n2 on eth0
[t=0.000,src=n1] Send 1 bytes to n2 on eth0
[t=2.000,src=n2] Receive 1 bytes on eth0
[t=2.000,src=n2] Received: Hello World from 0!
[t=2.000,src=n2] Receive 1 bytes on eth0
[t=2.000,src=n2] Received: Hello World from 1!
[t=2.000,src=esds] Simulation ends

View file

@ -0,0 +1,13 @@
#!/usr/bin/env python
def execute(api):
##### Simple receive from node 0
code, data=api.receive("eth0")
msg="Received: "+data if code == 0 else "Receive failed code="+str(code)
api.log(msg)
##### Simple receive from node 1
code, data=api.receive("eth0")
msg="Received: "+data if code == 0 else "Receive failed code="+str(code)
api.log(msg)

View file

@ -0,0 +1,5 @@
#!/usr/bin/env python
def execute(api):
api.send("eth0","Hello World from {}!".format(api.node_id),1,2)

View file

@ -0,0 +1,17 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
B=np.full((3,3),8)
L=np.full((3,3),0)
s=esds.Simulator(B,L)
s.create_node("sender")
s.create_node("sender")
s.create_node("receiver")
s.run()

View file

@ -0,0 +1,40 @@
[t=0.000,src=n0] Send 1 bytes to n3 on eth0
[t=0.000,src=n1] Send 1 bytes to n3 on eth0
[t=0.000,src=n2] Send 1 bytes to n3 on eth0
[t=3.000,src=n3] Receive 1 bytes on eth0
[t=3.000,src=n3] Received: Hello World from 0!
[t=3.000,src=n3] Receive 1 bytes on eth0
[t=3.000,src=n3] Received: Hello World from 1!
[t=3.000,src=n3] Receive 1 bytes on eth0
[t=3.000,src=n3] Received: Hello World from 2!
[t=3.000,src=n0] Send 2 bytes to n3 on eth0
[t=3.000,src=n1] Send 1 bytes to n3 on eth0
[t=3.000,src=n2] Send 1 bytes to n3 on eth0
[t=6.000,src=n3] Receive 1 bytes on eth0
[t=6.000,src=n3] Received: Hello World from 1!
[t=6.000,src=n3] Receive 1 bytes on eth0
[t=6.000,src=n3] Received: Hello World from 2!
[t=7.000,src=n3] Receive 2 bytes on eth0
[t=7.000,src=n3] Received: Hello World from 0!
[t=7.000,src=n0] Send 2 bytes to n3 on eth0
[t=7.000,src=n1] Send 2 bytes to n3 on eth0
[t=7.000,src=n2] Send 1 bytes to n3 on eth0
[t=10.000,src=n3] Receive 1 bytes on eth0
[t=10.000,src=n3] Received: Hello World from 2!
[t=12.000,src=n3] Receive 2 bytes on eth0
[t=12.000,src=n3] Received: Hello World from 0!
[t=12.000,src=n3] Receive 2 bytes on eth0
[t=12.000,src=n3] Received: Hello World from 1!
[t=12.000,src=n0] Send 1 bytes to n3 on eth0
[t=12.000,src=n1] Send 2 bytes to n3 on eth0
[t=12.000,src=n2] Send 3 bytes to n3 on eth0
[t=15.000,src=n3] Receive 1 bytes on eth0
[t=15.000,src=n3] Received: Hello World from 0!
[t=17.000,src=n3] Receive 2 bytes on eth0
[t=17.000,src=n3] Received: Hello World from 1!
[t=18.000,src=n3] Receive 3 bytes on eth0
[t=18.000,src=n3] Received: Hello World from 2!
[t=18.000,src=n0] Send 5 bytes to n3 on eth0
[t=23.000,src=n3] Receive 5 bytes on eth0
[t=23.000,src=n3] Received: Hello World from 0!
[t=23.000,src=esds] Simulation ends

View file

@ -0,0 +1,19 @@
#!/usr/bin/env python
def receive(node, n):
for i in range(0,n):
code, data=node.receive("eth0")
msg="Received: "+data if code == 0 else "Receive failed code="+str(code)
node.log(msg)
def execute(api):
# Receive the first 3 send that should end at 3s
receive(api,3)
# Receive the first 3 send that should end at 7s
receive(api,3)
# Receive the first 3 send that should end at 12s
receive(api,3)
# Receive the first 3 send that should end at 18s
receive(api,3)
# Should ends at 23s
receive(api,1)

View file

@ -0,0 +1,37 @@
#!/usr/bin/env python
# Node that bandwidths at setup in a way that 1 byte is send in 1 seconds with no sharing
def execute(api):
# Should be completed at 3s (bandwidth divided by 3)
api.send("eth0","Hello World from {}!".format(api.node_id),1,3) # Shoud lasts 3s
# These send should start at 3s and be completed at 7s
if api.node_id==0:
api.send("eth0","Hello World from {}!".format(api.node_id),2,3) # Should lasts 3s + 1s = 4s
else:
api.send("eth0","Hello World from {}!".format(api.node_id),1,3) # Should lasts 3s
api.wait(1) # Sync with node 0 at 7s
# Those sends should start at 7s and be completed at 12s
if api.node_id<=1:
api.send("eth0","Hello World from {}!".format(api.node_id),2,3) # Should last 3s + 2s = 5s
# Completed at 12s since 3 nodes are sharing the bandwidth up to 10s
# then the 2 two remaining node send their last byte up to 12s
else:
api.send("eth0","Hello World from {}!".format(api.node_id),1,3) # Should last 3s
# Completed at 10s (3 nodes are sharing the bandwidth)
api.wait(2) # Sync with node 0-1 at 12s
# Should start at 12s
# Node 0 sends 1 byte, node 1 sends 2 byte and node 2 sends 3
# These send should end at 18s
api.send("eth0","Hello World from {}!".format(api.node_id),api.node_id+1,3) # Should lasts 3s, 5s and 6s
# Finally a single send from node 0
if api.node_id==0:
api.wait(3) # Since node 0 send ends at 15s we sync it to 18s
api.send("eth0","Hello World from {}!".format(api.node_id),5,3) # Should takes 5 seconds (ends at 23s)

View file

@ -0,0 +1,18 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
B=np.full((4,4),8)
L=np.full((4,4),0)
s=esds.Simulator(B,L)
s.create_node("sender")
s.create_node("sender")
s.create_node("sender")
s.create_node("receiver")
s.run()

View file

@ -0,0 +1,16 @@
[t=0.000,src=n0] Send 1 bytes on wlan0
[t=1.000,src=n1] Receive 1 bytes on wlan0
[t=1.000,src=n1] Received: Hello World!
[t=1.000,src=n2] Receive 1 bytes on wlan0
[t=1.000,src=n2] Received: Hello World!
[t=1.000,src=n2] Turned off
[t=1.000,src=n0] Send 1 bytes on wlan0
[t=2.000,src=n1] Receive 1 bytes on wlan0
[t=2.000,src=n1] Received: Hello World!
[t=2.000,src=n2] Turned on
[t=2.000,src=n0] Send 1 bytes on wlan0
[t=2.500,src=n2] Turned off
[t=3.000,src=n1] Receive 1 bytes on wlan0
[t=3.000,src=n1] Received: Hello World!
[t=3.000,src=n2] Turned on
[t=3.000,src=esds] Simulation ends

View file

@ -0,0 +1,29 @@
#!/usr/bin/env python
def receive(node):
##### Simple receive
code, data=node.receive("wlan0")
msg="Received: "+data if code == 0 else "Receive failed code="+str(code)
node.log(msg)
def execute(api):
# Should works for all receivers
receive(api)
if api.node_id == 1:
receive(api) # Should works
else:
api.turn_off()
api.wait(1) # Node 2 should not receive anything during 1s
api.turn_on()
if api.node_id == 1:
receive(api) # Should works
else:
api.wait(0.5) # Check if started communication get cancelled on turning off
api.turn_off() # Node 2 should not receive anything
api.wait(0.5) # Node 2 should not receive anything during 0.5s
api.turn_on()

View file

@ -0,0 +1,6 @@
#!/usr/bin/env python
def execute(api):
api.send("wlan0","Hello World!",1,1)
api.send("wlan0","Hello World!",1,1)
api.send("wlan0","Hello World!",1,1)

View file

@ -0,0 +1,17 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
B=np.full((3,3),8)
L=np.full((3,3),0)
s=esds.Simulator(B,L)
s.create_node("sender")
s.create_node("receiver")
s.create_node("receiver")
s.run()

View file

@ -0,0 +1,6 @@
[t=0.000,src=n0] Send 1 bytes on wlan0
[t=0.000,src=n1] Send 1 bytes on wlan0
[t=0.000,src=n0] Interferences on wlan0
[t=0.000,src=n1] Interferences on wlan0
[t=0.000,src=n2] Interferences on wlan0
[t=1.000,src=esds] Simulation ends

View file

@ -0,0 +1,5 @@
#!/usr/bin/env python
def execute(api):
pass

View file

@ -0,0 +1,4 @@
#!/usr/bin/env python
def execute(api):
api.send("wlan0","Hello World!",1,1)

View file

@ -0,0 +1,17 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
B=np.full((3,3),8)
L=np.full((3,3),0)
s=esds.Simulator(B,L)
s.create_node("sender")
s.create_node("sender")
s.create_node("receiver")
s.run()

View file

@ -0,0 +1,11 @@
[t=0.000,src=n0] Send 1 bytes to n1 on eth0
[t=1.000,src=n1] Receive 1 bytes on eth0
[t=1.000,src=n1] Received: Hello World!
[t=1.000,src=n0] Send worked!
[t=1.000,src=n0] Send 1 bytes to n1 on eth0
[t=1.500,src=n0] Send failed
[t=1.500,src=n0] Send 1 bytes to n1 on eth0
[t=2.500,src=n1] Receive 1 bytes on eth0
[t=2.500,src=n1] Received: Hello World!
[t=2.500,src=n0] Send worked!
[t=2.500,src=esds] Simulation ends

View file

@ -0,0 +1,11 @@
#!/usr/bin/env python
def receive(node):
##### Simple receive
code, data=node.receive("eth0")
msg="Received: "+data if code == 0 else "Receive failed code="+str(code)
node.log(msg)
def execute(api):
receive(api)
receive(api)

View file

@ -0,0 +1,14 @@
#!/usr/bin/env python
def sendt(node,timeout):
code=node.sendt("eth0","Hello World!",1,1,timeout)
msg="Send worked!" if code == 0 else "Send failed"
node.log(msg)
def execute(api):
# Should work
sendt(api,2)
# Should not work
sendt(api,0.5)
# Should work
sendt(api,2)

View file

@ -0,0 +1,16 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
B=np.full((2,2),8)
L=np.full((2,2),0)
s=esds.Simulator(B,L)
s.create_node("sender")
s.create_node("receiver")
s.run()

View file

@ -0,0 +1,7 @@
[t=0.000,src=n0] Send 1 bytes on wlan0
[t=1.000,src=n1] Receive 1 bytes on wlan0
[t=1.000,src=n1] Received: Hello World!
[t=1.000,src=n2] Receive 1 bytes on wlan0
[t=1.000,src=n2] Received: Hello World!
[t=1.000,src=n0] Send 1 bytes on wlan0
[t=1.500,src=esds] Simulation ends

View file

@ -0,0 +1,13 @@
#!/usr/bin/env python
def receive(node):
##### Simple receive
code, data=node.receive("wlan0")
msg="Received: "+data if code == 0 else "Receive failed code="+str(code)
node.log(msg)
def execute(api):
# Should works for all receivers
receive(api)

View file

@ -0,0 +1,8 @@
#!/usr/bin/env python
def execute(api):
# Should works
api.sendt("wlan0","Hello World!",1,1,2)
# Should not work
api.sendt("wlan0","Hello World!",1,1,0.5)

View file

@ -0,0 +1,17 @@
#!/usr/bin/env python
# Load ESDS
import sys
sys.path.append("../../")
import esds
import numpy as np
B=np.full((3,3),8)
L=np.full((3,3),0)
s=esds.Simulator(B,L)
s.create_node("sender")
s.create_node("receiver")
s.create_node("receiver")
s.run()

Some files were not shown because too many files have changed in this diff Show more