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_monitor = None
42 def create_slice(exp_desc, slicename, plc_host, pl_user, pl_pwd,
43 pl_ssh_key, root_dir):
44 pl_provider = FactoriesProvider("planetlab")
45 slice_desc = exp_desc.add_testbed_description(pl_provider)
46 slice_desc.set_attribute_value("homeDirectory", root_dir)
47 slice_desc.set_attribute_value("slice", slicename)
48 slice_desc.set_attribute_value("sliceSSHKey", pl_ssh_key)
49 slice_desc.set_attribute_value("authUser", pl_user)
50 slice_desc.set_attribute_value("authPass", pl_pwd)
51 slice_desc.set_attribute_value("plcHost", plc_host)
52 # Kills all running processes before starting the experiment
53 slice_desc.set_attribute_value("cleanProc", True)
54 # NOTICE: Setting 'cleanHome' to 'True' will erase all previous
55 # folders in the sliver Home directory, including result files!
56 slice_desc.set_attribute_value("cleanHome", True)
57 slice_desc.set_attribute_value("plLogLevel", "DEBUG")
60 def create_node(hostname, pl_inet, slice_desc):
61 pl_node = slice_desc.create("Node")
62 pl_node.set_attribute_value("hostname", hostname)
63 pl_node.set_attribute_value("label", "%d" % pl_node.guid)
64 pl_node.set_attribute_value("operatingSystem", "f12")
65 pl_iface = slice_desc.create("NodeInterface")
66 pl_iface.set_attribute_value("label", "iface_%d" % pl_node.guid)
67 pl_iface.connector("inet").connect(pl_inet.connector("devs"))
68 pl_node.connector("devs").connect(pl_iface.connector("node"))
69 return pl_node, pl_iface
71 def create_vlc_server(movie, pl_node, slice_desc):
72 mv = os.path.basename(movie)
73 pl_app = slice_desc.create("Application")
74 pl_app.set_attribute_value("rpmFusion", True)
75 pl_app.set_attribute_value("depends", "vlc")
76 pl_app.set_attribute_value("build",
77 # "echo -e 'new TEST vod enabled\\nsetup TEST input %s' > ${SOURCES}/VOD.vlm" % mv)
78 "echo -e 'new TEST broadcast enabled loop\\n"\
79 "setup TEST input %s\\n"\
80 "setup TEST output #rtp{mux=ts,sdp=rtsp://0.0.0.0:8554/TEST}\\n\\n"\
81 "new test_sched schedule enabled\\n"\
82 "setup test_sched append control TEST play' > ${SOURCES}/VOD.vlm" % mv)
84 pl_app.set_attribute_value("sources", "%s" % movie)
85 pl_app.set_attribute_value("command",
86 # "sudo -S dbus-uuidgen --ensure ; vlc -vvv -I dummy --vlm-conf VOD.vlm --rtsp-host=0.0.0.0:8554")
87 "sudo -S dbus-uuidgen --ensure ; vlc -vvv -I dummy --vlm-conf VOD.vlm")
88 pl_app.enable_trace("stdout")
89 pl_app.enable_trace("stderr")
90 pl_node.connector("apps").connect(pl_app.connector("node"))
93 def create_vlc_client(root_node, pl_node, slice_desc):
94 label = "%d_app" % pl_node.guid
95 hostname = root_node.get_attribute_value("hostname")
96 pl_app = slice_desc.create("Application")
97 pl_app.set_attribute_value("label", label)
98 pl_app.set_attribute_value("rpmFusion", True)
99 pl_app.set_attribute_value("depends", "vlc")
100 pl_app.set_attribute_value("command",
101 "sudo -S dbus-uuidgen --ensure ; sleep 5;" \
102 "vlc -I dummy --repeat rtsp://%s:8554/TEST --sout '#std{access=file,mux=ts,dst=/dev/null}'" % (hostname))
103 pl_app.enable_trace("stdout")
104 pl_app.enable_trace("stderr")
105 pl_node.connector("apps").connect(pl_app.connector("node"))
108 def create_cpumem_monitor(pl_node, slice_desc):
109 """ This function creates a monitoring application for the
110 utilization of node resources by the vlc application.
112 The format of the stdout trace file is the following:
113 'timestamp cpu(%) mem(%) time'
115 label = "%d_cpumem" % pl_node.guid
116 pl_app = slice_desc.create("Application")
117 pl_app.set_attribute_value("label", label)
118 pl_app.set_attribute_value("command",
119 "while true ; do echo $(date +%Y%m%d%H%M%S%z) " \
120 " $(top -b -n 1 | grep 'vlc' | head -1 | sed 's/\s\s*/ /g' | cut -d' ' -f9,10,11)" \
122 pl_app.enable_trace("stdout")
123 pl_app.enable_trace("stderr")
124 pl_node.connector("apps").connect(pl_app.connector("node"))
127 def create_net_monitor(pl_node, slice_desc, pl_ifaces):
128 """ This function creates a monitoring application for the
129 amount of bytes transmitted/received by the vlc application.
131 The format of the stdout trace file is the following:
132 'total-Mbytes total-time'
134 label = "%d_net" % pl_node.guid
135 hosts = " or ".join(map(lambda pl_iface: " ( host {#[%s].addr[0].[Address]#} ) " %
136 pl_iface.get_attribute_value("label"), pl_ifaces))
137 pl_app = slice_desc.create("Application")
138 pl_app.set_attribute_value("label", label)
139 pl_app.set_attribute_value("rpmFusion", True)
140 pl_app.set_attribute_value("sudo", True)
141 pl_app.set_attribute_value("depends", "tcpdump pv")
142 pl_app.set_attribute_value("command",
143 "tcpdump -l -i eth0 -nNqttf '(%s)' -w - | pv -fbt >/dev/null 2>>{#[%s].trace[stdout].[name]#}" %
145 pl_app.enable_trace("stdout")
146 pl_app.enable_trace("stderr")
147 pl_node.connector("apps").connect(pl_app.connector("node"))
150 def store_results(controller, monitors, results_dir, exp_label):
151 # create results directory for experiment
152 root_path = os.path.join(results_dir, exp_label)
154 print "STORING RESULTS in ", root_path
157 os.makedirs(root_path)
161 # collect information on nodes
165 hosts_info += "%s %s\n" % (mon.hostname, mon.type)
167 # create a subdir per hostname
168 node_path = os.path.join(root_path, mon.hostname)
170 os.makedirs(node_path)
174 # store monitoring results
175 cpumem_stdout = controller.trace(mon.cpumem_monitor.guid, "stdout")
176 net_stdout = controller.trace(mon.net_monitor.guid, "stdout")
177 results = dict({"cpumem": cpumem_stdout, "net": net_stdout})
178 for name, stdout in results.iteritems():
179 fpath = os.path.join(node_path, name)
184 # store node info file
185 fpath = os.path.join(root_path, "hosts")
191 slicename = os.environ.get("PL_SLICE")
192 pl_host = os.environ.get("PL_HOST", "www.planet-lab.eu")
193 pl_ssh_key = os.environ.get(
195 "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'],) )
196 pl_user = os.environ.get('PL_USER')
197 pl_pwd = os.environ.get('PL_PASS')
198 exp_label = "%s" % uuid.uuid4()
200 usage = "usage: %prog -s <pl_slice> -H <pl_host> -k <ssh_key> -u <pl_user> \
201 -p <pl_password> -m <movie> -r <results-dir> -l <experiment-label>"
203 parser = OptionParser(usage=usage)
204 parser.add_option("-s", "--slicename", dest="slicename",
205 help="PlanetLab slicename", default=slicename, type="str")
206 parser.add_option("-H", "--pl-host", dest="pl_host",
207 help="PlanetLab site (e.g. www.planet-lab.eu)",
208 default=pl_host, type="str")
209 parser.add_option("-k", "--ssh-key", dest="pl_ssh_key",
210 help="Path to private ssh key used for PlanetLab authentication",
211 default=pl_ssh_key, type="str")
212 parser.add_option("-u", "--pl-user", dest="pl_user",
213 help="PlanetLab account user (i.e. Registration email address)",
214 default=pl_user, type="str")
215 parser.add_option("-p", "--pl-pwd", dest="pl_pwd",
216 help="PlanetLab account password", default=pl_pwd, type="str")
217 parser.add_option("-m", "--movie", dest="movie",
218 help="Stream movie", type="str")
219 parser.add_option("-r", "--results", dest="results_dir", default = "/tmp",
220 help="Path to directory to store results", type="str")
221 parser.add_option("-l", "--label", dest="exp_label", default = exp_label,
222 help="Label to identify experiment results", type="str")
223 parser.add_option("-t", "--time", dest="time_to_run", default = 2,
224 help="Time to run the experiment in hours", type="float")
226 (options, args) = parser.parse_args()
228 if not options.movie:
229 parser.error("movie is a required argument")
231 return (options.slicename, options.pl_host, options.pl_user,
232 options.pl_pwd, options.pl_ssh_key, options.movie,
233 options.results_dir, options.exp_label, options.time_to_run)
235 if __name__ == '__main__':
236 root_dir = tempfile.mkdtemp()
245 time_to_run) = get_options()
247 # list to store information on monitoring apps per node
250 # Create the experiment description object
251 exp_desc = ExperimentDescription()
254 slice_desc = create_slice(exp_desc, pl_slice, pl_host, pl_user, pl_pwd,
255 pl_ssh_key, root_dir)
257 # Create the Internet box object
258 pl_inet = slice_desc.create("Internet")
261 hostname = "ple6.ipv6.lip6.fr"
262 (root_node, root_iface) = create_node(hostname, pl_inet, slice_desc)
264 # Create monitor info object for root node
265 root_mon = MonitorInfo(hostname, MonitorInfo.TYPE_ROOT)
266 monitors.append(root_mon)
269 create_vlc_server(movie, root_node, slice_desc)
271 # Add memory and cpu monitoring for root node
272 root_mon.cpumem_monitor = create_cpumem_monitor(root_node, slice_desc)
279 hostnames = ["planetlab1.rd.tut.fi",
280 "planetlab1.s3.kth.se",
281 "planetlab1.tlm.unavarra.es",
282 "planet1.servers.ua.pt",
283 "onelab3.warsaw.rd.tp.pl",
284 "gschembra3.diit.unict.it",
285 "iraplab1.iralab.uni-karlsruhe.de",
286 "host3-plb.loria.fr",
288 "planetlab04.cnds.unibe.ch"]
291 hostnames = ["planetlab1.rd.tut.fi",
292 "planetlab-2.research.netlab.hut.fi",
293 "planetlab2.willab.fi",
294 "planetlab3.hiit.fi",
295 "planetlab4.hiit.fi",
296 "planetlab1.s3.kth.se",
297 "itchy.comlab.bth.se",
298 "planetlab-1.ida.liu.se",
299 "scratchy.comlab.bth.se",
300 "planetlab2.s3.kth.se",
301 "planetlab1.tlm.unavarra.es",
302 "planetlab2.uc3m.es",
306 "planet1.servers.ua.pt",
307 "planetlab2.fct.ualg.pt",
308 "planetlab-1.tagus.ist.utl.pt",
309 "planetlab1.di.fct.unl.pt",
310 "planetlab1.fct.ualg.pt",
311 "onelab3.warsaw.rd.tp.pl",
312 "onelab1.warsaw.rd.tp.pl",
313 "prata.mimuw.edu.pl",
314 "onelab2.warsaw.rd.tp.pl",
315 "prometeusz.we.po.opole.pl",
316 "gschembra3.diit.unict.it",
317 "onelab6.iet.unipi.it",
318 "planetlab1.science.unitn.it",
319 "planetlab-1.ing.unimo.it",
320 "gschembra4.diit.unict.it",
321 "iraplab1.iralab.uni-karlsruhe.de",
322 "planetlab-1.fokus.fraunhofer.de",
323 "iraplab2.iralab.uni-karlsruhe.de",
325 "planet2.inf.tu-dresden.de",
326 "host3-plb.loria.fr",
327 "inriarennes1.irisa.fr",
328 "inriarennes2.irisa.fr",
329 "peeramide.irisa.fr",
332 "pl001.ece.upatras.gr",
333 "planetlab1.ionio.gr",
334 "planetlab2.ionio.gr",
335 "planetlab2.cs.uoi.gr",
336 "planetlab04.cnds.unibe.ch",
337 "lsirextpc01.epfl.ch",
338 "planetlab2.csg.uzh.ch",
339 "lsirextpc02.epfl.ch",
340 "planetlab1.unineuchatel.ch"]
342 for hostname in hostnames:
343 pl_node, pl_iface = create_node(hostname, pl_inet, slice_desc)
344 cli_ifaces.append(pl_iface)
346 # Create monitor info object for root node
347 node_mon = MonitorInfo(hostname, MonitorInfo.TYPE_LEAF)
348 monitors.append(node_mon)
350 # Add memory and cpu monitoring for all nodes
351 node_mon.cpumem_monitor = create_cpumem_monitor(pl_node, slice_desc)
353 # Add network monitoring for all nodes
354 node_mon.net_monitor = create_net_monitor(pl_node, slice_desc, [root_iface])
357 app = create_vlc_client(root_node, pl_node, slice_desc)
360 # Add network monitoring for root node
361 root_mon.net_monitor = create_net_monitor(root_node, slice_desc, cli_ifaces)
363 xml = exp_desc.to_xml()
365 controller = ExperimentController(xml, root_dir)
368 start_time = time.time()
369 duration = time_to_run * 3600 # in seconds
372 if (time.time() - start_time) > duration: # elapsed time
373 TERMINATE.append(None)
377 # store results in results dir
378 store_results(controller, monitors, results_dir, exp_label)
380 controller.shutdown()