3 from nepi.core.design import ExperimentDescription, FactoriesProvider
4 from nepi.core.execute import ExperimentController
5 from nepi.util.constants import ApplicationStatus as AS
6 from optparse import OptionParser, SUPPRESS_HELP
13 This experiment evaluates the consumption of computer resources when using
14 VLC for Internet broasdcasting using PlanetLab nodes as both server and clients.
15 A root node (server) streams a broadcast in a loop, while the clients retrieve
16 the same video over and over until experiment run time is elapsed.
18 While the experiment is running cpu and memory usage, and the amount of bytes
19 transmitted per stream are traced to files.
23 # Trak SIGTERM, and set global termination flag instead of dying
26 def _finalize(sig,frame):
28 TERMINATE.append(None)
29 signal.signal(signal.SIGTERM, _finalize)
30 signal.signal(signal.SIGINT, _finalize)
32 class MonitorInfo(object):
36 def __init__(self, hostname, type):
37 self.hostname = hostname
39 self.cpumem_monitor = None
40 self.net_in_monitor = None
41 self.net_out_monitor = None
44 def create_slice(exp_desc, slicename, plc_host, pl_user, pl_pwd,
45 pl_ssh_key, root_dir):
46 pl_provider = FactoriesProvider("planetlab")
47 slice_desc = exp_desc.add_testbed_description(pl_provider)
48 slice_desc.set_attribute_value("homeDirectory", root_dir)
49 slice_desc.set_attribute_value("slice", slicename)
50 slice_desc.set_attribute_value("sliceSSHKey", pl_ssh_key)
51 slice_desc.set_attribute_value("authUser", pl_user)
52 slice_desc.set_attribute_value("authPass", pl_pwd)
53 slice_desc.set_attribute_value("plcHost", plc_host)
54 # Kills all running processes before starting the experiment
55 slice_desc.set_attribute_value("cleanProc", True)
56 # NOTICE: Setting 'cleanHome' to 'True' will erase all previous
57 # folders in the sliver Home directory, including result files!
58 slice_desc.set_attribute_value("cleanHome", True)
59 slice_desc.set_attribute_value("plLogLevel", "DEBUG")
62 def create_node(hostname, pl_inet, slice_desc):
63 pl_node = slice_desc.create("Node")
64 pl_node.set_attribute_value("hostname", hostname)
65 pl_node.set_attribute_value("label", "%d" % pl_node.guid)
66 pl_node.set_attribute_value("operatingSystem", "f12")
67 pl_iface = slice_desc.create("NodeInterface")
68 pl_iface.set_attribute_value("label", "iface_%d" % pl_node.guid)
69 pl_iface.connector("inet").connect(pl_inet.connector("devs"))
70 pl_node.connector("devs").connect(pl_iface.connector("node"))
71 return pl_node, pl_iface
73 def create_vlc_server(movie, pl_node, slice_desc):
74 mv = os.path.basename(movie)
75 pl_app = slice_desc.create("Application")
76 pl_app.set_attribute_value("rpmFusion", True)
77 pl_app.set_attribute_value("depends", "vlc")
78 pl_app.set_attribute_value("build",
79 # "echo -e 'new TEST vod enabled\\nsetup TEST input %s' > ${SOURCES}/VOD.vlm" % mv)
80 "echo -e 'new TEST broadcast enabled loop\\n"\
81 "setup TEST input %s\\n"\
82 "setup TEST output #rtp{mux=ts,sdp=rtsp://0.0.0.0:8554/TEST}\\n\\n"\
83 "new test_sched schedule enabled\\n"\
84 "setup test_sched append control TEST play' > ${SOURCES}/VOD.vlm" % mv)
86 pl_app.set_attribute_value("sources", "%s" % movie)
87 pl_app.set_attribute_value("command",
88 "sudo -S dbus-uuidgen --ensure ; vlc -vvv -I dummy --vlm-conf VOD.vlm")
89 pl_app.enable_trace("stdout")
90 pl_app.enable_trace("stderr")
91 pl_node.connector("apps").connect(pl_app.connector("node"))
94 def create_vlc_client(root_node, pl_node, slice_desc):
95 label = "%d_app" % pl_node.guid
96 hostname = root_node.get_attribute_value("hostname")
97 pl_app = slice_desc.create("Application")
98 pl_app.set_attribute_value("label", label)
99 pl_app.set_attribute_value("rpmFusion", True)
100 pl_app.set_attribute_value("depends", "vlc")
101 pl_app.set_attribute_value("command",
102 "sudo -S dbus-uuidgen --ensure ; sleep 5;" \
103 "vlc -I dummy rtsp://%s:8554/TEST --sout '#std{access=file,mux=ts,dst=/dev/null}'" % (hostname))
104 pl_app.enable_trace("stdout")
105 pl_app.enable_trace("stderr")
106 pl_node.connector("apps").connect(pl_app.connector("node"))
109 def create_cpumem_monitor(pl_node, slice_desc):
110 """ This function creates a monitoring application for the
111 utilization of node resources by the vlc application.
113 The format of the stdout trace file is the following:
114 'timestamp cpu(%) mem(%) time'
116 label = "%d_cpumem" % pl_node.guid
117 pl_app = slice_desc.create("Application")
118 pl_app.set_attribute_value("label", label)
119 pl_app.set_attribute_value("command",
120 "while true ; do echo $(date +%Y%m%d%H%M%S%z) " \
121 " $(top -b -n 1 | grep 'vlc' | head -1 | sed 's/\s\s*/ /g' | sed 's/^\s//g' | cut -d' ' -f9,10,11)" \
123 pl_app.enable_trace("stdout")
124 pl_app.enable_trace("stderr")
125 pl_node.connector("apps").connect(pl_app.connector("node"))
128 def create_net_monitor(pl_node, slice_desc, pl_ifaces, pcap=False):
129 """ This function creates a monitoring application for the
130 amount of bytes transmitted/received by the vlc application.
132 The format of the stdout trace file is the following:
133 'total-Mbytes total-time'
135 label = "%d_net" % pl_node.guid
136 hosts = " or ".join(map(lambda pl_iface: " ( host {#[%s].addr[0].[Address]#} ) " %
137 pl_iface.get_attribute_value("label"), pl_ifaces))
138 pl_app = slice_desc.create("Application")
139 pl_app.set_attribute_value("label", label)
140 pl_app.set_attribute_value("rpmFusion", True)
141 pl_app.set_attribute_value("sudo", True)
142 pl_app.set_attribute_value("depends", "tcpdump pv")
146 output = "{#[%s].trace[output].[name]#}" % label
148 pl_app.set_attribute_value("command",
149 "tcpdump -l -i eth0 -s 0 -f '(%s)' -w - | pv -fbt >%s 2>>{#[%s].trace[stdout].[name]#}" %
150 (hosts, output, label))
153 pl_app.enable_trace("output")
155 pl_app.enable_trace("stdout")
156 pl_app.enable_trace("stderr")
157 pl_node.connector("apps").connect(pl_app.connector("node"))
160 def store_results(controller, monitors, results_dir, exp_label):
161 # create results directory for experiment
162 root_path = os.path.join(results_dir, exp_label)
164 print "STORING RESULTS in ", root_path
167 os.makedirs(root_path)
171 # collect information on nodes
175 hosts_info += "%s %s\n" % (mon.hostname, mon.type)
177 # create a subdir per hostname
178 node_path = os.path.join(root_path, mon.hostname)
180 os.makedirs(node_path)
184 # store monitoring results
186 cpumem_out = controller.trace(mon.cpumem_monitor.guid, "stdout")
189 if mon.net_in_monitor:
190 net_in = controller.trace(mon.net_in_monitor.guid, "stdout")
193 if mon.net_out_monitor:
194 net_out = controller.trace(mon.net_out_monitor.guid, "stdout")
196 vlc_err = controller.trace(mon.vlc.guid, "stderr")
197 vlc_out = controller.trace(mon.vlc.guid, "stdout")
200 "cpumem": cpumem_out,
204 "vlc_err": vlc_err })
206 for name, result in results.iteritems():
210 fpath = os.path.join(node_path, name)
215 # store node info file
216 fpath = os.path.join(root_path, "hosts")
222 slicename = os.environ.get("PL_SLICE")
223 pl_host = os.environ.get("PL_HOST", "www.planet-lab.eu")
224 pl_ssh_key = os.environ.get(
226 "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'],) )
227 pl_user = os.environ.get('PL_USER')
228 pl_pwd = os.environ.get('PL_PASS')
229 exp_label = "%s" % uuid.uuid4()
231 usage = "usage: %prog -s <pl_slice> -H <pl_host> -k <ssh_key> -u <pl_user> \
232 -p <pl_password> -m <movie> -r <results-dir> -l <experiment-label>"
234 parser = OptionParser(usage=usage)
235 parser.add_option("-s", "--slicename", dest="slicename",
236 help="PlanetLab slicename", default=slicename, type="str")
237 parser.add_option("-H", "--pl-host", dest="pl_host",
238 help="PlanetLab site (e.g. www.planet-lab.eu)",
239 default=pl_host, type="str")
240 parser.add_option("-k", "--ssh-key", dest="pl_ssh_key",
241 help="Path to private ssh key used for PlanetLab authentication",
242 default=pl_ssh_key, type="str")
243 parser.add_option("-u", "--pl-user", dest="pl_user",
244 help="PlanetLab account user (i.e. Registration email address)",
245 default=pl_user, type="str")
246 parser.add_option("-p", "--pl-pwd", dest="pl_pwd",
247 help="PlanetLab account password", default=pl_pwd, type="str")
248 parser.add_option("-m", "--movie", dest="movie",
249 help="Stream movie", type="str")
250 parser.add_option("-r", "--results", dest="results_dir", default = "/tmp",
251 help="Path to directory to store results", type="str")
252 parser.add_option("-l", "--label", dest="exp_label", default = exp_label,
253 help="Label to identify experiment results", type="str")
254 parser.add_option("-t", "--time", dest="time_to_run", default = 20,
255 help="Time to run the experiment in minutes", type="float")
257 (options, args) = parser.parse_args()
259 if not options.movie:
260 parser.error("movie is a required argument")
262 return (options.slicename, options.pl_host, options.pl_user,
263 options.pl_pwd, options.pl_ssh_key, options.movie,
264 options.results_dir, options.exp_label, options.time_to_run)
266 if __name__ == '__main__':
267 root_dir = tempfile.mkdtemp()
276 time_to_run) = get_options()
278 # list to store information on monitoring apps per node
281 # Create the experiment description object
282 exp_desc = ExperimentDescription()
285 slice_desc = create_slice(exp_desc, pl_slice, pl_host, pl_user, pl_pwd,
286 pl_ssh_key, root_dir)
288 # Create the Internet box object
289 pl_inet = slice_desc.create("Internet")
292 hostname = "ple6.ipv6.lip6.fr"
293 (root_node, root_iface) = create_node(hostname, pl_inet, slice_desc)
295 # Create monitor info object for root node
296 root_mon = MonitorInfo(hostname, MonitorInfo.TYPE_ROOT)
297 monitors.append(root_mon)
300 root_vlc = create_vlc_server(movie, root_node, slice_desc)
302 # Add memory and cpu monitoring for root node
303 root_mon.cpumem_monitor = create_cpumem_monitor(root_node, slice_desc)
305 # Add reference to vlc app
306 root_mon.vlc = root_vlc
312 hostnames = ["planetlab1.rd.tut.fi",
313 "planetlab-2.research.netlab.hut.fi",
314 "planetlab2.willab.fi",
315 "planetlab3.hiit.fi",
316 "planetlab4.hiit.fi",
317 "planetlab1.willab.fi",
318 "planetlab1.s3.kth.se",
319 "itchy.comlab.bth.se",
320 "planetlab-1.ida.liu.se",
321 "scratchy.comlab.bth.se",
322 "planetlab2.s3.kth.se",
323 "planetlab1.sics.se",
324 "planetlab1.tlm.unavarra.es",
325 "planetlab2.uc3m.es",
329 "planetlab1.uc3m.es",
330 "planetlab2.dit.upm.es",
333 "planet1.servers.ua.pt",
334 "planetlab2.fct.ualg.pt",
335 "planetlab-1.tagus.ist.utl.pt",
336 "planetlab-2.tagus.ist.utl.pt",
337 "planetlab-um00.di.uminho.pt",
338 "planet2.servers.ua.pt",
339 "planetlab1.mini.pw.edu.pl",
341 "planetlab1.ci.pwr.wroc.pl",
342 "planetlab1.pjwstk.edu.pl",
343 "ple2.tu.koszalin.pl",
344 "planetlab2.ci.pwr.wroc.pl",
345 "planetlab2.cyfronet.pl",
346 "plab2.ple.silweb.pl",
347 "planetlab1.cyfronet.pl",
348 "plab4.ple.silweb.pl",
349 "ple2.dmcs.p.lodz.pl",
350 "planetlab2.pjwstk.edu.pl",
351 "ple1.dmcs.p.lodz.pl",
352 "pandora.we.po.opole.pl",
353 "gschembra3.diit.unict.it",
354 "onelab6.iet.unipi.it",
355 "planetlab1.science.unitn.it",
356 "planetlab-1.ing.unimo.it",
357 "gschembra4.diit.unict.it",
358 "iraplab1.iralab.uni-karlsruhe.de",
359 "planetlab-1.fokus.fraunhofer.de",
360 "iraplab2.iralab.uni-karlsruhe.de",
362 "pl2.uni-rostock.de",
363 "onelab-1.fhi-fokus.de",
364 "planet2.l3s.uni-hannover.de",
365 "planetlab1.exp-math.uni-essen.de",
366 "planetlab-2.fokus.fraunhofer.de",
367 "planetlab02.tkn.tu-berlin.de",
368 "planetlab1.informatik.uni-goettingen.de",
369 "planetlab1.informatik.uni-erlangen.de",
370 "planetlab2.exp-math.uni-essen.de",
371 "planetlab2.lkn.ei.tum.de",
372 "planetlab1.wiwi.hu-berlin.de",
373 "planet1.l3s.uni-hannover.de",
374 "planetlab1.informatik.uni-wuerzburg.de",
375 "host3-plb.loria.fr",
376 "inriarennes1.irisa.fr",
377 "inriarennes2.irisa.fr",
378 "peeramide.irisa.fr",
381 "host4-plb.loria.fr",
382 "planetlab-1.imag.fr",
383 "planetlab-2.imag.fr",
385 "planetlab1.u-strasbg.fr",
387 "planetlab1.ionio.gr",
388 "planetlab2.ionio.gr",
389 "planetlab2.cs.uoi.gr",
390 "stella.planetlab.ntua.gr",
391 "vicky.planetlab.ntua.gr",
392 "planetlab1.cs.uoi.gr",
393 "pl002.ece.upatras.gr",
394 "planetlab04.cnds.unibe.ch",
395 "lsirextpc01.epfl.ch",
396 "planetlab2.csg.uzh.ch",
397 "planetlab1.csg.uzh.ch",
398 "planetlab-2.cs.unibas.ch",
399 "planetlab-1.cs.unibas.ch",
400 "planetlab4.cs.st-andrews.ac.uk",
401 "planetlab-1.imperial.ac.uk",
402 "planetlab3.xeno.cl.cam.ac.uk",
403 "planetlab1.xeno.cl.cam.ac.uk",
404 "planetlab2.xeno.cl.cam.ac.uk",
405 "planetlab3.cs.st-andrews.ac.uk",
406 "planetlab1.aston.ac.uk",
407 "planetlab1.nrl.eecs.qmul.ac.uk",
408 "chimay.infonet.fundp.ac.be",
409 "orval.infonet.fundp.ac.be",
410 "rochefort.infonet.fundp.ac.be",
411 "planck227ple.test.ibbt.be",
415 for hostname in hostnames:
416 pl_node, pl_iface = create_node(hostname, pl_inet, slice_desc)
417 cli_ifaces.append(pl_iface)
419 # Create monitor info object for root node
420 node_mon = MonitorInfo(hostname, MonitorInfo.TYPE_LEAF)
421 monitors.append(node_mon)
423 # Add memory and cpu monitoring for all nodes
424 node_mon.cpumem_monitor = create_cpumem_monitor(pl_node, slice_desc)
426 # Add network monitoring for all nodes
427 node_mon.net_out_monitor = create_net_monitor(pl_node, slice_desc, [root_iface])
430 vlc = create_vlc_client(root_node, pl_node, slice_desc)
433 # Add reference to vlc app
436 # Add network monitoring for root node
437 #root_mon.net_monitor = create_net_monitor(root_node, slice_desc, cli_ifaces, pcap=True)
438 root_mon.net_out_monitor = create_net_monitor(root_node, slice_desc, cli_ifaces)
440 xml = exp_desc.to_xml()
442 controller = ExperimentController(xml, root_dir)
445 start_time = time.time()
446 duration = time_to_run * 60 # in seconds
449 if (time.time() - start_time) > duration: # elapsed time
450 TERMINATE.append(None)
454 # store results in results dir
455 store_results(controller, monitors, results_dir, exp_label)
457 controller.shutdown()