Commit ff6a55aa authored by Michael König's avatar Michael König

dynamic detection of new flows

parent 0ca7ef2e
# -*- coding: utf-8 -*-
# TODO:
# * dynamic flow detection
# * flowIdentifer i/o "port"
# * fix socket-input
# * dynamic value detection
import numpy as np
import math
import sys
import time
......@@ -19,7 +12,7 @@ VALUES_TO_PLOT = ['cwnd', 'sst', 'rtt', 'smoothedThroughput'] # (only values for
VALUES_TO_PROCESS = ['time'] + VALUES_TO_PLOT #helper to init all data structures
# Strings for UI-elements
FIGURE_TITLE = "TCPplot"
FIGURE_TITLE = "TCPlivePLOT"
PLOT_TITLE = "Data from"
PAUSE = "Pause"
QUIT = "Quit"
......@@ -40,6 +33,14 @@ class LiveGui(GuiBase):
self.infoRegistry = infoRegistry
self.__stopped = threading.Event()
self.timestampOfLastGuiRefresh = 0
self.__lastPlotTimestamp = {}
self.__lastDrawTimestamp = 0
self.__initRealtimeTimestamp = 0
self.__initSampletimeTimestamp = -1
self.xmin = 0
self.xmax = self.xmin + self.options.xDelta
self.flows = []
self.lineVisibility = {}
if(self.options.debug):
print("matplotlib-version: " + matplotlib.__version__)
......@@ -58,7 +59,8 @@ class LiveGui(GuiBase):
pass
def startupCheck(self):
pass
for val in VALUES_TO_PLOT:
self.lineVisibility[val] = True
def pause(self, event):
"""Toggles pause flag."""
......@@ -67,17 +69,18 @@ class LiveGui(GuiBase):
def toggleVisibility(self, lineID):
"""Toggles visibility for given line."""
for port in self.options.filterPorts:
self.__plotLineConfigs[port][lineID] ^= True
self.__plotLines[port][lineID].set_visible(self.__plotLineConfigs[port][lineID])
self.lineVisibility[lineID] ^= True
for flowIdentifier in self.__connectionBuffer:
self.__plotLineConfigs[flowIdentifier][lineID] ^= True
self.__plotLines[flowIdentifier][lineID].set_visible(self.__plotLineConfigs[flowIdentifier][lineID])
self.drawPlotLegend()
def updateValueVisibility(self, label):
for port in self.options.filterPorts:
for flowIdentifier in self.__connectionBuffer:
for i in range(1, len(VALUES_TO_PLOT)+1):
self.__plotLineConfigs[port][VALUES_TO_PLOT[(i-1)]] = False
self.__plotLines[port][(VALUES_TO_PLOT[(i-1)])].set_visible(self.__plotLineConfigs[port][(VALUES_TO_PLOT[(i-1)])])
self.__plotLineConfigs[flowIdentifier][VALUES_TO_PLOT[(i-1)]] = False
self.__plotLines[flowIdentifier][(VALUES_TO_PLOT[(i-1)])].set_visible(self.__plotLineConfigs[flowIdentifier][(VALUES_TO_PLOT[(i-1)])])
if label == 'cwnd':
self.toggleVisibility(VALUES_TO_PLOT[0])
elif label == 'sst':
......@@ -91,17 +94,22 @@ class LiveGui(GuiBase):
def drawPlotLegend(self):
"""(Re)draws legend with visible lines."""
labelObjs = []
labelTexts = []
for port in self.options.filterPorts:
for val in VALUES_TO_PLOT:
if(self.__plotLineConfigs[port][val]):
labelObjs.append(self.__plotLines[port][val])
labelTexts.append(self.__plotLines[port][val].get_label())
if(len(labelObjs) > 0):
self.__ax.legend(labelObjs, labelTexts, fontsize='small')
else:
self.__ax.legend_.remove()
if len(self.__connectionBuffer) > 0:
labelObjs = []
labelTexts = []
for flowIdentifier in self.__connectionBuffer:
if(flowIdentifier in self.flows):
for val in VALUES_TO_PLOT:
if(self.__plotLineConfigs[flowIdentifier][val]):
labelObjs.append(self.__plotLines[flowIdentifier][val])
labelTexts.append(self.__plotLines[flowIdentifier][val].get_label())
if(len(labelObjs) > 0):
self.legendVisible = True
self.__ax.legend(labelObjs, labelTexts, fontsize='small')
else:
if self.legendVisible:
self.legendVisible = False
self.__ax.legend_.remove()
def plotKeyPressCallback(self, event):
"""Callback to handle key presses."""
......@@ -129,8 +137,63 @@ class LiveGui(GuiBase):
self.__tmpTimestamp = time.perf_counter()
self.tearDown()
def updateFlowDataStructures(self):
for flowIdentifier in self.__connectionBuffer:
if(flowIdentifier not in self.flows):
self.initFlowDataStructures(flowIdentifier)
else:
outdated = self.__lastPlotTimestamp[flowIdentifier] < self.xmin
if(outdated):
self.destroyFlowDataStructures(flowIdentifier)
self.drawPlotLegend()
def initFlowDataStructures(self, flowIdentifier):
splittedFlowidentifier = flowIdentifier.split("-")
srcPort = splittedFlowidentifier[0]
dstPort = splittedFlowidentifier[1]
dstPortCount = 1
for preexistingFlow in self.flows:
flowDstPort = preexistingFlow.split("-")[1]
if flowDstPort == dstPort:
dstPortCount += 1
self.flows.append(flowIdentifier)
self.__lastPlotTimestamp[flowIdentifier] = 0
self.__plotLines[flowIdentifier] = {}
self.__plotValues[flowIdentifier] = {}
self.__plotValuesMin[flowIdentifier] = {}
self.__plotValuesMax[flowIdentifier] = {}
self.__plotLineConfigs[flowIdentifier] = {}
self.__plotLineConfigs[flowIdentifier]['lastTimestamp'] = 0
for val in VALUES_TO_PROCESS:
self.__plotValuesMin[flowIdentifier][val] = math.inf
self.__plotValuesMax[flowIdentifier][val] = -math.inf
self.__plotValues[flowIdentifier][val] = deque(maxlen=(int(self.options.xDelta / self.options.plotResolution * 10)))
index = 1
for val in VALUES_TO_PLOT:
self.__plotLines[flowIdentifier][val], = self.__ax.plot([])
self.__plotLines[flowIdentifier][val].set_label("[" + str(index) + "] " + val + " - " + str(dstPort) + " #" + str(dstPortCount) + "")
self.__plotLineConfigs[flowIdentifier][val] = self.lineVisibility[val]
self.__plotLines[flowIdentifier][val].set_visible(self.lineVisibility[val])
self.__plotLines[flowIdentifier][val].set_data([], [])
index += 1
def destroyFlowDataStructures(self, flowIdentifier):
self.flows.remove(flowIdentifier)
pass
def plotGraph(self):
"""Initializes plot configuration and starts the plotting."""
while(len(self.__connectionBuffer) < 1):
print("waiting for data on filtered flows...")
time.sleep(0.5)
if(self.options.debug):
print("initializing...")
time.sleep(1)
self.__paused = False
self.__minVal = 9999999999
self.__maxVal = 0
......@@ -148,29 +211,8 @@ class LiveGui(GuiBase):
self.__plotValuesMin = {}
self.__plotValuesMax = {}
self.__plotLineConfigs = {}
for port in self.options.filterPorts:
self.__plotLines[port] = {}
self.__plotValues[port] = {}
self.__plotValuesMin[port] = {}
self.__plotValuesMax[port] = {}
self.__plotLineConfigs[port] = {}
self.__plotLineConfigs[port]['lastTimestamp'] = 0
for val in VALUES_TO_PROCESS:
self.__plotValuesMin[port][val] = math.inf
self.__plotValuesMax[port][val] = -math.inf
self.__plotValues[port][val] = deque(maxlen=(int(self.options.xDelta / self.options.plotResolution * 10)))
index = 1
for val in VALUES_TO_PLOT:
# if(val == "rtt"):
# print("bla")
# self.__plotLines[port][val], = self.__ax2.plot([])
# else:
self.__plotLines[port][val], = self.__ax.plot([])
self.__plotLines[port][val].set_label("[" + str(index) + "] " + val + " - " + str(port) + "")
self.__plotLineConfigs[port][val] = True
self.__plotLines[port][val].set_visible(True)
index += 1
self.drawPlotLegend()
self.updateFlowDataStructures()
# pause button
pauseAx = plt.axes([0.8, 0.025, 0.1, 0.04])
......@@ -196,12 +238,6 @@ class LiveGui(GuiBase):
else:
self.__preloading = False
self.__lastPlotTimestamp = {}
for port in self.options.filterPorts:
self.__lastPlotTimestamp[port] = 0
self.__lastDrawTimestamp = 0
self.__initRealtimeTimestamp = 0
self.__initSampletimeTimestamp = -1
self.__timeOffset = 0
self.__bufferFactor = 1
......@@ -222,9 +258,9 @@ class LiveGui(GuiBase):
def returnAllLines(self):
"""Macro to return all lines as they are."""
allPlotLines = []
for port in self.options.filterPorts:
for flowIdentifier in self.__connectionBuffer:
for val in VALUES_TO_PLOT:
allPlotLines.append(self.__plotLines[port][val])
allPlotLines.append(self.__plotLines[flowIdentifier][val])
return tuple(allPlotLines)
def returnNanSample(self, time):
......@@ -237,6 +273,9 @@ class LiveGui(GuiBase):
def plotGraphUpdate(self, i):
"""Animation loop - does the actual plot update."""
self.updateFlowDataStructures()
if(self.__initSampletimeTimestamp == -1):
self.__initSampletimeTimestamp = 0
return self.returnAllLines()
......@@ -247,8 +286,8 @@ class LiveGui(GuiBase):
# fill playback-buffer
if(False and self.__preloading):
bufferLength = -1
for port in self.options.filterPorts:
bufferLength = max(bufferLength, len(self.__connectionBuffer[port]))
for flowIdentifier in self.__connectionBuffer:
bufferLength = max(bufferLength, len(self.__connectionBuffer[flowIdentifier]))
if(bufferLength > 0):
bufferedTime = bufferLength * self.options.plotResolution
......@@ -275,6 +314,8 @@ class LiveGui(GuiBase):
currentYmin, currentYmax = self.__ax.get_ylim()
newXmax = currentTimestamp - self.options.preloadBuffer
newXmin = newXmax - self.options.xDelta
self.xmin = newXmin
self.xmax = newXmax
self.__ax.set_xlim(newXmin, newXmax)
maxYval = -math.inf
......@@ -285,31 +326,34 @@ class LiveGui(GuiBase):
if(timestampDelta < self.options.plotResolution):
return self.returnAllLines()
for port in self.options.filterPorts:
connectionsData[port] = deque()
for flowIdentifier in self.__connectionBuffer:
connectionsData[flowIdentifier] = deque()
whileRun = True
while(len(self.__connectionBuffer[port]) > 0 and whileRun):
while(len(self.__connectionBuffer[flowIdentifier]) > 0 and whileRun):
try:
data = self.__connectionBuffer[port].popleft()
data = self.__connectionBuffer[flowIdentifier].popleft()
except IndexError:
whileRun = False
pass
else:
if(flowIdentifier not in self.flows):
continue
lineTime = self.__initRealtimeTimestamp + (float(data['time']) - self.__initSampletimeTimestamp)
# time in past
if(lineTime < newXmin):
continue
# time older than newst timestamp
elif(lineTime < self.__lastPlotTimestamp[port]):
elif(lineTime < self.__lastPlotTimestamp[flowIdentifier]):
continue
# skip this sample due plot plotResolution
elif((lineTime - self.__lastPlotTimestamp[port]) < self.options.plotResolution):
elif((lineTime - self.__lastPlotTimestamp[flowIdentifier]) < self.options.plotResolution):
continue
else:
if(self.__lastPlotTimestamp[port] > 0 and ((lineTime - self.__lastPlotTimestamp[port]) > CLEAR_GAP)):
self.__lastPlotTimestamp[port] = lineTime
if(self.__lastPlotTimestamp[flowIdentifier] > 0 and ((lineTime - self.__lastPlotTimestamp[flowIdentifier]) > CLEAR_GAP)):
self.__lastPlotTimestamp[flowIdentifier] = lineTime
nanSample = self.returnNanSample(lineTime)
connectionsData[port].append(nanSample)
connectionsData[flowIdentifier].append(nanSample)
infinityReached = False
for val in VALUES_TO_PLOT:
try:
......@@ -324,16 +368,16 @@ class LiveGui(GuiBase):
# infinityReached = True
if(not infinityReached):
self.__lastPlotTimestamp[port] = lineTime
connectionsData[port].append(data)
self.__lastPlotTimestamp[flowIdentifier] = lineTime
connectionsData[flowIdentifier].append(data)
data = 0
for port in connectionsData:
if(len(connectionsData[port]) > 0):
for flowIdentifier in connectionsData:
if(len(connectionsData[flowIdentifier]) > 0):
data += 1
for port in self.options.filterPorts:
if(data < 1 and currentTimestamp > self.__lastPlotTimestamp[port] ):
for flowIdentifier in self.__connectionBuffer:
if(data < 1 and currentTimestamp > self.__lastPlotTimestamp[flowIdentifier] ):
if(self.options.debug):
print("No data for any connection.")
if(self.options.interimBuffering):
......@@ -411,9 +455,10 @@ class LiveGui(GuiBase):
def plotInit(self):
"""Helper to initialize plot."""
for port in self.options.filterPorts:
for flowIdentifier in self.__connectionBuffer:
for val in VALUES_TO_PLOT:
self.__plotLines[port][val].set_data([], [])
self.__plotLines[flowIdentifier][val].set_data([], [])
newXmin = 0
newXmax = newXmin + self.options.xDelta
......@@ -426,9 +471,9 @@ class LiveGui(GuiBase):
def calculateSampleTimeOffset(self):
"""Calculate SampleTime difference at start"""
for port in self.options.filterPorts:
for flowIdentifier in self.__connectionBuffer:
try:
data = self.__connectionBuffer[port].popleft()
data = self.__connectionBuffer[flowIdentifier].popleft()
except IndexError:
pass
except KeyError:
......@@ -436,7 +481,7 @@ class LiveGui(GuiBase):
else:
# print(data)
#re-add first sample (to head of dequeue)
self.__connectionBuffer[port].appendleft(data)
self.__connectionBuffer[flowIdentifier].appendleft(data)
self.__initSampletimeTimestamp = float(data['time'])
return
......@@ -79,11 +79,14 @@ class TcpLivePlot():
if(len(tmpData) == len(LOG_FORMAT)):
data = dict(zip(LOG_FORMAT, tmpData))
# print(data)
port = int(data['dstPort'])
if(port not in self.connectionBuffer):
self.connectionBuffer[port] = deque()
self.connectionBuffer[port].append(data)
# self.incomeBuffer.append(sample)
srcPort = int(data['srcPort'])
dstPort = int(data['dstPort'])
if(dstPort in self.options.filterPorts):
flowIdentifier = str(srcPort) + "-" + str(dstPort)
if(flowIdentifier not in self.connectionBuffer):
self.connectionBuffer[flowIdentifier] = deque()
self.connectionBuffer[flowIdentifier].append(data)
# self.incomeBuffer.append(sample)
def processGui(self):
# while(not self.__stopped.wait(THREAD_STOPFLAG_WAIT)):
......@@ -97,47 +100,50 @@ class TcpLivePlot():
# plt.show()
def processInputFiltering(self):
"""
Filters retrieved data by selected port. Drops malformed data.
"""
return
lastTimestamp = 0
while(True):
try:
line = self.incomeBuffer.popleft()
except IndexError:
time.sleep(0.00001)
else:
tmpData = line.split(" ")
if(len(tmpData) is NUMBER_OF_VALUES):
data = dict(zip(LOG_FORMAT, tmpData))
else:
continue
try:
timestamp = float(data['time'])
port = int(data['dstPort'])
except ValueError:
continue
else:
if(port not in self.options.filterPorts):
continue
filteredData = {}
try:
for val in VALUES_TO_PROCESS:
filteredData[val] = float(data[val])
except ValueError:
continue
else:
timestampDelta = lastTimestamp - timestamp
if(timestampDelta > self.options.plotResolution):
lastTimestamp = timestamp
continue
self.connectionBuffer[port].append(filteredData)
lastTimestamp = timestamp
# def processInputFiltering(self):
# """
# Filters retrieved data by selected port. Drops malformed data.
# """
# return
#
# lastTimestamp = 0
# while(True):
# try:
# line = self.incomeBuffer.popleft()
# except IndexError:
# time.sleep(0.00001)
# else:
# tmpData = line.split(" ")
# if(len(tmpData) is NUMBER_OF_VALUES):
# data = dict(zip(LOG_FORMAT, tmpData))
# else:
# continue
#
# try:
# timestamp = float(data['time'])
# srcPort = int(data['srcPort'])
# dstPort = int(data['dstPort'])
# flowIdentifier = str(srcPort) + "-" + str(dstPort)
# except ValueError:
# continue
# else:
# if(dstPort in self.options.filterPorts):
# print("bar")
# filteredData = {}
# try:
# for val in VALUES_TO_PROCESS:
# filteredData[val] = float(data[val])
# except ValueError:
# continue
# else:
# timestampDelta = lastTimestamp - timestamp
# if(timestampDelta > self.options.plotResolution):
# lastTimestamp = timestamp
# continue
# self.connectionBuffer[flowIdentifier].append(filteredData)
# lastTimestamp = timestamp
# else:
# print("bar")
def handleSignals(self, signal, frame):
"""
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment