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
43 def create_slice(exp_desc, slicename, plc_host, pl_user, pl_pwd,
44 pl_ssh_key, root_dir):
45 pl_provider = FactoriesProvider("planetlab")
46 slice_desc = exp_desc.add_testbed_description(pl_provider)
47 slice_desc.set_attribute_value("homeDirectory", root_dir)
48 slice_desc.set_attribute_value("slice", slicename)
49 slice_desc.set_attribute_value("sliceSSHKey", pl_ssh_key)
50 slice_desc.set_attribute_value("authUser", pl_user)
51 slice_desc.set_attribute_value("authPass", pl_pwd)
52 slice_desc.set_attribute_value("plcHost", plc_host)
53 # Kills all running processes before starting the experiment
54 slice_desc.set_attribute_value("cleanProc", True)
55 # NOTICE: Setting 'cleanHome' to 'True' will erase all previous
56 # folders in the sliver Home directory, including result files!
57 slice_desc.set_attribute_value("cleanHome", True)
58 slice_desc.set_attribute_value("plLogLevel", "DEBUG")
61 def create_node(hostname, pl_inet, slice_desc):
62 pl_node = slice_desc.create("Node")
63 pl_node.set_attribute_value("hostname", hostname)
64 pl_node.set_attribute_value("label", "%d" % pl_node.guid)
65 pl_node.set_attribute_value("operatingSystem", "f12")
66 pl_iface = slice_desc.create("NodeInterface")
67 pl_iface.set_attribute_value("label", "iface_%d" % pl_node.guid)
68 pl_iface.connector("inet").connect(pl_inet.connector("devs"))
69 pl_node.connector("devs").connect(pl_iface.connector("node"))
70 return pl_node, pl_iface
72 def create_vlc_server(movie, pl_node, slice_desc):
73 mv = os.path.basename(movie)
74 pl_app = slice_desc.create("Application")
75 pl_app.set_attribute_value("rpmFusion", True)
76 pl_app.set_attribute_value("depends", "vlc")
77 pl_app.set_attribute_value("build",
78 # "echo -e 'new TEST vod enabled\\nsetup TEST input %s' > ${SOURCES}/VOD.vlm" % mv)
79 "echo -e 'new TEST broadcast enabled loop\\n"\
80 "setup TEST input %s\\n"\
81 "setup TEST output #rtp{mux=ts,sdp=rtsp://0.0.0.0:8554/TEST}\\n\\n"\
82 "new test_sched schedule enabled\\n"\
83 "setup test_sched append control TEST play' > ${SOURCES}/VOD.vlm" % mv)
85 pl_app.set_attribute_value("sources", "%s" % movie)
86 pl_app.set_attribute_value("command",
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' | sed '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 vlc_stderr = controller.trace(mon.vlc.guid, "stderr")
179 results = dict({"cpumem": cpumem_stdout, "net": net_stdout,
180 "vlc_error": vlc_stderr})
182 for name, stdout in results.iteritems():
183 fpath = os.path.join(node_path, name)
188 # store node info file
189 fpath = os.path.join(root_path, "hosts")
195 slicename = os.environ.get("PL_SLICE")
196 pl_host = os.environ.get("PL_HOST", "www.planet-lab.eu")
197 pl_ssh_key = os.environ.get(
199 "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'],) )
200 pl_user = os.environ.get('PL_USER')
201 pl_pwd = os.environ.get('PL_PASS')
202 exp_label = "%s" % uuid.uuid4()
204 usage = "usage: %prog -s <pl_slice> -H <pl_host> -k <ssh_key> -u <pl_user> \
205 -p <pl_password> -m <movie> -r <results-dir> -l <experiment-label>"
207 parser = OptionParser(usage=usage)
208 parser.add_option("-s", "--slicename", dest="slicename",
209 help="PlanetLab slicename", default=slicename, type="str")
210 parser.add_option("-H", "--pl-host", dest="pl_host",
211 help="PlanetLab site (e.g. www.planet-lab.eu)",
212 default=pl_host, type="str")
213 parser.add_option("-k", "--ssh-key", dest="pl_ssh_key",
214 help="Path to private ssh key used for PlanetLab authentication",
215 default=pl_ssh_key, type="str")
216 parser.add_option("-u", "--pl-user", dest="pl_user",
217 help="PlanetLab account user (i.e. Registration email address)",
218 default=pl_user, type="str")
219 parser.add_option("-p", "--pl-pwd", dest="pl_pwd",
220 help="PlanetLab account password", default=pl_pwd, type="str")
221 parser.add_option("-m", "--movie", dest="movie",
222 help="Stream movie", type="str")
223 parser.add_option("-r", "--results", dest="results_dir", default = "/tmp",
224 help="Path to directory to store results", type="str")
225 parser.add_option("-l", "--label", dest="exp_label", default = exp_label,
226 help="Label to identify experiment results", type="str")
227 parser.add_option("-t", "--time", dest="time_to_run", default = 1,
228 help="Time to run the experiment in hours", type="float")
230 (options, args) = parser.parse_args()
232 if not options.movie:
233 parser.error("movie is a required argument")
235 return (options.slicename, options.pl_host, options.pl_user,
236 options.pl_pwd, options.pl_ssh_key, options.movie,
237 options.results_dir, options.exp_label, options.time_to_run)
239 if __name__ == '__main__':
240 root_dir = tempfile.mkdtemp()
249 time_to_run) = get_options()
251 # list to store information on monitoring apps per node
254 # Create the experiment description object
255 exp_desc = ExperimentDescription()
258 slice_desc = create_slice(exp_desc, pl_slice, pl_host, pl_user, pl_pwd,
259 pl_ssh_key, root_dir)
261 # Create the Internet box object
262 pl_inet = slice_desc.create("Internet")
265 hostname = "ple6.ipv6.lip6.fr"
266 (root_node, root_iface) = create_node(hostname, pl_inet, slice_desc)
268 # Create monitor info object for root node
269 root_mon = MonitorInfo(hostname, MonitorInfo.TYPE_ROOT)
270 monitors.append(root_mon)
273 root_vlc = create_vlc_server(movie, root_node, slice_desc)
275 # Add memory and cpu monitoring for root node
276 root_mon.cpumem_monitor = create_cpumem_monitor(root_node, slice_desc)
278 # Add reference to vlc app
279 root_mon.vlc = root_vlc
285 hostnames = ["planetlab1.rd.tut.fi",
286 "planetlab1.s3.kth.se",
287 "planetlab1.tlm.unavarra.es",
288 "planet1.servers.ua.pt",
289 "onelab3.warsaw.rd.tp.pl",
290 "gschembra3.diit.unict.it",
291 "iraplab1.iralab.uni-karlsruhe.de",
292 "host3-plb.loria.fr",
294 "planetlab04.cnds.unibe.ch"]
296 for hostname in hostnames:
297 pl_node, pl_iface = create_node(hostname, pl_inet, slice_desc)
298 cli_ifaces.append(pl_iface)
300 # Create monitor info object for root node
301 node_mon = MonitorInfo(hostname, MonitorInfo.TYPE_LEAF)
302 monitors.append(node_mon)
304 # Add memory and cpu monitoring for all nodes
305 node_mon.cpumem_monitor = create_cpumem_monitor(pl_node, slice_desc)
307 # Add network monitoring for all nodes
308 node_mon.net_monitor = create_net_monitor(pl_node, slice_desc, [root_iface])
311 vlc = create_vlc_client(root_node, pl_node, slice_desc)
314 # Add reference to vlc app
317 # Add network monitoring for root node
318 root_mon.net_monitor = create_net_monitor(root_node, slice_desc, cli_ifaces)
320 xml = exp_desc.to_xml()
322 controller = ExperimentController(xml, root_dir)
325 start_time = time.time()
326 duration = time_to_run * 3600 # in seconds
329 if (time.time() - start_time) > duration: # elapsed time
330 TERMINATE.append(None)
334 # store results in results dir
335 store_results(controller, monitors, results_dir, exp_label)
337 controller.shutdown()