Loading eval.py +13 −4 Original line number Diff line number Diff line import sys sys.path.insert(0, "./build") import time import tests.perf as perf def run_setup_and_report(setup): results = setup.run() print("Setup:\n ", setup) print(" Parameters:\n ", setup) print(" Results:\n " + str(results).replace("\n","\n ")) if __name__ == "__main__": Loading @@ -13,8 +14,16 @@ if __name__ == "__main__": # TODO: support multiple tests via proper socket termination setups = [ perf.TestSetup(packets=2**10,delay=0,loss=30,reorder=0,duplicate=0) #perf.TestSetup(packets=100,delay=0,loss=0,reorder=0,duplicate=0), # smoke test #perf.TestSetup(packets=500,delay=10,loss=1,reorder=0,duplicate=0), # stability #perf.TestSetup(packets=2**11,delay=0,loss=0,reorder=0,duplicate=0), # smoke test perf.TestSetup(packets=100,delay=10,loss=50,reorder=0,duplicate=0, packet_interval=0.01) # freaky ] i = 1 for setup in setups: print("Setup #%d:" % i) run_setup_and_report(setup) i += 1 time.sleep(2) print("\n") prrt/prrt.pyx +1 −1 Original line number Diff line number Diff line Loading @@ -109,7 +109,7 @@ cdef class PrrtSocket: raise Exception("Not a sender.") return cprrt.PrrtSocket_get_rtt(self._c_socket) * 0.000001 def recv(self): def recv(self, wait_time): cdef char buffer[65536] cdef int32_t len with nogil: Loading tests/perf/__init__.py +32 −21 Original line number Diff line number Diff line Loading @@ -21,8 +21,12 @@ class ReceiverThread(threading.Thread): self.receivedPackets[:] = np.NAN def run(self): while(1): data = self.sock.recv() while(self.running): try: data = self.sock.recv(1000000) except prrt.TimeoutException: continue v = data.decode('UTF-8') seqno = v[:self.seqnoDigits] if seqno in self.received: Loading @@ -34,11 +38,12 @@ class ReceiverThread(threading.Thread): class SenderThread(threading.Thread): def __init__(self, seqnoDigits, packetCount): def __init__(self, seqnoDigits, packetCount, packetInterval): threading.Thread.__init__(self) self.sock = prrt.PrrtSocket(7005, True, 1) self.packetCount = packetCount self.seqnoDigits = seqnoDigits self.packetInterval = packetInterval self.sentPackets = np.ndarray((packetCount),dtype="datetime64[us]") self.sentPackets[:] = np.NAN Loading @@ -46,26 +51,30 @@ class SenderThread(threading.Thread): # TODO: create proper arrays def run(self): self.sock.connect("127.244.0.1", 7000) self.sock.connect("127.0.0.1", 7000) for i in range(self.packetCount): d = str(i).zfill(self.seqnoDigits).encode("UTF-8") self.sentPackets[i] = datetime.datetime.now() self.sock.send(d) time.sleep(0.00001) time.sleep(self.packetInterval) class TestResults(object): def __init__(self): def __init__(self, showLossPattern=True): self.loss = 0 self.packetsSent = 0 self.packetsReceived = 0 self.duplicates = 0 self.delays = None self.showLossPattern = showLossPattern def __str__(self): delayValues = self.delays[~np.isnan(self.delays)] plr = 1 - (self.packetsReceived / self.packetsSent) loss = "Residual Loss: %f%% (received %d of %d)" % (plr * 100, self.packetsReceived, self.packetsSent) loss = "Residual Loss: %f%% (received %d / %d)" % (plr * 100, self.packetsReceived, self.packetsSent) duplicates = "Duplicates: %d" % (self.duplicates) if len(delayValues) == 0: return "No packets successfully transmitted." delayMean = np.mean(delayValues) * 1000 delayStd = np.std(delayValues) * 1000 delayMin = np.min(delayValues) * 1000 Loading @@ -84,38 +93,40 @@ class TestResults(object): return "%s\n%s\n%s\n%s" % (loss, duplicates, delays, losses) class TestSetup(object): def __init__(self,packets=20,delay=1,delay_variation=0,delay_correlation=0,loss=0,loss_correlation=0,duplicate=0,reorder=0,reorder_correlation=0): def __init__(self, packets=20, packet_interval=0.0001, delay=1, delay_variation=0, delay_correlation=0, loss=0, loss_correlation=0, duplicate=0, reorder=0, reorder_correlation=0, loss_pattern=True): self.packets = packets self.delay = delay self.delay_variation = delay_variation self.delay_correlation = delay_correlation self.delayVariation = delay_variation self.delayCorrelation = delay_correlation self.loss = loss self.loss_correlation = loss_correlation self.lossCorrelation = loss_correlation self.duplicate = duplicate self.reorder = reorder self.reorder_correlation = reorder_correlation self.processing_delay = 0.0001 # in ms self.reorderCorrelation = reorder_correlation self.packetInterval = packet_interval # in s self.processingDelay = packet_interval def netem_config(self): def netemConfigString(self): # http://www.linuxfoundation.org/collaborate/workgroups/networking/netem return "delay %dus %dus %d%% loss %f%% %f%% duplicate %f%% reorder %f%% %f%%" % ( self.delay, self.delay_variation, self.delay_correlation, self.loss, self.loss_correlation, self.duplicate, self.reorder, self.reorder_correlation) self.delay, self.delayVariation, self.delayCorrelation, self.loss, self.lossCorrelation, self.duplicate, self.reorder, self.reorderCorrelation) def run(self): # TODO: create and apply only to specific traffic subprocess.run("tc qdisc add dev lo root netem " + self.netem_config(), shell=True) subprocess.run("tc qdisc add dev lo root netem " + self.netemConfigString(), shell=True) seqnoDigits = math.ceil(math.log10(self.packets)) recvThread = ReceiverThread(seqnoDigits, self.packets) recvThread.daemon = True sendThread = SenderThread(seqnoDigits, self.packets) sendThread = SenderThread(seqnoDigits, self.packets, self.packetInterval) recvThread.start() sendThread.run() recvThread.running = False time.sleep(1) #time.sleep(1 + self.packets * (self.delay / (1000**2) + self.processing_delay)) count = len(recvThread.received) diffs = map(lambda x: x.item().total_seconds() if x.item() is not None else np.NAN, Loading @@ -124,7 +135,7 @@ class TestSetup(object): subprocess.run("tc qdisc del dev lo root", shell=True, check=True) results = TestResults() results = TestResults(showLossPattern=self.showLossPattern) results.packetsSent = self.packets results.packetsReceived = count results.duplicates = recvThread.duplicates Loading @@ -132,4 +143,4 @@ class TestSetup(object): return results def __str__(self): return self.netem_config() return self.netemConfigString() Loading
eval.py +13 −4 Original line number Diff line number Diff line import sys sys.path.insert(0, "./build") import time import tests.perf as perf def run_setup_and_report(setup): results = setup.run() print("Setup:\n ", setup) print(" Parameters:\n ", setup) print(" Results:\n " + str(results).replace("\n","\n ")) if __name__ == "__main__": Loading @@ -13,8 +14,16 @@ if __name__ == "__main__": # TODO: support multiple tests via proper socket termination setups = [ perf.TestSetup(packets=2**10,delay=0,loss=30,reorder=0,duplicate=0) #perf.TestSetup(packets=100,delay=0,loss=0,reorder=0,duplicate=0), # smoke test #perf.TestSetup(packets=500,delay=10,loss=1,reorder=0,duplicate=0), # stability #perf.TestSetup(packets=2**11,delay=0,loss=0,reorder=0,duplicate=0), # smoke test perf.TestSetup(packets=100,delay=10,loss=50,reorder=0,duplicate=0, packet_interval=0.01) # freaky ] i = 1 for setup in setups: print("Setup #%d:" % i) run_setup_and_report(setup) i += 1 time.sleep(2) print("\n")
prrt/prrt.pyx +1 −1 Original line number Diff line number Diff line Loading @@ -109,7 +109,7 @@ cdef class PrrtSocket: raise Exception("Not a sender.") return cprrt.PrrtSocket_get_rtt(self._c_socket) * 0.000001 def recv(self): def recv(self, wait_time): cdef char buffer[65536] cdef int32_t len with nogil: Loading
tests/perf/__init__.py +32 −21 Original line number Diff line number Diff line Loading @@ -21,8 +21,12 @@ class ReceiverThread(threading.Thread): self.receivedPackets[:] = np.NAN def run(self): while(1): data = self.sock.recv() while(self.running): try: data = self.sock.recv(1000000) except prrt.TimeoutException: continue v = data.decode('UTF-8') seqno = v[:self.seqnoDigits] if seqno in self.received: Loading @@ -34,11 +38,12 @@ class ReceiverThread(threading.Thread): class SenderThread(threading.Thread): def __init__(self, seqnoDigits, packetCount): def __init__(self, seqnoDigits, packetCount, packetInterval): threading.Thread.__init__(self) self.sock = prrt.PrrtSocket(7005, True, 1) self.packetCount = packetCount self.seqnoDigits = seqnoDigits self.packetInterval = packetInterval self.sentPackets = np.ndarray((packetCount),dtype="datetime64[us]") self.sentPackets[:] = np.NAN Loading @@ -46,26 +51,30 @@ class SenderThread(threading.Thread): # TODO: create proper arrays def run(self): self.sock.connect("127.244.0.1", 7000) self.sock.connect("127.0.0.1", 7000) for i in range(self.packetCount): d = str(i).zfill(self.seqnoDigits).encode("UTF-8") self.sentPackets[i] = datetime.datetime.now() self.sock.send(d) time.sleep(0.00001) time.sleep(self.packetInterval) class TestResults(object): def __init__(self): def __init__(self, showLossPattern=True): self.loss = 0 self.packetsSent = 0 self.packetsReceived = 0 self.duplicates = 0 self.delays = None self.showLossPattern = showLossPattern def __str__(self): delayValues = self.delays[~np.isnan(self.delays)] plr = 1 - (self.packetsReceived / self.packetsSent) loss = "Residual Loss: %f%% (received %d of %d)" % (plr * 100, self.packetsReceived, self.packetsSent) loss = "Residual Loss: %f%% (received %d / %d)" % (plr * 100, self.packetsReceived, self.packetsSent) duplicates = "Duplicates: %d" % (self.duplicates) if len(delayValues) == 0: return "No packets successfully transmitted." delayMean = np.mean(delayValues) * 1000 delayStd = np.std(delayValues) * 1000 delayMin = np.min(delayValues) * 1000 Loading @@ -84,38 +93,40 @@ class TestResults(object): return "%s\n%s\n%s\n%s" % (loss, duplicates, delays, losses) class TestSetup(object): def __init__(self,packets=20,delay=1,delay_variation=0,delay_correlation=0,loss=0,loss_correlation=0,duplicate=0,reorder=0,reorder_correlation=0): def __init__(self, packets=20, packet_interval=0.0001, delay=1, delay_variation=0, delay_correlation=0, loss=0, loss_correlation=0, duplicate=0, reorder=0, reorder_correlation=0, loss_pattern=True): self.packets = packets self.delay = delay self.delay_variation = delay_variation self.delay_correlation = delay_correlation self.delayVariation = delay_variation self.delayCorrelation = delay_correlation self.loss = loss self.loss_correlation = loss_correlation self.lossCorrelation = loss_correlation self.duplicate = duplicate self.reorder = reorder self.reorder_correlation = reorder_correlation self.processing_delay = 0.0001 # in ms self.reorderCorrelation = reorder_correlation self.packetInterval = packet_interval # in s self.processingDelay = packet_interval def netem_config(self): def netemConfigString(self): # http://www.linuxfoundation.org/collaborate/workgroups/networking/netem return "delay %dus %dus %d%% loss %f%% %f%% duplicate %f%% reorder %f%% %f%%" % ( self.delay, self.delay_variation, self.delay_correlation, self.loss, self.loss_correlation, self.duplicate, self.reorder, self.reorder_correlation) self.delay, self.delayVariation, self.delayCorrelation, self.loss, self.lossCorrelation, self.duplicate, self.reorder, self.reorderCorrelation) def run(self): # TODO: create and apply only to specific traffic subprocess.run("tc qdisc add dev lo root netem " + self.netem_config(), shell=True) subprocess.run("tc qdisc add dev lo root netem " + self.netemConfigString(), shell=True) seqnoDigits = math.ceil(math.log10(self.packets)) recvThread = ReceiverThread(seqnoDigits, self.packets) recvThread.daemon = True sendThread = SenderThread(seqnoDigits, self.packets) sendThread = SenderThread(seqnoDigits, self.packets, self.packetInterval) recvThread.start() sendThread.run() recvThread.running = False time.sleep(1) #time.sleep(1 + self.packets * (self.delay / (1000**2) + self.processing_delay)) count = len(recvThread.received) diffs = map(lambda x: x.item().total_seconds() if x.item() is not None else np.NAN, Loading @@ -124,7 +135,7 @@ class TestSetup(object): subprocess.run("tc qdisc del dev lo root", shell=True, check=True) results = TestResults() results = TestResults(showLossPattern=self.showLossPattern) results.packetsSent = self.packets results.packetsReceived = count results.duplicates = recvThread.duplicates Loading @@ -132,4 +143,4 @@ class TestSetup(object): return results def __str__(self): return self.netem_config() return self.netemConfigString()