blob: ea2d4c94353f87ab3b29c26ca454abe4ed00175b [file] [log] [blame]
Florin Coras3417d082019-06-12 08:12:58 -07001#!/usr/bin/env python
2
3import sys
4import re
5import argparse
6import matplotlib.pyplot as plt
7from matplotlib.lines import Line2D
8
9class Point():
10 "CC event"
11 def __init__(self, x, y):
12 self.x = x
13 self.y = y
14
15def listx(points):
16 return list(map(lambda pt: pt.x, points))
17
18def listy(points):
19 return list(map(lambda pt: pt.y, points))
20
21def plot_data(d):
22
23 plt.figure(1)
24
25 cwndx = listx(d["cwnd"])
26 cwndy = listy(d["cwnd"])
27 congx = listx(d["congestion"])
28 congy = listy(d["congestion"])
29 rcvrdx = listx(d["recovered"])
30 rcvrdy = listy(d["recovered"])
31 rxttx = listx(d["rxtTimeout"])
32 rxtty = listy(d["rxtTimeout"])
33
34 # cwnd/ssthresh/cc events
35 plt.subplot(311)
36 plt.title("cwnd/ssthresh")
37 pcwnd = plt.plot(cwndx, cwndy, 'r')
38 psst = plt.plot(cwndx, d["ssthresh"], 'y-')
39 pcong = plt.plot(congx, congy,'yo')
40 precov = plt.plot(rcvrdx, rcvrdy,'co')
41 prxtt = plt.plot(rxttx, rxtty,'mo')
42
43 marker1 = Line2D(range(1), range(1), color="r")
44 marker2 = Line2D(range(1), range(1), color="y")
45 marker3 = Line2D(range(1), range(1), color="w", marker="o", markerfacecolor="y")
46 marker4 = Line2D(range(1), range(1), color="w", marker="o", markerfacecolor="c")
47 marker5 = Line2D(range(1), range(1), color="w", marker="o", markerfacecolor="m")
48 plt.legend((marker1, marker2, marker3, marker4, marker5),
49 ('cwnd', 'ssthresh', 'congestion', 'recovered', 'rxt-timeout'),
50 loc=4)
51 axes = plt.gca()
52 axes.set_ylim([-20e4, max(cwndy) + 20e4])
53
54 # snd variables
55 plt.subplot(312)
56 plt.title("cc variables")
57 plt.plot(cwndx, d["space"], 'g-', markersize=1)
58 plt.plot(cwndx, d["flight"], 'b-', markersize=1)
59 plt.plot(cwndx, d["sacked"], 'm:', markersize=1)
60 plt.plot(cwndx, d["lost"], 'y:', markersize=1)
61 plt.plot(cwndx, d["cc-space"], 'k:', markersize=1)
62 plt.plot(cwndx, cwndy, 'ro', markersize=2)
63
64 plt.plot(congx, congy, 'y^', markersize=10, markerfacecolor="y")
65 plt.plot(rcvrdx, rcvrdy, 'c^', markersize=10, markerfacecolor="c")
66 plt.plot(rxttx, rxtty, 'm^', markersize=10, markerfacecolor="m")
67
68 #plt.plot(cwndx, d["snd_wnd"], 'ko', markersize=1)
69 plt.legend(("snd-space", "flight", "sacked", "lost", "cc-space", "cwnd",
70 "congestion", "recovered", "rxt-timeout"),
71 loc=1)
72
73 # rto/srrt/rttvar
74 plt.subplot(313)
75 plt.title("rtt")
76 plt.plot(cwndx, d["srtt"], 'g-')
77 plt.plot(cwndx, [x/1000 for x in d["mrtt-us"]], 'r-')
78 plt.plot(cwndx, d["rttvar"], 'b-')
79 plt.legend(["srtt", "mrtt-us", "rttvar"])
80 axes = plt.gca()
81 #plt.plot(cwndx, rto, 'r-')
82 #axes.set_ylim([0, int(max(rto[2:len(rto)])) + 50])
83
84 # show
85 plt.show()
86
87def find_pattern(file_path,session_idx):
88 is_active_open = 1
89 listener_pattern = "l\[\d\]"
90 if (is_active_open):
91 initial_pattern = "\[\d\](\.\d+:\d+\->\.\d+:\d+)\s+open:\s"
92 else:
93 initial_pattern = "\[\d\](\.\d+:\d+\->\.\d+:\d+)\s"
94 idx = 0
95 f = open(file_path, 'r')
96 for line in f:
97 # skip listener lines (server)
98 if (re.search(listener_pattern, line) != None):
99 continue
100 match = re.search(initial_pattern, line)
101 if (match == None):
102 continue
103 if (idx < session_idx):
104 idx += 1
105 continue
106 filter_pattern = str(match.group(1)) + "\s+(.+)"
107 print ("pattern is %s" % filter_pattern)
108 f.close()
109 return filter_pattern
110 raise Exception ("Could not find initial pattern")
111
112def compute_time(min, sec, msec):
113 return int(min)*60 + int(sec) + int(msec)/1000.0
114
115def run(file_path, session_idx):
116 filter_sessions = 1
117 filter_pattern = ""
118
119 patterns = {
120 "time" : "^\d+:(\d+):(\d+):(\d+):\d+",
121 "listener" : "l\[\d\]",
122 "cc" : "cwnd (\d+) flight (\d+) space (\d+) ssthresh (\d+) snd_wnd (\d+)",
123 "cc-snd" : "cc_space (\d+) sacked (\d+) lost (\d+)",
124 "rtt" : "rto (\d+) srtt (\d+) mrtt-us (\d+) rttvar (\d+)",
125 "rxtt" : "rxt-timeout",
126 "congestion": "congestion",
127 "recovered" : "recovered",
128 }
129 d = {
130 "cwnd" : [],
131 "space" : [],
132 "flight" : [],
133 "ssthresh" : [],
134 "snd_wnd" : [],
135 "cc-space" : [],
136 "lost" : [],
137 "sacked" : [],
138 "rto" : [],
139 "srtt" : [],
140 "mrtt-us" : [],
141 "rttvar" : [],
142 "rxtTimeout" : [],
143 "congestion" : [],
144 "recovered" : [],
145 }
146
147 if (filter_sessions):
148 filter_pattern = find_pattern(file_path, session_idx)
149 f = open(file_path, 'r')
150
151 stats_index = 0
152 start_time = 0
153
154 for line in f:
155 # skip listener lines (server)
156 if (re.search(patterns["listener"], line) != None):
157 continue
158 # filter sessions
159 if (filter_sessions):
160 match = re.search(filter_pattern, line)
161 if (match == None):
162 continue
163
164 original_line = line
165 line = match.group(1)
166 match = re.search (patterns["time"], original_line)
167 if (match == None):
168 print "something went wrong! no time!"
169 continue
170 time = compute_time (match.group(1), match.group(2), match.group(3))
171 if (start_time == 0):
172 start_time = time
173
174 time = time - start_time
175 match = re.search(patterns["cc"], line)
176 if (match != None):
177 d["cwnd"].append(Point(time, int(match.group(1))))
178 d["flight"].append(int(match.group(2)))
179 d["space"].append(int(match.group(3)))
180 d["ssthresh"].append(int(match.group(4)))
181 d["snd_wnd"].append(int(match.group(5)))
182 stats_index += 1
183 continue
184 match = re.search(patterns["cc-snd"], line)
185 if (match != None):
186 d["cc-space"].append(int(match.group(1)))
187 d["sacked"].append(int(match.group(2)))
188 d["lost"].append(int(match.group(3)))
189 match = re.search(patterns["rtt"], line)
190 if (match != None):
191 d["rto"].append(int(match.group(1)))
192 d["srtt"].append(int(match.group(2)))
193 d["mrtt-us"].append(int(match.group(3)))
194 d["rttvar"].append(int(match.group(4)))
195 if (stats_index == 0):
196 continue
197 match = re.search(patterns["rxtt"], line)
198 if (match != None):
199 d["rxtTimeout"].append(Point(time, d["cwnd"][stats_index - 1].y + 1e4))
200 continue
201 match = re.search(patterns["congestion"], line)
202 if (match != None):
203 d["congestion"].append(Point(time, d["cwnd"][stats_index - 1].y - 1e4))
204 continue
205 match = re.search(patterns["recovered"], line)
206 if (match != None):
207 d["recovered"].append(Point(time, d["cwnd"][stats_index - 1].y))
208 continue
209
210 plot_data(d)
211
212if __name__ == "__main__":
213 parser = argparse.ArgumentParser(description="Plot tcp cc logs")
214 parser.add_argument('-f', action='store', dest='file', required=True,
215 help="elog file in txt format")
216 parser.add_argument('-s', action='store', dest='session_index', default=0,
217 help="session index for which to plot cc logs" )
218 results = parser.parse_args()
219 run(results.file, int(results.session_index))