Simplifying factorial in examples/ccnx/planetlab_ccnx_multicast.py
[nepi.git] / examples / POPI / run_popi_experiments.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 from nepi.core.execute import ExperimentController
5 from optparse import OptionParser, SUPPRESS_HELP
6 import collections
7 import commands
8 import os
9 import shutil
10 import signal
11 import subprocess
12 import sys
13 import time
14 import traceback
15 import getpass
16 import cPickle
17
18 class PopiExample(object):
19     _testsets = dict({
20         "popi":  "./popi-tun-classfilter-2MB-q500-pl.xml",
21         "popi_hibw":  "./popi-tun-classfilter-2MB-q500-pl-hibw.xml",
22         })
23     
24     classes = {
25         'tcpx4' : 'udp:tcp*4:icmp:',
26         'icmpx4' : 'udp:tcp:icmp*4:',
27         'udpx4' : 'udp*4:tcp:icmp:',
28         'u1t4i16' : 'udp:tcp*4:icmp*16:',
29         'u4t4i16' : 'udp*4:tcp*4:icmp*16:',
30         'u1t16i16' : 'udp*4:tcp*16:icmp*16:',
31         'u1t1t1' : 'udp:tcp:icmp:',
32     }
33     
34     bwlimits = {
35         '32K' : '32',
36         '64K' : '64',
37         '128K' : '128',
38         '256K' : '256',
39         '384K' : '384',
40     #    '512K' : '512',
41     #    '768K' : '768',
42     #    '1M' : '1024',
43     #    '2M' : '2048',
44     }
45     
46     testsets = dict([
47         ("%s-%s-%s" % (tset,clsname,bwname), (xml, {'classes':cls, 'bwlimit':bw}))
48         for tset,xml in _testsets.iteritems()
49         for clsname,cls in classes.iteritems()
50         for bwname,bw in bwlimits.iteritems()
51     ])
52
53     def __init__(self):
54         usage = "usage: %prog -u user -t times -d results_dir -f remove -e experiment -s start"
55         parser = OptionParser(usage=usage)
56         parser.add_option("-u", "--user", dest="pluser", help="PlanetLab PLC user (email)", type="str")
57         parser.add_option("-p", "--pass", dest="plpass", help="PlanetLab PLC user (password) - leave empty for interactive prompt", type="str")
58         parser.add_option("-k", "--key", dest="plkey", help="PlanetLab PLC private key to use", type="str")
59         parser.add_option("-S", "--slice", dest="plslice", help="PlanetLab slice into which to deploy experiments", type="str")
60         parser.add_option("-t", "--times", dest="times", help="Number of times to run each scenario", type="int")
61         parser.add_option("-d", "--dir", dest="results_dir", help="Results directory", type="str")
62         parser.add_option("-f", "--remove", dest="remove", help="Remove previous results directory",  action="store_true", default=False)
63         parser.add_option("-e", "--experiment", dest="experiment", help="Experiment to execute [%s]" % ('|'.join(self._testsets.keys()),),  type="str")
64         parser.add_option("-s", "--start", dest="start", help="Start experiment at specific iteration",  type="int")
65         (options, args) = parser.parse_args()
66         
67         if not options.pluser:
68             print >>sys.stderr, "Must specify --user"
69             sys.exit(1)
70         else:
71             self.pluser = options.pluser
72             
73         if not options.plslice:
74             print >>sys.stderr, "Must specify --slice"
75             sys.exit(1)
76         else:
77             self.plslice = options.plslice
78             
79         if not options.plkey:
80             print >>sys.stderr, "Must specify --key"
81             sys.exit(1)
82         else:
83             self.plkey = options.plkey
84             
85         if not options.plpass:
86             self.plpass = getpass.getpass("Password for %s: " % (self.pluser,))
87             
88         self.times = options.times if options.times else 5
89         self.results_dir = options.results_dir if options.results_dir else "results"
90         self.remove = options.remove
91         if options.experiment:
92             if ',' in options.experiment:
93                 options.experiment = options.experiment.split(',')
94             else:
95                 options.experiment = [ options.experiment ]
96         else:
97             options.experiment = self.testsets.keys()
98         self.experiments = [x for x in options.experiment if x in self.testsets]
99         self.start = options.start if options.start else 0
100
101     def run(self):
102         duration = 3600
103
104         if self.remove:
105             try:
106                 shutil.rmtree(self.results_dir)
107             except:
108                 traceback.print_exc(file=sys.stderr)
109
110         try:
111             os.mkdir(self.results_dir)
112         except:
113             traceback.print_exc(file=sys.stderr)
114
115         for j,testset in enumerate(self.experiments):
116             xml_filepath, replacements = self.testsets[testset]
117             replacements = dict(replacements)
118             replacements['pluser'] = self.pluser
119             replacements['plpass'] = self.plpass
120             replacements['plslice'] = self.plslice
121             replacements['plkey'] = self.plkey
122             
123             for i in xrange(self.start, self.times):
124                 testset_dir = os.path.join(self.results_dir, testset, str(i))
125                 os.makedirs(testset_dir)
126
127                 print >>sys.stderr, "%3d%% - " % ((j+i*1.0/(self.times-self.start))*100/len(self.experiments),), testset, "...",
128                 
129                 # launch experiment
130                 command = "python run_one_experiment.py %d '%s' '%s' '%s' %d" % \
131                         (duration, xml_filepath, testset, self.results_dir, i)
132                 # send by environment, we don't want passwords in the commandline
133                 env = dict(os.environ)
134                 env['POPI_REPLACEMENTS'] = cPickle.dumps(replacements,2).encode("base64").strip()
135                 
136                 for trials in xrange(5):
137                     logfile = open(os.path.join(testset_dir,"log"), "w")
138                     p = subprocess.Popen(
139                         command, 
140                         shell = True, 
141                         env = env,
142                         stdout = logfile,
143                         stderr = logfile,
144                         stdin = open("/dev/null","rb") )
145                     
146                     # we wait two time the estimated dirantion of the movie (120s)
147                     for i in xrange(0, duration * 2, 10):
148                         time.sleep(10)
149                         returncode = p.poll()
150                         if returncode is not None:
151                             break
152                     time.sleep(10)
153                     try:
154                         os.kill(p.pid, signal.SIGKILL)
155                     except:
156                         pass
157                     
158                     logfile.close()
159                     retfile = open(os.path.join(testset_dir,"retcode"), "w")
160                     if returncode:
161                         rettext = "FAIL %s" % (returncode,)
162                     else:
163                         rettext = "SUCCESS"
164                     retfile.write(rettext)
165                     retfile.close()
166
167                     print >>sys.stderr, rettext,
168                     
169                     if not returncode:
170                         print >>sys.stderr
171                         break
172                     else:
173                         time.sleep(60)
174                 else:
175                     print >>sys.stderr, "Giving up"
176
177 if __name__ == '__main__':
178     example = PopiExample()
179     example.run()
180