Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
T
TCPlivePLOT
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
CPUnetLOG
TCPlivePLOT
Commits
ff6a55aa
Commit
ff6a55aa
authored
Oct 28, 2016
by
Michael König
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dynamic detection of new flows
parent
0ca7ef2e
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
176 additions
and
125 deletions
+176
-125
tcpliveplot/backends/gui/live.py
tcpliveplot/backends/gui/live.py
+124
-79
tcpliveplot/tcpliveplot.py
tcpliveplot/tcpliveplot.py
+52
-46
No files found.
tcpliveplot/backends/gui/live.py
View file @
ff6a55aa
# -*- 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
=
"TCP
plot
"
FIGURE_TITLE
=
"TCP
livePLOT
"
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
tcpliveplot/tcpliveplot.py
View file @
ff6a55aa
...
...
@@ -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
):
"""
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment