[PATCH] TaskAPI: use netns argument in hostAPI config() method
by Jan Tluka
The hostAPI's method config() has the netns argument but it was not
passed further.
Fixes #125.
Signed-off-by: Jan Tluka <jtluka(a)redhat.com>
---
lnst/Controller/Task.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/lnst/Controller/Task.py b/lnst/Controller/Task.py
index ccbd299..073aacb 100644
--- a/lnst/Controller/Task.py
+++ b/lnst/Controller/Task.py
@@ -176,6 +176,7 @@ class HostAPI(object):
cmd = {"host": str(self._id), "type": "config"}
cmd["options"] = [{"name": option, "value": value}]
cmd["persistent"] = persistent
+ cmd["netns"] = netns
return self._ctl._run_command(cmd)
--
1.9.3
8 years, 10 months
[RFC] PerfRepo integration proposal
by Ondrej Lichtner
From: Ondrej Lichtner <olichtne(a)redhat.com>
The following patch creates a first version of a ENRT recipe that is integrated
with PerfRepo - Netperf results are stored in a PerfRepo instance. I don't want
this patch to be pushed upstream, yet, since it doesn't properly check if
PerfRepo is accessible and because it will probably have some other stability
problems. Therefore this is just a request for comments about what can be done
better or what needs to be changed.
Any feedback is greatly appreciated.
Ondrej Lichtner (1):
3_vlans task: refactoring and storing results in PerfRepo
recipes/regression_tests/phase1/3_vlans.py | 212 ++++++++++++++++++-----------
1 file changed, 136 insertions(+), 76 deletions(-)
--
2.1.0
8 years, 10 months
[PATCH] Netperf: major refactorization
by Ondrej Lichtner
From: Ondrej Lichtner <olichtne(a)redhat.com>
This commit brings major changes to the client side of the Netperf test
module.
* The first change is that the return message to the controller now
contains data about the measured speed.
* Secondly threshold and result parsing were separated into their own
functions so that they're easier to manage.
* The client measures speeds in kilobits by default, previously this
wasn't set so whatever Netperf deemed appropriate was used. This helps
with result parsing.
* Added a new option 'runs' which you can use to make Netperf do
multiple runs with specified parameters. The final result is an
average of all the results and a standard deviation is computed.
* When the result is 0.0 it is automatically assumed that the test has
failed even when no threshold was set.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
---
test_modules/Netperf.py | 204 +++++++++++++++++++++++++++++-------------------
1 file changed, 125 insertions(+), 79 deletions(-)
diff --git a/test_modules/Netperf.py b/test_modules/Netperf.py
index a098d5a..95f88ef 100644
--- a/test_modules/Netperf.py
+++ b/test_modules/Netperf.py
@@ -11,6 +11,7 @@ import errno
import re
from lnst.Common.TestsCommon import TestGeneric
from lnst.Common.ShellProcess import ShellProcess
+from lnst.Common.Utils import std_deviation
class Netperf(TestGeneric):
@@ -27,7 +28,7 @@ class Netperf(TestGeneric):
duration = self.get_opt("duration")
port = self.get_opt("port")
testname = self.get_opt("testname")
- cmd = "netperf -H %s" % netperf_server
+ cmd = "netperf -H %s -f k" % netperf_server
if port is not None:
"""
client connects on this port
@@ -76,7 +77,7 @@ class Netperf(TestGeneric):
cmd += " %s" % netperf_opts
return cmd
- def _parse_output(self, threshold, output):
+ def _parse_output(self, output):
testname = self.get_opt("testname")
if testname == "UDP_STREAM":
# pattern for UDP_STREAM throughput output
@@ -98,69 +99,60 @@ class Netperf(TestGeneric):
# decimal decimal decimal float (float)
pattern_sctp = "\d+\s+\d+\s+\d+\s+\d+\.\d+\s+(\d+(\.\d+){0,1})"
r2 = re.search(pattern_sctp, output.lower())
- if threshold is not None:
- # pattern for threshold
- # group(1) ... threshold value
- # group(3) ... threshold units
- # group(4) ... bytes/bits
- if (testname == "TCP_STREAM" or testname == "UDP_STREAM" or
- testname == "SCTP_STREAM" or testname == "SCTP_STREAM_MANY"):
- pattern_stream = "(\d*(\.\d*){0,1})\s*([ kmgt])(bits|bytes)\/sec"
- r1 = re.search(pattern_stream, threshold.lower())
- if r1 is None:
- return (False, "Invalid unit type in the throughput option")
- threshold_rate = float(r1.group(1))
- threshold_unit_size = r1.group(3)
- threshold_unit_type = r1.group(4)
- elif (testname == "TCP_RR" or testname == "UDP_RR" or
- testname == "SCTP_RR"):
- pattern_rr = "(\d*(\.\d*){0,1})\s*trans\.\/sec"
- r1 = re.search(pattern_rr, threshold.lower())
- if r1 is None:
- return (False, "Invalid unit type in the throughput option")
- threshold_rate = float(r1.group(1))
- threshold_unit_size = ""
- threshold_unit_type = "Trans./sec"
- throughput_rate = float(r2.group(1))
- """
- this part converts threshold and throughput rates to same format
- user will get output in format specified in threshold option
- if no threshold option is put in, default format is Mbits
- """
- if (testname == "UDP_STREAM" or testname == "TCP_STREAM" or
- testname == "SCTP_STREAM" or testname == "SCTP_STREAM_MANY"):
- if threshold_unit_size == 'k':
- throughput_rate *= 1000
- elif threshold_unit_size == 'g':
- throughput_rate /= 1000
- elif threshold_unit_size == 't':
- throughput_rate /= 1000 * 1000
- if threshold_unit_type == "bytes":
- throughput_rate /= 8
- if threshold_rate > throughput_rate:
- return (False, "Measured rate (%s %s%s) is below threshold "
- "(%s %s%s)!" % (throughput_rate,
- threshold_unit_size.upper(),
- threshold_unit_type,
- threshold_rate,
- threshold_unit_size.upper(),
- threshold_unit_type))
- else:
- return (True, "Measured rate (%s %s%s) is over threshold "
- "(%s %s%s)." % (throughput_rate,
- threshold_unit_size.upper(),
- threshold_unit_type,
- threshold_rate,
- threshold_unit_size.upper(),
- threshold_unit_type))
- else:
- if (testname == "TCP_RR" or testname == "UDP_RR" or
- testname == "SCTP_RR"):
- return (True, "Measured rate: %s Trans./sec" % r2.group(1))
- else:
- return (True, "Measured rate: %s Mbits/sec" % r2.group(1))
+
+ rate_in_kb = float(r2.group(1))
+
+ return {"rate": rate_in_kb*1000,
+ "unit": "bps"}
+ def _parse_threshold(self, threshold):
+ if threshold is None:
+ return None
+ # pattern for threshold
+ # group(1) ... threshold value
+ # group(3) ... threshold units
+ # group(4) ... bytes/bits
+ if (testname == "TCP_STREAM" or testname == "UDP_STREAM" or
+ testname == "SCTP_STREAM" or testname == "SCTP_STREAM_MANY"):
+ pattern_stream = "(\d*(\.\d*)?)\s*([ kmgtKMGT])(bits|bytes)\/sec"
+ r1 = re.search(pattern_stream, threshold)
+ if r1 is None:
+ res_data["msg"] = "Invalid unit type in the "\
+ "throughput option"
+ return (False, res_data)
+ threshold_rate = float(r1.group(1))
+ threshold_unit_size = r1.group(3)
+ threshold_unit_type = r1.group(4)
+ if threshold_unit_size == 'k':
+ threshold_rate *= 1000
+ elif threshold_unit_size == 'K':
+ threshold_rate *= 1024
+ elif threshold_unit_size == 'g':
+ threshold_rate *= 1000*1000
+ elif threshold_unit_size == 'G':
+ threshold_rate *= 1024*1024
+ elif threshold_unit_size == 't':
+ threshold_rate *= 1000 * 1000 * 1000
+ elif threshold_unit_size == 'T':
+ threshold_rate *= 1024 * 1024 * 1024
+ if threshold_unit_type == "bytes":
+ threshold_rate *= 8
+ threshold_unit_type = "bps"
+ elif (testname == "TCP_RR" or testname == "UDP_RR" or
+ testname == "SCTP_RR"):
+ pattern_rr = "(\d*(\.\d*)?)\s*trans\.\/sec"
+ r1 = re.search(pattern_rr, threshold.lower())
+ if r1 is None:
+ res_data["msg"] = "Invalid unit type in the "\
+ "throughput option"
+ return (False, res_data)
+ threshold_rate = float(r1.group(1))
+ threshold_unit_size = ""
+ threshold_unit_type = "tps"
+
+ return {"rate": threshold_rate,
+ "unit": threshold_unit_type}
def _run_server(self, cmd):
logging.debug("running as server...")
@@ -173,29 +165,83 @@ class Netperf(TestGeneric):
def _run_client(self, cmd):
logging.debug("running as client...")
- client = ShellProcess(cmd)
- try:
- rv = client.wait()
- except OSError as e:
- if e.errno == errno.EINTR:
- client.kill()
- output = client.read_nonblocking()
+
+ res_data = {}
+
+ rv = 0
+ runs = self.get_opt("runs", default=1)
+ results = []
+ rates = []
+ for i in range(1, runs+1):
+ if runs > 1:
+ logging.info("Netperf starting run %d" % i)
+ client = ShellProcess(cmd)
+ try:
+ rv += client.wait()
+ except OSError as e:
+ if e.errno == errno.EINTR:
+ client.kill()
+ output = client.read_nonblocking()
+ results.append(self._parse_output(output))
+ rates.append(results[-1]["rate"])
+
+ if runs > 1:
+ res_data["results"] = results
+
+ rate = sum(rates)/len(rates)
+ rate_std_deviation = std_deviation(rates)
+ res_data["rate"] = rate
+ res_data["rate_std_deviation"] = rate_std_deviation
+
+ threshold = self._parse_threshold(self.get_opt("threshold"))
+ threshold_std_deviation = self._parse_threshold(self.get_opt("threshold_std_deviation"))
+
+ res_val = False
+ if threshold is not None:
+ threshold = threshold["rate"]
+ if threshold_std_deviation is None:
+ threshold_std_deviation = 0.0
+ else:
+ threshold_std_deviation = threshold_std_deviation["rate"]
+ result_interval = (rate - rate_std_deviation,
+ rate + rate_std_deviation)
+ threshold_interval = (threshold - threshold_std_deviation,
+ threshold + threshold_std_deviation)
+
+ if threshold_interval[0] > result_interval[1]:
+ res_val = False
+ res_data["msg"] = "Measured rate %.2f +-%.2f bps is lower "\
+ "than threshold %.2f +-%.2f" %\
+ (rate, rate_std_deviation,
+ threshold, threshold_std_deviation)
+ else:
+ res_val = True
+ res_data["msg"] = "Measured rate %.2f +-%.2f bps is higher "\
+ "than threshold %.2f +-.2%f" %\
+ (rate, rate_std_deviation,
+ threshold, threshold_std_deviation)
+ else:
+ if rate > 0.0:
+ res_val = True
+ else:
+ res_val = False
+ res_data["msg"] = "Measured rate was %.2f +-%.2f bps" %\
+ (rate, rate_std_deviation)
+
if rv != 0:
- logging.info("Could not get performance throughput! Are you sure "
- "netperf is installed on both machines and machines "
- "are mutually accessible?")
- return (False, "Could not get performance throughput! Are you "
- "sure netperf is installed on both machines and "
- "machines are mutually accessible?")
- return self._parse_output(self.get_opt("threshold"), output)
+ res_data["msg"] = "Could not get performance throughput! Are you "\
+ "sure netperf is installed on both machines and "\
+ "machines are mutually accessible?"
+ logging.info(res_data["msg"])
+ return (False, res_data)
+ return (res_val, res_data)
def run(self):
self.role = self.get_mopt("role")
cmd = self._compose_cmd(self.role)
logging.debug("compiled command: %s" % cmd)
if self.role == "client":
- (rv, message) = self._run_client(cmd)
- res_data = {"msg" : message}
+ (rv, res_data) = self._run_client(cmd)
if rv == False:
return self.set_fail(res_data)
return self.set_pass(res_data)
--
2.1.0
8 years, 10 months
[PATCH 1/6] NetTestController: change dir when running a python task
by Ondrej Lichtner
From: Ondrej Lichtner <olichtne(a)redhat.com>
This patch makes it so that we change into the directory containing the
python task before running it. This ensures that the developer can use
file paths relative to the location of the python taks.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
---
lnst/Controller/NetTestController.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lnst/Controller/NetTestController.py b/lnst/Controller/NetTestController.py
index eeb6426..5c2695d 100644
--- a/lnst/Controller/NetTestController.py
+++ b/lnst/Controller/NetTestController.py
@@ -682,10 +682,13 @@ class NetTestController:
# Initialize the API handle
Task.ctl = Task.ControllerAPI(self, self._machines)
+ cwd = os.getcwd()
task_path = task["python"]
name = os.path.basename(task_path.abs_path()).split(".")[0]
sys.path.append(os.path.dirname(task_path.resolve()))
+ os.chdir(os.path.dirname(task_path.resolve()))
module = imp.load_source(name, task_path.resolve())
+ os.chdir(cwd)
sys.path.remove(os.path.dirname(task_path.resolve()))
#restore resource table
--
2.1.0
8 years, 10 months
[PATCH 1/8] NetTestController: change dir when running a python task
by Ondrej Lichtner
From: Ondrej Lichtner <olichtne(a)redhat.com>
This patch makes it so that we change into the directory containing the
python task before running it. This ensures that the developer can use
file paths relative to the location of the python taks.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
---
lnst/Controller/NetTestController.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lnst/Controller/NetTestController.py b/lnst/Controller/NetTestController.py
index eeb6426..5c2695d 100644
--- a/lnst/Controller/NetTestController.py
+++ b/lnst/Controller/NetTestController.py
@@ -682,10 +682,13 @@ class NetTestController:
# Initialize the API handle
Task.ctl = Task.ControllerAPI(self, self._machines)
+ cwd = os.getcwd()
task_path = task["python"]
name = os.path.basename(task_path.abs_path()).split(".")[0]
sys.path.append(os.path.dirname(task_path.resolve()))
+ os.chdir(os.path.dirname(task_path.resolve()))
module = imp.load_source(name, task_path.resolve())
+ os.chdir(cwd)
sys.path.remove(os.path.dirname(task_path.resolve()))
#restore resource table
--
2.1.0
8 years, 10 months
[PATCH 01/10] Task: add set_parameter(s) and set_tag methods
by Ondrej Lichtner
From: Ondrej Lichtner <olichtne(a)redhat.com>
Methods for adding parameters were missing from the PerfRepoResult
class, this commit fixes that.
Same goes for the set_tag method that sets a single tag instead of a
list of tags.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
---
lnst/Controller/Task.py | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/lnst/Controller/Task.py b/lnst/Controller/Task.py
index f2ee4e0..e8db95f 100644
--- a/lnst/Controller/Task.py
+++ b/lnst/Controller/Task.py
@@ -546,9 +546,19 @@ class PerfRepoResult(object):
for pair in list_to_dot(mapping, "mapping.", "machine"):
self._testExecution.add_parameter(pair[0], pair[1])
+ def set_tag(self, tag):
+ self._testExecution.add_tag(tag)
+
def set_tags(self, tags):
for tag in tags:
- self._testExecution.add_tag(tag)
+ self.set_tag(tag)
+
+ def set_parameter(self, name, value):
+ self._testExecution.add_parameter(name, value)
+
+ def set_parameters(self, params):
+ for name, value in params:
+ self.set_parameter(name, value)
def get_testExecution(self):
return self._testExecution
--
2.1.0
8 years, 11 months