diff options
author | Florin Coras <fcoras@cisco.com> | 2019-06-12 08:12:58 -0700 |
---|---|---|
committer | Damjan Marion <dmarion@me.com> | 2019-06-12 17:14:39 +0000 |
commit | 3417d08700168d9a7c0fe561e40e73478d5e1229 (patch) | |
tree | 2715bd489ab1277d24017ad0ee12033f028d4472 /src/scripts/host-stack/cc_plots.py | |
parent | 26ce6ca1fe6f524a9049444fe8d55042fd7530a6 (diff) |
tcp: add cc stats plotting tools
Type: feature
cc_plot.py can plot cc stats collected via elogs from tcp connections.
To enable the collection of cc stats, tcp must be compiled with
TCP_DEBUG_CC_STAT turned on.
Once the tests have been carried out, and elogs have been saved with "ev
save log <file>", the logs can be converted to txt format with the
convert_evt script. The resulting file can be used as input to the
cc_plots script.
Change-Id: I16df2993fa09cab9ad35f91825eab7df4da6428b
Signed-off-by: Florin Coras <fcoras@cisco.com>
Diffstat (limited to 'src/scripts/host-stack/cc_plots.py')
-rwxr-xr-x | src/scripts/host-stack/cc_plots.py | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/src/scripts/host-stack/cc_plots.py b/src/scripts/host-stack/cc_plots.py new file mode 100755 index 00000000000..ea2d4c94353 --- /dev/null +++ b/src/scripts/host-stack/cc_plots.py @@ -0,0 +1,219 @@ +#!/usr/bin/env python + +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)) |