blob: 9eb022eb44519038e8ddb48d58757d3747552be9 [file] [log] [blame]
brianb87e3b12014-01-12 22:12:14 -08001#!/usr/bin/python
2'''
3 Script that tests Flow Manager performance
4 Author: Brian O'Connor <bocon@onlab.us>
5
6'''
7
8import csv
9import os
10import sys
Brian O'Connor0d9963f2014-01-14 14:44:21 -080011import re
brianb87e3b12014-01-12 22:12:14 -080012from time import sleep, strftime
13from subprocess import Popen, call, check_output, PIPE
14from datetime import datetime
15
16try:
17 import pexpect
18except:
19 # install pexpect if it cannot be found and re-import
20 print '* Installing Pexpect'
21 call( 'apt-get install -y python-pexpect', stdout=PIPE, shell=True )
22 import pexpect
23
24ONOS_HOME = '..'
25ONOS_LOG = '%s/onos-logs/onos.%s.log' % ( ONOS_HOME, check_output( 'hostname').strip() )
Brian O'Connor0d9963f2014-01-14 14:44:21 -080026ONOS_URL = 'http://127.0.0.1:8080/wm/onos/flows/get/%d/json'
27ONOS_LOG = '/tmp/onos-0.logs/onos.onos-vm.log'
brianb87e3b12014-01-12 22:12:14 -080028print "ONOS Log File:", ONOS_LOG
29
30PORT = 's1-eth2'
brian6df88232014-01-14 17:05:07 -080031N = 1
brianb87e3b12014-01-12 22:12:14 -080032
33# ----------------- Running the test and output -------------------------
34
Brian O'Connor0d9963f2014-01-14 14:44:21 -080035class Result(object):
36 def __init__(self, tsharkTime, flowmods, onosTime, overhead, details):
37 self.tsharkTime = tsharkTime
38 self.flowmods = flowmods
39 self.onosTime = onosTime
40 self.overhead = overhead
41 # sorted by start time
brian6df88232014-01-14 17:05:07 -080042 self.tags = sorted(details, key=lambda x: float(x[2]))
43 self.details = sorted(details, key=lambda x: float(x[2]), reverse=True)
Brian O'Connor0d9963f2014-01-14 14:44:21 -080044
45 def __repr__(self):
brian6df88232014-01-14 17:05:07 -080046 return '%f %f %f %d %s' % (self.tsharkTime, self.onosTime, self.overhead, self.flowmods, self.tags)
Brian O'Connor0d9963f2014-01-14 14:44:21 -080047
48
49def clearResults():
50 cmd = 'curl %s' % ONOS_URL % -200
51 call( cmd, shell=True )
52 pass
53
54def reportResults():
55 cmd = 'curl %s' % ONOS_URL % -100
56 call( cmd, shell=True )
brianb87e3b12014-01-12 22:12:14 -080057
58def test():
59 # Start tailing the onos log
60 tail = pexpect.spawn( "tail -0f %s" % ONOS_LOG )
Brian O'Connor0d9963f2014-01-14 14:44:21 -080061 tshark = pexpect.spawn( 'tshark -i lo -R "of.type == 12 || of.type == 14"' )
62 tshark.expect('Capturing on lo')
63 sleep(1) # wait for tshark to start
brianb87e3b12014-01-12 22:12:14 -080064
Brian O'Connor0d9963f2014-01-14 14:44:21 -080065 clearResults() # REST call to ONOS
brianb87e3b12014-01-12 22:12:14 -080066 # Take link down
67 call( 'ifconfig %s down' % PORT, shell=True )
68
Brian O'Connor0d9963f2014-01-14 14:44:21 -080069 # collect openflow packets using tshark
70 count = 0
71 timeout = 6000
72 start = -1
73 end = -1
74 while True:
75 i = tshark.expect( ['(\d+\.\d+)', pexpect.TIMEOUT], timeout=timeout )
76 if i == 1:
77 break
78 time = float(tshark.match.group(1))
79 if start == -1:
80 start = time
81 if time > end:
82 end = time
83 i = tshark.expect( ['Port Status', 'Flow Mod'] )
84 if i == 1:
85 count += 1
86 timeout = 3 #sec
87 elapsed = (end - start) * 1000
brianb87e3b12014-01-12 22:12:14 -080088
brian6df88232014-01-14 17:05:07 -080089 sleep(2)
Brian O'Connor0d9963f2014-01-14 14:44:21 -080090 # read the performance results from ONOS
91 reportResults() # REST call
92
93 # Wait for performance results in the log
94 tail.expect('Performance Results: \(avg/start/stop/count\)', timeout=10)
95 i = tail.expect('TotalTime:([\d\.]+)/Overhead:([\d\.]+)')
96 totalTime = float(tail.match.group(1))
97 overhead = float(tail.match.group(2))
98 tags = re.findall( r'([\w\.]+)=([\d\.]+)/([\d\.]+)/([\d\.]+)/(\d+)', tail.before )
99 result = Result(elapsed, count, totalTime, overhead, tags)
brianb87e3b12014-01-12 22:12:14 -0800100 # Output results
Brian O'Connor0d9963f2014-01-14 14:44:21 -0800101 print result
brian6df88232014-01-14 17:05:07 -0800102 plot(result)
Brian O'Connor0d9963f2014-01-14 14:44:21 -0800103
brianb87e3b12014-01-12 22:12:14 -0800104 # Bring port back up
105 call( 'ifconfig %s up' % PORT, shell=True )
106
107 tail.terminate()
Brian O'Connor0d9963f2014-01-14 14:44:21 -0800108 tshark.terminate()
109 return []
brianb87e3b12014-01-12 22:12:14 -0800110
111def outputResults(filename, results):
112 with open(filename, 'a') as csvfile:
113 writer = csv.writer(csvfile)
114 writer.writerow(results)
115
116def runPerf(n):
117 filename = 'results-flowmanager-%s.csv' % strftime( '%Y%m%d-%H%M%S' )
118 print 'Starting experiments:'
119 start = datetime.now()
120 for i in range(n):
121 results = test()
Brian O'Connor0d9963f2014-01-14 14:44:21 -0800122 #outputResults(filename, results)
123 sys.stdout.write('$')
124 sys.stdout.flush()
125 sleep(5) # sleep for 5 seconds between tests
brianb87e3b12014-01-12 22:12:14 -0800126 sys.stdout.write('.')
127 sys.stdout.flush()
brianb87e3b12014-01-12 22:12:14 -0800128 totalTime = datetime.now() - start
129 print '\nExperiments complete in %s (h:m:s.s)' % totalTime
130
brian6df88232014-01-14 17:05:07 -0800131def plot(result):
132 import matplotlib.pyplot as plt
133 import pylab
134 import numpy as np
135 from matplotlib.ticker import MaxNLocator
136
137 tags = [ x[0] for x in result.details ]
138 numTags = len(tags)
139 scores = [ float(x[1]) for x in result.details ]
140 offset = [ float(x[2]) for x in result.details ]
141 rankings = [ float(x[3]) - float(x[2]) for x in result.details ]
142 counts = [ x[4] for x in result.details ]
143
144 fig, ax1 = plt.subplots(figsize=(15, 9))
145 plt.subplots_adjust(left=0.3, right=0.8)
146 pos = np.arange(numTags)+0.5 # Center bars on the Y-axis ticks
147 rects = ax1.barh(pos, rankings, left=offset, align='center', height=0.5, color='m')
148
149 ax1.axis([0, result.onosTime, 0, numTags])
150 pylab.yticks(pos, tags)
151 ax1.set_title('TITLE HERE')
152 #plt.text(result.onosTime/2, -0.5,
153 # 'Iteration: ' + str(1), horizontalalignment='center', size='small')
154
155 # Set the right-hand Y-axis ticks and labels and set X-axis tick marks at the
156 # deciles
157 ax2 = ax1.twinx()
158 print MaxNLocator(7)
159 ax2.xaxis.set_major_locator(MaxNLocator(7)) # max number of xaxis ticks
160 #ax2.plot([100, 100], [0, 5], 'white', alpha=0.1)
161 ax2.xaxis.grid(True, linestyle='--', which='major', color='grey', alpha=0.25)
162 #Plot a solid vertical gridline to highlight the median position
163 #plt.plot([50, 50], [0, 5], 'grey', alpha=0.25)
164
165 # Build up the score labels for the right Y-axis by first appending a carriage
166 # return to each string and then tacking on the appropriate meta information
167 # (i.e., 'laps' vs 'seconds'). We want the labels centered on the ticks, so if
168 # there is no meta info (like for pushups) then don't add the carriage return to
169 # the string
170
171 '''
172 scoreLabels = [withnew(i, scr) for i, scr in enumerate(scores)]
173 scoreLabels = [i+j for i, j in zip(scoreLabels, testMeta)]
174 '''
175 scoreLabels = ['%.3f ms\n%s'%(i,j) for i,j in zip(scores,counts)]
176 # set the tick locations
177 ax2.set_yticks(pos)
178 # set the tick labels
179 ax2.set_yticklabels(scoreLabels)
180 # make sure that the limits are set equally on both yaxis so the ticks line up
181 ax2.set_ylim(ax1.get_ylim())
182
183 ax1.set_xlabel('Time (ms)')
184 ax2.set_ylabel('Average iteration / Count')
185
186 # Lastly, write in the ranking inside each bar to aid in interpretation
187 for rect in rects:
188 # Rectangle widths are already integer-valued but are floating
189 # type, so it helps to remove the trailing decimal point and 0 by
190 # converting width to int type
191 width = int(rect.get_width())
192 offset = int(rect.get_x())
193 percent = width / result.onosTime
194 onePercent = 0.01 * result.onosTime
195
196 rankStr = str(width) + 'ms'
197 if (percent < 0.09): # The bars aren't wide enough to print the ranking inside
198 xloc = offset + width + onePercent # Shift the text to the right side of the right edge
199 clr = 'black' # Black against white background
200 align = 'left'
201 else:
202 xloc = offset + 0.98*width # Shift the text to the left side of the right edge
203 clr = 'white' # White on magenta
204 align = 'right'
205
206 # Center the text vertically in the bar
207 yloc = rect.get_y()+rect.get_height()/2.0
208 ax1.text(xloc, yloc, rankStr, horizontalalignment=align,
209 verticalalignment='center', color=clr)
210
211 plt.show()
212 plt.savefig('test.png')
brianb87e3b12014-01-12 22:12:14 -0800213if __name__ == '__main__':
214 n = N
215 runPerf(n)
216