Changing reschedule_delay internals
[nepi.git] / src / nepi / resources / linux / udptest.py
1 #
2 #    NEPI, a framework to manage network experiments
3 #    Copyright (C) 2013 INRIA
4 #
5 #    This program is free software: you can redistribute it and/or modify
6 #    it under the terms of the GNU General Public License as published by
7 #    the Free Software Foundation, either version 3 of the License, or
8 #    (at your option) any later version.
9 #
10 #    This program is distributed in the hope that it will be useful,
11 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #    GNU General Public License for more details.
14 #
15 #    You should have received a copy of the GNU General Public License
16 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 #
18 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
19
20 from nepi.execution.attribute import Attribute, Flags, Types
21 from nepi.execution.resource import clsinit_copy, ResourceState
22 from nepi.resources.linux.application import LinuxApplication
23 from nepi.util.timefuncs import tnow
24
25 import os
26
27 @clsinit_copy
28 class LinuxUdpTest(LinuxApplication):
29     """ Uses the hpcbench udptest tool to gather UDP measurements.
30     Measurements require two ends, a server and a client RM.
31
32     http://hpcbench.sourceforge.net/
33     """
34     _rtype = "LinuxUdpTest"
35
36     @classmethod
37     def _register_attributes(cls):
38         s = Attribute("s",
39             "Runs in server mode. ",
40             type = Types.Bool,
41             default = False,
42             flags = Flags.Design)
43
44         p = Attribute("p",
45             "Port to listen to in server mode, or to connect to in client mode. "
46             "Defaults to 5678. ",
47             type = Types.Integer,
48             flags = Flags.Design)
49
50         a = Attribute("a",
51             "Client option. Perform UDP Round Trip Time (latency) ",
52             type = Types.Bool,
53             flags = Flags.Design)
54
55         A = Attribute("A",
56             "Client option. "
57             "Message size for UDP RTT test. "
58             "UDP RTT (latency) test with specified message size.",
59             type = Types.Integer,
60             flags = Flags.Design)
61
62         b = Attribute("b",
63             "Client option. "
64             "Client UDP buffer size in bytes. Using system default "
65             "value if not defined.",
66             type = Types.Integer,
67             flags = Flags.Design)
68
69         B = Attribute("B",
70             "Client option. "
71             "Server UDP buffer size in bytes. The same as cleint's by default.",
72             type = Types.Integer,
73             flags = Flags.Design)
74
75         c = Attribute("c",
76             "Client option. "
77             "CPU log option. Tracing system info during the test. "
78             "Only available when output is defined. ",
79             type = Types.Bool,
80             flags = Flags.Design)
81
82         d = Attribute("d",
83             "Client option. "
84             "Data size of each read/write in bytes. The same as packet size "
85             "by default.",
86             type = Types.Integer,
87             flags = Flags.Design)
88
89         e = Attribute("e",
90             "Client option. "
91             "Exponential test (data size of each sending increasing from 1 "
92             "byte to packet size). ",
93             type = Types.Bool,
94             flags = Flags.Design)
95
96         g = Attribute("g",
97             "Client option. "
98             "UDP traffic generator (Keep sending data to a host). "
99             "Work without server's support.",
100             type = Types.Bool,
101             flags = Flags.Design)
102
103         target = Attribute("target",
104             "Client option. "
105             "Hostname or IP address of UDP server. Must be specified.",
106             flags = Flags.Design)
107
108         i = Attribute("i",
109             "Client option. "
110             "Bidirectional UDP throuhgput test. Default is unidirection "
111             "stream test. ",
112             type = Types.Bool,
113             flags = Flags.Design)
114
115         l = Attribute("l",
116             "Client option. "
117             "UDP datagram (packet) size in bytes ( < udp-buffer-szie ). "
118             "1460 by default.",
119             type = Types.Integer,
120             flags = Flags.Design)
121
122         m = Attribute("m",
123             "Client option. "
124             "Total message size in bytes. 1048576 by default.",
125             type = Types.Integer,
126             flags = Flags.Design)
127
128         o = Attribute("o",
129             "Client option. "
130             "Output file name. ",
131             flags = Flags.Design)
132
133         P = Attribute("P",
134             "Client option. "
135             "Write the plot file for gnuplot. Only enable when the output "
136             "is specified. ",
137             type = Types.Bool,
138             flags = Flags.Design)
139
140         q = Attribute("q",
141             "Client option. "
142             "Define the TOS field of IP packets. "
143             "Six values can be used for this setting:\n"
144             " 1:(IPTOS)-Minimize delay\n"
145             " 2:(IPTOS)-Maximize throughput\n"
146             " 3:(DiffServ)-Class1 with low drop probability\n"
147             " 4:(DiffServ)-class1 with high drop probability\n"
148             " 5:(DiffServ)-Class4 with low drop probabiltiy\n"
149             " 6:(DiffServ)-Class4 with high drop probabiltiy\n"
150             "Write the plot file for gnuplot. Only enable when the output "
151             "is specified. ",
152             type = Types.Enumerate,
153             allowed = ["1", "2", "3", "4", "5", "6"],
154             flags = Flags.Design)
155
156         r = Attribute("r",
157             "Client option. "
158             "Repetition of tests. 10 by default. ",
159             type = Types.Integer,
160             flags = Flags.Design)
161
162         t = Attribute("t",
163             "Client option. "
164             "Test time constraint in seconds. 5 by default. ",
165             type = Types.Integer,
166             flags = Flags.Design)
167
168         T = Attribute("T",
169             "Client option. "
170             "Throughput constraint for UDP generator or throughput "
171             "test. Unlimited by default. ",
172             type = Types.Integer,
173             flags = Flags.Design)
174
175         continuous = Attribute("continuous",
176             "Run nping in a while loop",
177             type = Types.Bool,
178             default = False,
179             flags = Flags.Design)
180
181         print_timestamp = Attribute("printTimestamp",
182             "Print timestamp before running nping",
183             type = Types.Bool,
184             default = False,
185             flags = Flags.Design)
186
187         cls._register_attribute(s)
188         cls._register_attribute(p)
189         cls._register_attribute(a)
190         cls._register_attribute(A)
191         cls._register_attribute(b)
192         cls._register_attribute(B)
193         cls._register_attribute(c)
194         cls._register_attribute(d)
195         cls._register_attribute(e)
196         cls._register_attribute(g)
197         cls._register_attribute(target)
198         cls._register_attribute(g)
199         cls._register_attribute(i)
200         cls._register_attribute(l)
201         cls._register_attribute(m)
202         cls._register_attribute(o)
203         cls._register_attribute(P)
204         cls._register_attribute(q)
205         cls._register_attribute(r)
206         cls._register_attribute(t)
207         cls._register_attribute(T)
208         cls._register_attribute(continuous)
209         cls._register_attribute(print_timestamp)
210
211     def __init__(self, ec, guid):
212         super(LinuxUdpTest, self).__init__(ec, guid)
213         self._home = "udptest-%s" % self.guid
214
215     def do_deploy(self):
216         if not self.get("command"):
217             self.set("command", self._start_command)
218
219         if not self.get("sources"):
220             self.set("sources", self._sources)
221
222         if not self.get("install"):
223             self.set("install", self._install)
224
225         if not self.get("build"):
226             self.set("build", self._build)
227
228         if not self.get("env"):
229             self.set("env", self._environment)
230
231         if not self.get("depends"):
232             self.set("depends", self._depends)
233
234         super(LinuxUdpTest, self).do_deploy()
235
236     def upload_start_command(self):
237         super(LinuxUdpTest, self).upload_start_command()
238
239         if self.get("s") == True:
240             # We want to make sure the server is running
241             # before the client starts.
242             # Run the command as a bash script in background,
243             # in the host ( but wait until the command has
244             # finished to continue )
245             self._run_in_background()
246     
247     def do_start(self):
248         if self.get("s") == True:
249             # Server is already running
250             if self.state == ResourceState.READY:
251                 command = self.get("command")
252                 self.info("Starting command '%s'" % command)
253
254                 self.set_started()
255             else:
256                 msg = " Failed to execute command '%s'" % command
257                 self.error(msg, out, err)
258                 raise RuntimeError, err
259         else:
260             super(LinuxUdpTest, self).do_start()
261  
262     @property
263     def _start_command(self):
264         args = []
265         if self.get("continuous") == True:
266             args.append("while true; do ")
267
268         if self.get("printTimestamp") == True:
269             args.append("""echo "`date +'%Y%m%d%H%M%S'`";""")
270
271         if self.get("s") == True:
272             args.append("udpserver")
273         else:
274             args.append("udptest")
275
276         if self.get("p"):
277             args.append("-p %d" % self.get("p"))
278         if self.get("a") == True:
279             args.append("-a")
280         if self.get("A"):
281             args.append("-A %d" % self.get("A"))
282         if self.get("b"):
283             args.append("-b %d" % self.get("b"))
284         if self.get("B"):
285             args.append("-B %d" % self.get("B"))
286         if self.get("c") == True:
287             args.append("-c")
288         if self.get("d"):
289             args.append("-d %d" % self.get("d"))
290         if self.get("e") == True:
291             args.append("-e")
292         if self.get("g") == True:
293             args.append("-g")
294         if self.get("target"):
295             args.append("-h %s" % self.get("target"))
296         if self.get("i") == True:
297             args.append("-i")
298         if self.get("l"):
299             args.append("-l %d" % self.get("l"))
300         if self.get("m"):
301             args.append("-m %d" % self.get("m"))
302         if self.get("o"):
303             args.append("-o %d" % self.get("o"))
304         if self.get("P"):
305             args.append("-P %d" % self.get("P"))
306         if self.get("q"):
307             args.append("-q %s" % self.get("q"))
308         if self.get("r"):
309             args.append("-r %d" % self.get("r"))
310         if self.get("t"):
311             args.append("-t %d" % self.get("t"))
312         if self.get("T"):
313             args.append("-T %d" % self.get("T"))
314
315         if self.get("continuous") == True:
316             args.append("; done ")
317
318         command = " ".join(args)
319
320         return command
321
322     @property
323     def _sources(self):
324         return "http://hpcbench.sourceforge.net/udp.tar.gz"
325
326     @property
327     def _depends(self):
328         return "gcc make"
329
330     @property
331     def _build(self):
332         sources = self.get("sources").split(" ")[0]
333         sources = os.path.basename(sources)
334
335         return (
336             # Evaluate if ccnx binaries are already installed
337             " ( "
338                 " test -f ${BIN}/udptest && "
339                 " echo 'binaries found, nothing to do' "
340             " ) || ( "
341             # If not, untar and build
342                 " ( "
343                     " mkdir -p ${SRC}/udptest && "
344                     " tar xf ${SRC}/%(sources)s --strip-components=1 -C ${SRC}/udptest "
345                  " ) && "
346                     "cd ${SRC}/udptest && "
347                     # Just execute and silence warnings...
348                     " ( make ) "
349              " )") % ({ 'sources': sources,
350                  })
351
352     @property
353     def _install(self):
354         return (
355             # Evaluate if ccnx binaries are already installed
356             " ( "
357                 " test -f ${BIN}/udptest && "
358                 " echo 'binaries found, nothing to do' "
359             " ) || ( "
360             # If not, install
361                 "  mv ${SRC}/udptest ${BIN} "
362             " )")
363
364     @property
365     def _environment(self):
366         return "PATH=$PATH:${BIN}/udptest"
367
368     def valid_connection(self, guid):
369         # TODO: Validate!
370         return True
371