Home | History | Annotate | Download | only in test-scripts
      1 #!/usr/bin/env python
      2 
      3 #
      4 # Copyright (C) 2010 The Android Open Source Project
      5 #
      6 # Licensed under the Apache License, Version 2.0 (the "License");
      7 # you may not use this file except in compliance with the License.
      8 # You may obtain a copy of the License at
      9 #
     10 #      http://www.apache.org/licenses/LICENSE-2.0
     11 #
     12 # Unless required by applicable law or agreed to in writing, software
     13 # distributed under the License is distributed on an "AS IS" BASIS,
     14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 # See the License for the specific language governing permissions and
     16 # limitations under the License.
     17 #
     18 
     19 import math
     20 import optparse
     21 import sched
     22 import subprocess
     23 import sys
     24 import time
     25 
     26 
     27 def fxrange(start, finish, increment=1.0):
     28     """Like xrange, but with float arguments."""
     29     steps = int(math.ceil(float(finish - start) / increment))
     30 
     31     if steps < 0:
     32         raise ValueError
     33 
     34     for i in xrange(steps):
     35         yield start + i * increment
     36 
     37 
     38 def hms(seconds):
     39     hours = int(seconds / (60 * 60))
     40     seconds -= hours * 60 * 60
     41     minutes = int(seconds / 60)
     42     seconds -= minutes * 60
     43     return '%d:%02d:%02d' % (hours, minutes, seconds)
     44 
     45 
     46 class PeriodicExperiment(object):
     47     """Uses the scheduler to run the specified function repeatedly."""
     48     def __init__(self,
     49                  scheduler=None,
     50                  total_duration=8 * 60 * 60,
     51                  test_interval=60,
     52                  test_function=None):
     53         self._scheduler = scheduler
     54         self._total_duration = total_duration
     55         self._test_interval = test_interval
     56         self._test_function = test_function
     57         self._start = self._scheduler.timefunc()
     58         self._finish = self._start + self._total_duration
     59 
     60     def Run(self):
     61         for start_one in fxrange(self._start,
     62                                  self._finish,
     63                                  self._test_interval):
     64             time_remaining = self._finish - start_one
     65             self._scheduler.enterabs(start_one,
     66                                      1,     # Priority
     67                                      self._test_function,
     68                                      [time_remaining])
     69         self._scheduler.run()
     70 
     71 
     72 class ManualExperiment(object):
     73     """Runs the experiment repeatedly, prompting for input each time."""
     74     def __init__(self, test_function):
     75         self._test_function = test_function
     76 
     77     def Run(self):
     78         try:
     79             while True:
     80                 self._test_function(0)    # Pass in a fake time remaining
     81                 _ = raw_input('Press return to run the test again.  '
     82                               'Control-c to exit.')
     83         except KeyboardInterrupt:
     84             return
     85 
     86 class IperfTest(object):
     87     def __init__(self, filename, servername, individual_length):
     88         self._file = file(filename, 'a')
     89         self._servername = servername
     90         self._individual_length = individual_length
     91 
     92     def Run(self, remaining):
     93         """Run iperf, log output to file, and print."""
     94         iperf = ['iperf',
     95                  '--client', self._servername,
     96                  # Transfer time in seconds.
     97                  '--time', str(self._individual_length),
     98                  '--reportstyle', 'c' # CSV output
     99                  ]
    100         print '%s remaining.  Running %s' % (hms(remaining), ' '.join(iperf))
    101         result = subprocess.Popen(iperf,
    102                                   stdout=subprocess.PIPE).communicate()[0]
    103         print result.rstrip()
    104         sys.stdout.flush()
    105         self._file.write(result)
    106         self._file.flush()
    107 
    108     def teardown(self):
    109         self._file.close()
    110 
    111 def main():
    112     default_output = 'stability-' + time.strftime('%Y-%m-%d-%H-%M-%S')
    113 
    114     parser = optparse.OptionParser()
    115     parser.add_option('--server', default=None,
    116                       help='Machine running the iperf server')
    117     parser.add_option('--test_interval', default=60 * 5, type='int',
    118                       help='Interval (in seconds) between tests')
    119     parser.add_option('--individual_length', default=10, type='int',
    120                       help='length (in seconds) of each individual test')
    121     parser.add_option('--total_duration', default=8 * 60 * 60, type='int',
    122                       help='length (in seconds) for entire test')
    123     parser.add_option('--output', default=default_output,
    124                       help='Output file')
    125     parser.add_option('--manual', default=False, action='store_true',
    126                       help='Manual mode; wait for input between every test')
    127 
    128     (options, _) = parser.parse_args()
    129 
    130     if not options.server:
    131         print 'No server specified.  Specify a server with --server=SERVER.'
    132         exit(2)
    133 
    134     if options.individual_length > options.test_interval:
    135         print ('The length of a given bandwidth test must be lower than the '
    136                'interval between tests')
    137         exit(2)
    138 
    139     s = sched.scheduler(time.time, time.sleep)
    140 
    141     iperf = IperfTest(filename=options.output,
    142                       servername=options.server,
    143                       individual_length=options.individual_length)
    144 
    145     if options.manual:
    146         e = ManualExperiment(test_function=iperf.Run)
    147     else:
    148         e = PeriodicExperiment(scheduler=s,
    149                                total_duration=options.total_duration,
    150                                test_interval=options.test_interval,
    151                                test_function=iperf.Run)
    152     e.Run()
    153     iperf.teardown()
    154 
    155 if __name__ == '__main__':
    156     main()
    157