156 lines
5.4 KiB
Python
Executable file
156 lines
5.4 KiB
Python
Executable file
#!/usr/bin/env python
|
|
|
|
#
|
|
# Copyright (C) 2010 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
|
|
import math
|
|
import optparse
|
|
import sched
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
|
|
|
|
def fxrange(start, finish, increment=1.0):
|
|
"""Like xrange, but with float arguments."""
|
|
steps = int(math.ceil(float(finish - start) / increment))
|
|
|
|
if steps < 0:
|
|
raise ValueError
|
|
|
|
for i in xrange(steps):
|
|
yield start + i * increment
|
|
|
|
|
|
def hms(seconds):
|
|
hours = int(seconds / (60 * 60))
|
|
seconds -= hours * 60 * 60
|
|
minutes = int(seconds / 60)
|
|
seconds -= minutes * 60
|
|
return '%d:%02d:%02d' % (hours, minutes, seconds)
|
|
|
|
|
|
class PeriodicExperiment(object):
|
|
"""Uses the scheduler to run the specified function repeatedly."""
|
|
def __init__(self,
|
|
scheduler=None,
|
|
total_duration=8 * 60 * 60,
|
|
test_interval=60,
|
|
test_function=None):
|
|
self._scheduler = scheduler
|
|
self._total_duration = total_duration
|
|
self._test_interval = test_interval
|
|
self._test_function = test_function
|
|
self._start = self._scheduler.timefunc()
|
|
self._finish = self._start + self._total_duration
|
|
|
|
def Run(self):
|
|
for start_one in fxrange(self._start,
|
|
self._finish,
|
|
self._test_interval):
|
|
time_remaining = self._finish - start_one
|
|
self._scheduler.enterabs(start_one,
|
|
1, # Priority
|
|
self._test_function,
|
|
[time_remaining])
|
|
self._scheduler.run()
|
|
|
|
|
|
class ManualExperiment(object):
|
|
"""Runs the experiment repeatedly, prompting for input each time."""
|
|
def __init__(self, test_function):
|
|
self._test_function = test_function
|
|
|
|
def Run(self):
|
|
try:
|
|
while True:
|
|
self._test_function(0) # Pass in a fake time remaining
|
|
_ = raw_input('Press return to run the test again. '
|
|
'Control-c to exit.')
|
|
except KeyboardInterrupt:
|
|
return
|
|
|
|
class IperfTest(object):
|
|
def __init__(self, filename, servername, individual_length):
|
|
self._file = file(filename, 'a')
|
|
self._servername = servername
|
|
self._individual_length = individual_length
|
|
|
|
def Run(self, remaining):
|
|
"""Run iperf, log output to file, and print."""
|
|
iperf = ['iperf',
|
|
'--client', self._servername,
|
|
# Transfer time in seconds.
|
|
'--time', str(self._individual_length),
|
|
'--reportstyle', 'c' # CSV output
|
|
]
|
|
print '%s remaining. Running %s' % (hms(remaining), ' '.join(iperf))
|
|
result = subprocess.Popen(iperf,
|
|
stdout=subprocess.PIPE).communicate()[0]
|
|
print result.rstrip()
|
|
sys.stdout.flush()
|
|
self._file.write(result)
|
|
self._file.flush()
|
|
|
|
def teardown(self):
|
|
self._file.close()
|
|
|
|
def main():
|
|
default_output = 'stability-' + time.strftime('%Y-%m-%d-%H-%M-%S')
|
|
|
|
parser = optparse.OptionParser()
|
|
parser.add_option('--server', default=None,
|
|
help='Machine running the iperf server')
|
|
parser.add_option('--test_interval', default=60 * 5, type='int',
|
|
help='Interval (in seconds) between tests')
|
|
parser.add_option('--individual_length', default=10, type='int',
|
|
help='length (in seconds) of each individual test')
|
|
parser.add_option('--total_duration', default=8 * 60 * 60, type='int',
|
|
help='length (in seconds) for entire test')
|
|
parser.add_option('--output', default=default_output,
|
|
help='Output file')
|
|
parser.add_option('--manual', default=False, action='store_true',
|
|
help='Manual mode; wait for input between every test')
|
|
|
|
(options, _) = parser.parse_args()
|
|
|
|
if not options.server:
|
|
print 'No server specified. Specify a server with --server=SERVER.'
|
|
exit(2)
|
|
|
|
if options.individual_length > options.test_interval:
|
|
print ('The length of a given bandwidth test must be lower than the '
|
|
'interval between tests')
|
|
exit(2)
|
|
|
|
s = sched.scheduler(time.time, time.sleep)
|
|
|
|
iperf = IperfTest(filename=options.output,
|
|
servername=options.server,
|
|
individual_length=options.individual_length)
|
|
|
|
if options.manual:
|
|
e = ManualExperiment(test_function=iperf.Run)
|
|
else:
|
|
e = PeriodicExperiment(scheduler=s,
|
|
total_duration=options.total_duration,
|
|
test_interval=options.test_interval,
|
|
test_function=iperf.Run)
|
|
e.Run()
|
|
iperf.teardown()
|
|
|
|
if __name__ == '__main__':
|
|
main()
|