blob: f7953f223d4a672f23a0031410a2f04968b4edf0 [file] [log] [blame]
#!/usr/bin/env python3
import sys
import re
import argparse
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
class Point:
"CC event"
def __init__(self, x, y):
self.x = x
self.y = y
def listx(points):
return list(map(lambda pt: pt.x, points))
def listy(points):
return list(map(lambda pt: pt.y, points))
def plot_data(d):
plt.figure(1)
cwndx = listx(d["cwnd"])
cwndy = listy(d["cwnd"])
congx = listx(d["congestion"])
congy = listy(d["congestion"])
rcvrdx = listx(d["recovered"])
rcvrdy = listy(d["recovered"])
rxttx = listx(d["rxtTimeout"])
rxtty = listy(d["rxtTimeout"])
# cwnd/ssthresh/cc events
plt.subplot(311)
plt.title("cwnd/ssthresh")
pcwnd = plt.plot(cwndx, cwndy, "r")
psst = plt.plot(cwndx, d["ssthresh"], "y-")
pcong = plt.plot(congx, congy, "yo")
precov = plt.plot(rcvrdx, rcvrdy, "co")
prxtt = plt.plot(rxttx, rxtty, "mo")
marker1 = Line2D(range(1), range(1), color="r")
marker2 = Line2D(range(1), range(1), color="y")
marker3 = Line2D(range(1), range(1), color="w", marker="o", markerfacecolor="y")
marker4 = Line2D(range(1), range(1), color="w", marker="o", markerfacecolor="c")
marker5 = Line2D(range(1), range(1), color="w", marker="o", markerfacecolor="m")
plt.legend(
(marker1, marker2, marker3, marker4, marker5),
("cwnd", "ssthresh", "congestion", "recovered", "rxt-timeout"),
loc=4,
)
axes = plt.gca()
axes.set_ylim([-20e4, max(cwndy) + 20e4])
# snd variables
plt.subplot(312)
plt.title("cc variables")
plt.plot(cwndx, d["space"], "g-", markersize=1)
plt.plot(cwndx, d["flight"], "b-", markersize=1)
plt.plot(cwndx, d["sacked"], "m:", markersize=1)
plt.plot(cwndx, d["lost"], "y:", markersize=1)
plt.plot(cwndx, d["cc-space"], "k:", markersize=1)
plt.plot(cwndx, cwndy, "ro", markersize=2)
plt.plot(congx, congy, "y^", markersize=10, markerfacecolor="y")
plt.plot(rcvrdx, rcvrdy, "c^", markersize=10, markerfacecolor="c")
plt.plot(rxttx, rxtty, "m^", markersize=10, markerfacecolor="m")
# plt.plot(cwndx, d["snd_wnd"], 'ko', markersize=1)
plt.legend(
(
"snd-space",
"flight",
"sacked",
"lost",
"cc-space",
"cwnd",
"congestion",
"recovered",
"rxt-timeout",
),
loc=1,
)
# rto/srrt/rttvar
plt.subplot(313)
plt.title("rtt")
plt.plot(cwndx, d["srtt"], "g-")
plt.plot(cwndx, [x / 1000 for x in d["mrtt-us"]], "r-")
plt.plot(cwndx, d["rttvar"], "b-")
plt.legend(["srtt", "mrtt-us", "rttvar"])
axes = plt.gca()
# plt.plot(cwndx, rto, 'r-')
# axes.set_ylim([0, int(max(rto[2:len(rto)])) + 50])
# show
plt.show()
def find_pattern(file_path, session_idx):
is_active_open = 1
listener_pattern = "l\[\d\]"
if is_active_open:
initial_pattern = "\[\d\](\.\d+:\d+\->\.\d+:\d+)\s+open:\s"
else:
initial_pattern = "\[\d\](\.\d+:\d+\->\.\d+:\d+)\s"
idx = 0
f = open(file_path, "r")
for line in f:
# skip listener lines (server)
if re.search(listener_pattern, line) != None:
continue
match = re.search(initial_pattern, line)
if match == None:
continue
if idx < session_idx:
idx += 1
continue
filter_pattern = str(match.group(1)) + "\s+(.+)"
print("pattern is %s" % filter_pattern)
f.close()
return filter_pattern
raise Exception("Could not find initial pattern")
def compute_time(min, sec, msec):
return int(min) * 60 + int(sec) + int(msec) / 1000.0
def run(file_path, session_idx):
filter_sessions = 1
filter_pattern = ""
patterns = {
"time": "^\d+:(\d+):(\d+):(\d+):\d+",
"listener": "l\[\d\]",
"cc": "cwnd (\d+) flight (\d+) space (\d+) ssthresh (\d+) snd_wnd (\d+)",
"cc-snd": "cc_space (\d+) sacked (\d+) lost (\d+)",
"rtt": "rto (\d+) srtt (\d+) mrtt-us (\d+) rttvar (\d+)",
"rxtt": "rxt-timeout",
"congestion": "congestion",
"recovered": "recovered",
}
d = {
"cwnd": [],
"space": [],
"flight": [],
"ssthresh": [],
"snd_wnd": [],
"cc-space": [],
"lost": [],
"sacked": [],
"rto": [],
"srtt": [],
"mrtt-us": [],
"rttvar": [],
"rxtTimeout": [],
"congestion": [],
"recovered": [],
}
if filter_sessions:
filter_pattern = find_pattern(file_path, session_idx)
f = open(file_path, "r")
stats_index = 0
start_time = 0
for line in f:
# skip listener lines (server)
if re.search(patterns["listener"], line) != None:
continue
# filter sessions
if filter_sessions:
match = re.search(filter_pattern, line)
if match == None:
continue
original_line = line
line = match.group(1)
match = re.search(patterns["time"], original_line)
if match == None:
print("something went wrong! no time!")
continue
time = compute_time(match.group(1), match.group(2), match.group(3))
if start_time == 0:
start_time = time
time = time - start_time
match = re.search(patterns["cc"], line)
if match != None:
d["cwnd"].append(Point(time, int(match.group(1))))
d["flight"].append(int(match.group(2)))
d["space"].append(int(match.group(3)))
d["ssthresh"].append(int(match.group(4)))
d["snd_wnd"].append(int(match.group(5)))
stats_index += 1
continue
match = re.search(patterns["cc-snd"], line)
if match != None:
d["cc-space"].append(int(match.group(1)))
d["sacked"].append(int(match.group(2)))
d["lost"].append(int(match.group(3)))
match = re.search(patterns["rtt"], line)
if match != None:
d["rto"].append(int(match.group(1)))
d["srtt"].append(int(match.group(2)))
d["mrtt-us"].append(int(match.group(3)))
d["rttvar"].append(int(match.group(4)))
if stats_index == 0:
continue
match = re.search(patterns["rxtt"], line)
if match != None:
d["rxtTimeout"].append(Point(time, d["cwnd"][stats_index - 1].y + 1e4))
continue
match = re.search(patterns["congestion"], line)
if match != None:
d["congestion"].append(Point(time, d["cwnd"][stats_index - 1].y - 1e4))
continue
match = re.search(patterns["recovered"], line)
if match != None:
d["recovered"].append(Point(time, d["cwnd"][stats_index - 1].y))
continue
plot_data(d)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Plot tcp cc logs")
parser.add_argument(
"-f", action="store", dest="file", required=True, help="elog file in txt format"
)
parser.add_argument(
"-s",
action="store",
dest="session_index",
default=0,
help="session index for which to plot cc logs",
)
results = parser.parse_args()
run(results.file, int(results.session_index))