aboutsummaryrefslogtreecommitdiffstats
path: root/resources/tools/wrk
diff options
context:
space:
mode:
authorTibor Frank <tifrank@cisco.com>2020-07-13 14:08:13 +0200
committerDave Wallace <dwallacelf@gmail.com>2020-07-16 16:09:50 +0000
commit80adeefab9fc1871675688881498304ddc780828 (patch)
tree433d212f841e6cf5d25eb7226efacd5b6f2a9f46 /resources/tools/wrk
parentf9b18c597f8bd9419ce3ecdd36de351f7b05c59a (diff)
Remove remains of WRK tests
Change-Id: If61783fb717757c6189f06924412bd079e15a08f Signed-off-by: Tibor Frank <tifrank@cisco.com>
Diffstat (limited to 'resources/tools/wrk')
-rw-r--r--resources/tools/wrk/__init__.py16
-rw-r--r--resources/tools/wrk/doc/wrk_lld.rst293
-rw-r--r--resources/tools/wrk/wrk.py299
-rw-r--r--resources/tools/wrk/wrk_errors.py55
-rw-r--r--resources/tools/wrk/wrk_traffic_profile_parser.py294
-rwxr-xr-xresources/tools/wrk/wrk_utils.sh246
6 files changed, 0 insertions, 1203 deletions
diff --git a/resources/tools/wrk/__init__.py b/resources/tools/wrk/__init__.py
deleted file mode 100644
index 977169c00f..0000000000
--- a/resources/tools/wrk/__init__.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright (c) 2018 Cisco and/or its affiliates.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at:
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-__init__ file for directory tools/wrk
-"""
diff --git a/resources/tools/wrk/doc/wrk_lld.rst b/resources/tools/wrk/doc/wrk_lld.rst
deleted file mode 100644
index 1437fd8948..0000000000
--- a/resources/tools/wrk/doc/wrk_lld.rst
+++ /dev/null
@@ -1,293 +0,0 @@
-Onboarding of wrk as a http traffic generator in CSIT
------------------------------------------------------
-
-wrk is a modern HTTP benchmarking tool capable of generating significant
-load when run on a single multi-core CPU.
-
-An optional LuaJIT script can perform HTTP request generation, response
-processing, and custom reporting.
-
-
-wrk installation on TG node
-'''''''''''''''''''''''''''
-
-**Procedure**
-
- #. Check if wrk is installed on the TG node.
- #. If not, install it.
-
-**wrk installation**
-
-::
-
- # Install pre-requisites:
- sudo apt-get install build-essential libssl-dev git -y
-
- # Get the specified version:
- wget ${WRK_DWNLD_PATH}/${WRK_TAR}
- tar xzf ${WRK_TAR}
- cd wrk-${WRK_VERSION}
-
- # Build the wrk:
- cd wrk
- make
-
- # Move the executable to somewhere in the PATH, e.q:
- sudo cp wrk /usr/local/bin
-
-
-wrk traffic profile
-'''''''''''''''''''
-
-**The traffic profile can include these items:**
-
- - List of URLs - mandatory,
- - The first CPU used to run wrk - mandatory,
- - Number of CPUs used for wrk - mandatory,
- - Test duration - mandatory,
- - Number of threads - mandatory,
- - Number of connections - mandatory,
- - LuaJIT script - optional, defaults to no script,
- - HTTP header - optional, defaults to no header,
- - Latency - optional, defaults to False,
- - Timeout - optional, defaults to wrk default.
-
-**List of URLs**
-
-List of URLs for requests. Each URL is requested in a separate instance of wrk.
-Type: list
-
-*Example:*
-
-::
-
- urls:
- - "http://192.168.1.1/1kB.bin"
- - "http://192.168.1.2/1kB.bin"
- - "http://192.168.1.3/1kB.bin"
-
-**The first CPU used to run wrk**
-The first CPU used to run wrk. The other CPUs follow this one.
-Type: integer
-
-*Example:*
-
-::
-
- first-cpu: 1
-
-**Number of CPUs used for wrk**
-
-The number of CPUs used for wrk. The number of CPUs must be a multiplication
-of the number of URLs.
-Type: integer
-
-*Example:*
-
-::
-
- cpus: 6
-
-.. note::
-
- The combinations of URLs and a number of CPUs create following use cases:
-
- - One URL and one CPU - One instance of wrk sends one request (URL) via
- one NIC
- - One URL and n CPUs - n instances of wrk send the same request (URL)
- via one or more NICs
- - n URLs and n CPUs - n instances of wrk send n requests (URL) via one
- or more NICs
- - n URLs and m CPUs, m = a * n - m instances of wrk send n requests
- (URL) via one or more NICs
-
-**Test duration**
-
-Duration of the test in seconds.
-Type: integer
-
-*Example:*
-
-::
-
- duration: 30
-
-**Number of threads**
-
-Total number of threads to use by wrk to send traffic.
-Type: integer
-
-*Example:*
-
-::
-
- nr-of-threads: 1
-
-**Number of connections**
-
-Total number of HTTP connections to keep open with each thread handling
-N = connections / threads.
-Type: integer
-
-*Example:*
-
-::
-
- nr-of-connections: 50
-
-**LuaJIT script**
-
-Path to LuaJIT script.
-Type: string
-
-For more information see: https://github.com/wg/wrk/blob/master/SCRIPTING
-
-*Example:*
-
-::
-
- script: "scripts/report.lua"
-
-**HTTP header**
-
-HTTP header to add to request.
-Type: string (taken as it is) or dictionary
-
-*Example:*
-
-::
-
- # Dictionary:
- header:
- Connection: "close"
-
-or
-
-::
-
- # String:
- header: "Connection: close"
-
-**Latency**
-
-Print detailed latency statistics.
-Type: boolean
-
-*Example:*
-
-::
-
- latency: False
-
-**Timeout**
-
-Record a timeout if a response is not received within this amount of time.
-Type: integer
-
-::
-
- timeout: 5
-
-**Examples of a wrk traffic profile**
-
-*Get the number of connections per second:*
-
-- Use 3 CPUs to send 3 different requests via 3 NICs.
-- The test takes 30 seconds.
-- wrk sends traffic in one thread per CPU.
-- There will be open max 50 connection at the same time.
-- The header is set to 'Connection: "close"' so wrk opens separate connection
- for each request. Then the number of requests equals to the number of
- connections.
-- Timeout for responses from the server is set to 5 seconds.
-
-::
-
- urls:
- - "http://192.168.1.1/0B.bin"
- - "http://192.168.1.2/0B.bin"
- - "http://192.168.1.3/0B.bin"
- cpus: 3
- duration: 30
- nr-of-threads: 1
- nr-of-connections: 50
- header:
- Connection: "close"
- timeout: 5
-
-*Get the number of requests per second:*
-
-- Use 3 CPUs to send 3 different requests via 3 NICs.
-- The test takes 30 seconds.
-- wrk sends traffic in one thread per CPU.
-- There will be max 50 concurrent open connections.
-
-::
-
- urls:
- - "http://192.168.1.1/1kB.bin"
- - "http://192.168.1.2/1kB.bin"
- - "http://192.168.1.3/1kB.bin"
- cpus: 3
- duration: 30
- nr-of-threads: 1
- nr-of-connections: 50
-
-*Get the bandwidth:*
-
-- Use 3 CPUs to send 3 different requests via 3 NICs.
-- The test takes 30 seconds.
-- wrk sends traffic in one thread per CPU.
-- There will be open max 50 connection at the same time.
-- Timeout for responses from the server is set to 5 seconds.
-
-::
-
- urls:
- - "http://192.168.1.1/1MB.bin"
- - "http://192.168.1.2/1MB.bin"
- - "http://192.168.1.3/1MB.bin"
- cpus: 3
- duration: 30
- nr-of-threads: 1
- nr-of-connections: 50
- timeout: 5
-
-
-Running wrk
-'''''''''''
-
-**Suite setup phase**
-
-CSIT framework checks if wrk is installed on the TG node. If not, or if the
-installation is forced, it installs it on the TG node.
-
-*Procedure:*
-
- #. Make sure TRex is stopped.
- #. Bind used TG interfaces to corresponding drivers (defined in the topology
- file).
- #. If the wrk installation is forced:
-
- - Destroy existing wrk
-
- #. If the wrk installation is not forced:
-
- - Check if wrk is installed.
- - If installed, exit.
-
- #. Clone wrk from git (https://github.com/wg/wrk.git)
- #. Build wrk.
- #. Copy the executable to /usr/local/bin so it is in the PATH.
-
-**Test phase**
-
-*Procedure:*
-
-#. Read the wrk traffic profile.
-#. Verify the profile.
-#. Use the information from the profile to set the wrk parameters.
-#. Run wrk.
-#. Read the output.
-#. Evaluate and log the output.
-
diff --git a/resources/tools/wrk/wrk.py b/resources/tools/wrk/wrk.py
deleted file mode 100644
index 85d18d4a9c..0000000000
--- a/resources/tools/wrk/wrk.py
+++ /dev/null
@@ -1,299 +0,0 @@
-# Copyright (c) 2019 Cisco and/or its affiliates.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at:
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""wrk implementation into CSIT framework.
-"""
-
-import re
-
-from copy import deepcopy
-from time import sleep
-
-from robot.api import logger
-
-from resources.libraries.python.ssh import SSH
-from resources.libraries.python.topology import NodeType
-from resources.libraries.python.CpuUtils import CpuUtils
-from resources.libraries.python.Constants import Constants
-
-from resources.tools.wrk.wrk_traffic_profile_parser import WrkTrafficProfile
-from resources.tools.wrk.wrk_errors import WrkError
-
-
-REGEX_LATENCY_STATS = \
- r"Latency\s*" \
- r"(\d*\.*\d*\S*)\s*" \
- r"(\d*\.*\d*\S*)\s*" \
- r"(\d*\.*\d*\S*)\s*" \
- r"(\d*\.*\d*\%)"
-REGEX_RPS_STATS = \
- r"Req/Sec\s*" \
- r"(\d*\.*\d*\S*)\s*" \
- r"(\d*\.*\d*\S*)\s*" \
- r"(\d*\.*\d*\S*)\s*" \
- r"(\d*\.*\d*\%)"
-REGEX_RPS = r"Requests/sec:\s*" \
- r"(\d*\.*\S*)"
-REGEX_BW = r"Transfer/sec:\s*" \
- r"(\d*\.*\S*)"
-REGEX_LATENCY_DIST = \
- r"Latency Distribution\n" \
- r"\s*50\%\s*(\d*\.*\d*\D*)\n" \
- r"\s*75\%\s*(\d*\.*\d*\D*)\n" \
- r"\s*90\%\s*(\d*\.*\d*\D*)\n" \
- r"\s*99\%\s*(\d*\.*\d*\D*)\n"
-
-# Split number and multiplicand, e.g. 14.25k --> 14.25 and k
-REGEX_NUM = r"(\d*\.*\d*)(\D*)"
-
-
-def check_wrk(tg_node):
- """Check if wrk is installed on the TG node.
-
- :param tg_node: Traffic generator node.
- :type tg_node: dict
- :raises: RuntimeError if the given node is not a TG node or if the
- command is not availble.
- """
-
- if tg_node[u"type"] != NodeType.TG:
- raise RuntimeError(u"Node type is not a TG.")
-
- ssh = SSH()
- ssh.connect(tg_node)
-
- ret, _, _ = ssh.exec_command(
- f"sudo -E sh -c '{Constants.REMOTE_FW_DIR}/resources/tools/"
- f"wrk/wrk_utils.sh installed'"
- )
- if int(ret) != 0:
- raise RuntimeError(u"WRK is not installed on TG node.")
-
-
-def run_wrk(tg_node, profile_name, tg_numa, test_type, warm_up=False):
- """Send the traffic as defined in the profile.
-
- :param tg_node: Traffic generator node.
- :param profile_name: The name of wrk traffic profile.
- :param tg_numa: Numa node on which wrk will run.
- :param test_type: The type of the tests: cps, rps, bw
- :param warm_up: If True, warm-up traffic is generated before test traffic.
- :type profile_name: str
- :type tg_node: dict
- :type tg_numa: int
- :type test_type: str
- :type warm_up: bool
- :returns: Message with measured data.
- :rtype: str
- :raises: RuntimeError if node type is not a TG.
- """
-
- if tg_node[u"type"] != NodeType.TG:
- raise RuntimeError(u"Node type is not a TG.")
-
- # Parse and validate the profile
- profile_path = f"resources/traffic_profiles/wrk/{profile_name}.yaml"
- profile = WrkTrafficProfile(profile_path).traffic_profile
-
- cores = CpuUtils.cpu_list_per_node(tg_node, tg_numa)
- first_cpu = cores[profile[u"first-cpu"]]
-
- if len(profile[u"urls"]) == 1 and profile[u"cpus"] == 1:
- params = [
- u"traffic_1_url_1_core",
- str(first_cpu),
- str(profile[u"nr-of-threads"]),
- str(profile[u"nr-of-connections"]),
- f"{profile[u'duration']}s",
- f"'{profile[u'header']}'",
- str(profile[u"timeout"]),
- str(profile[u"script"]),
- str(profile[u"latency"]),
- f"'{u' '.join(profile[u'urls'])}'"
- ]
- if warm_up:
- warm_up_params = deepcopy(params)
- warm_up_params[4] = u"10s"
- elif len(profile[u"urls"]) == profile[u"cpus"]:
- params = [
- u"traffic_n_urls_n_cores",
- str(first_cpu),
- str(profile[u"nr-of-threads"]),
- str(profile[u"nr-of-connections"]),
- f"{profile[u'duration']}s",
- f"'{profile[u'header']}'",
- str(profile[u"timeout"]),
- str(profile[u"script"]),
- str(profile[u"latency"]),
- f"'{u' '.join(profile[u'urls'])}'"
- ]
- if warm_up:
- warm_up_params = deepcopy(params)
- warm_up_params[4] = u"10s"
- else:
- params = [
- u"traffic_n_urls_m_cores",
- str(first_cpu),
- str(profile[u"cpus"] // len(profile[u"urls"])),
- str(profile[u"nr-of-threads"]),
- str(profile[u"nr-of-connections"]),
- f"{profile[u'duration']}s",
- f"'{profile[u'header']}'",
- str(profile[u"timeout"]),
- str(profile[u"script"]),
- str(profile[u"latency"]),
- f"'{u' '.join(profile[u'urls'])}'"
- ]
- if warm_up:
- warm_up_params = deepcopy(params)
- warm_up_params[5] = u"10s"
-
- args = u" ".join(params)
-
- ssh = SSH()
- ssh.connect(tg_node)
-
- if warm_up:
- warm_up_args = u" ".join(warm_up_params)
- ret, _, _ = ssh.exec_command(
- f"{Constants.REMOTE_FW_DIR}/resources/tools/wrk/wrk_utils.sh "
- f"{warm_up_args}", timeout=1800
- )
- if int(ret) != 0:
- raise RuntimeError(u"wrk runtime error.")
- sleep(60)
-
- ret, stdout, _ = ssh.exec_command(
- f"{Constants.REMOTE_FW_DIR}/resources/tools/wrk/wrk_utils.sh {args}",
- timeout=1800
- )
- if int(ret) != 0:
- raise RuntimeError('wrk runtime error.')
-
- stats = _parse_wrk_output(stdout)
-
- log_msg = u"\nMeasured values:\n"
- if test_type == u"cps":
- log_msg += u"Connections/sec: Avg / Stdev / Max / +/- Stdev\n"
- for item in stats[u"rps-stats-lst"]:
- log_msg += u" / ".join(map(str, item)) + u"\n"
- log_msg += f"Total cps: {stats[u'rps-sum']}cps\n"
- elif test_type == u"rps":
- log_msg += u"Requests/sec: Avg / Stdev / Max / +/- Stdev\n"
- for item in stats[u"rps-stats-lst"]:
- log_msg += u" / ".join(map(str, item)) + u"\n"
- log_msg += f"Total rps: {stats[u'rps-sum']}rps\n"
- elif test_type == u"bw":
- log_msg += f"Transfer/sec: {stats[u'bw-sum']}Bps"
-
- logger.info(log_msg)
-
- return log_msg
-
-
-def _parse_wrk_output(msg):
- """Parse the wrk stdout with the results.
-
- :param msg: stdout of wrk.
- :type msg: str
- :returns: Parsed results.
- :rtype: dict
- :raises: WrkError if the message does not include the results.
- """
-
- if u"Thread Stats" not in msg:
- raise WrkError(u"The output of wrk does not include the results.")
-
- msg_lst = msg.splitlines(False)
-
- stats = {
- u"latency-dist-lst": list(),
- u"latency-stats-lst": list(),
- u"rps-stats-lst": list(),
- u"rps-lst": list(),
- u"bw-lst": list(),
- u"rps-sum": 0,
- u"bw-sum": None
- }
-
- for line in msg_lst:
- if u"Latency Distribution" in line:
- # Latency distribution - 50%, 75%, 90%, 99%
- pass
- elif u"Latency" in line:
- # Latency statistics - Avg, Stdev, Max, +/- Stdev
- pass
- elif u"Req/Sec" in line:
- # rps statistics - Avg, Stdev, Max, +/- Stdev
- stats[u"rps-stats-lst"].append(
- (
- _evaluate_number(re.search(REGEX_RPS_STATS, line).group(1)),
- _evaluate_number(re.search(REGEX_RPS_STATS, line).group(2)),
- _evaluate_number(re.search(REGEX_RPS_STATS, line).group(3)),
- _evaluate_number(re.search(REGEX_RPS_STATS, line).group(4))
- )
- )
- elif u"Requests/sec:" in line:
- # rps (cps)
- stats[u"rps-lst"].append(
- _evaluate_number(re.search(REGEX_RPS, line).group(1))
- )
- elif u"Transfer/sec:" in line:
- # BW
- stats[u"bw-lst"].append(
- _evaluate_number(re.search(REGEX_BW, line).group(1))
- )
-
- for item in stats[u"rps-stats-lst"]:
- stats[u"rps-sum"] += item[0]
- stats[u"bw-sum"] = sum(stats[u"bw-lst"])
-
- return stats
-
-
-def _evaluate_number(num):
- """Evaluate the numeric value of the number with multiplicands, e.g.:
- 12.25k --> 12250
-
- :param num: Number to evaluate.
- :type num: str
- :returns: Evaluated number.
- :rtype: float
- :raises: WrkError if it is not possible to evaluate the given number.
- """
-
- val = re.search(REGEX_NUM, num)
- try:
- val_num = float(val.group(1))
- except ValueError:
- raise WrkError(
- u"The output of wrk does not include the results or the format "
- u"of results has changed."
- )
- val_mul = val.group(2).lower()
- if val_mul:
- if u"k" in val_mul:
- val_num *= 1000
- elif u"m" in val_mul:
- val_num *= 1000000
- elif u"g" in val_mul:
- val_num *= 1000000000
- elif u"b" in val_mul:
- pass
- elif u"%" in val_mul:
- pass
- elif u"" in val_mul:
- pass
- else:
- raise WrkError(f"The multiplicand {val_mul} is not defined.")
- return val_num
diff --git a/resources/tools/wrk/wrk_errors.py b/resources/tools/wrk/wrk_errors.py
deleted file mode 100644
index 2cdd76815a..0000000000
--- a/resources/tools/wrk/wrk_errors.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# Copyright (c) 2019 Cisco and/or its affiliates.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at:
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Implementation of exceptions used in the wrk traffic generator.
-"""
-
-
-from robot.api import logger
-
-
-class WrkError(Exception):
- """Exception(s) raised by the wrk traffic generator.
-
- When raising this exception, put this information to the message in this
- order:
- - short description of the encountered problem (parameter msg),
- - relevant messages if there are any collected, e.g., from caught
- exception (optional parameter details),
- - relevant data if there are any collected (optional parameter details).
- """
-
- def __init__(self, msg, details=u""):
- """Sets the exception message and the level.
-
- :param msg: Short description of the encountered problem.
- :param details: Relevant messages if there are any collected, e.g.:
- from caught exception (optional parameter details), or relevant data if
- there are any collected (optional parameter details).
- :type msg: str
- :type details: str
- """
-
- super(WrkError, self).__init__()
- self._msg = msg
- self._details = details
-
- logger.error(self._msg)
- if self._details:
- logger.error(self._details)
-
- def __repr__(self):
- return repr(self._msg)
-
- def __str__(self):
- return str(self._msg)
diff --git a/resources/tools/wrk/wrk_traffic_profile_parser.py b/resources/tools/wrk/wrk_traffic_profile_parser.py
deleted file mode 100644
index f553465705..0000000000
--- a/resources/tools/wrk/wrk_traffic_profile_parser.py
+++ /dev/null
@@ -1,294 +0,0 @@
-# Copyright (c) 2019 Cisco and / or its affiliates.
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not
-# use this file except in compliance with the License. You may obtain a copy
-# of the License at:
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-
-"""wrk traffic profile parser.
-
-See LLD for the structure of a wrk traffic profile.
-"""
-
-
-from os.path import isfile
-from pprint import pformat
-
-from yaml import safe_load, YAMLError
-from robot.api import logger
-
-from resources.tools.wrk.wrk_errors import WrkError
-
-
-class WrkTrafficProfile:
- """The wrk traffic profile.
- """
-
- MANDATORY_PARAMS = (
- u"urls",
- u"first-cpu",
- u"cpus",
- u"duration",
- u"nr-of-threads",
- u"nr-of-connections"
- )
-
- INTEGER_PARAMS = (
- (u"cpus", 1),
- (u"first-cpu", 0),
- (u"duration", 1),
- (u"nr-of-threads", 1),
- (u"nr-of-connections", 1)
- )
-
- def __init__(self, profile_name):
- """Read the traffic profile from the yaml file.
-
- :param profile_name: Path to the yaml file with the profile.
- :type profile_name: str
- :raises: WrkError if it is not possible to parse the profile.
- """
-
- self._profile_name = None
- self._traffic_profile = None
-
- self.profile_name = profile_name
-
- try:
- with open(self.profile_name, u"rt") as profile_file:
- self.traffic_profile = safe_load(profile_file)
- except IOError as err:
- raise WrkError(
- msg=f"An error occurred while opening the file "
- f"'{self.profile_name}'.", details=str(err)
- )
- except YAMLError as err:
- raise WrkError(
- msg=f"An error occurred while parsing the traffic profile "
- f"'{self.profile_name}'.", details=str(err)
- )
-
- self._validate_traffic_profile()
-
- if self.traffic_profile:
- logger.debug(
- f"\nThe wrk traffic profile '{self.profile_name}' is valid.\n"
- )
- logger.debug(f"wrk traffic profile '{self.profile_name}':")
- logger.debug(pformat(self.traffic_profile))
- else:
- logger.debug(
- f"\nThe wrk traffic profile '{self.profile_name}' is invalid.\n"
- )
- raise WrkError(
- f"\nThe wrk traffic profile '{self.profile_name}' is invalid.\n"
- )
-
- def __repr__(self):
- return pformat(self.traffic_profile)
-
- def __str__(self):
- return pformat(self.traffic_profile)
-
- def _validate_traffic_profile(self):
- """Validate the traffic profile.
-
- The specification, the structure and the rules are described in
- doc/wrk_lld.rst
- """
-
- logger.debug(
- f"\nValidating the wrk traffic profile '{self.profile_name}'...\n"
- )
- if not (self._validate_mandatory_structure()
- and self._validate_mandatory_values()
- and self._validate_optional_values()
- and self._validate_dependencies()):
- self.traffic_profile = None
-
- def _validate_mandatory_structure(self):
- """Validate presence of mandatory parameters in trafic profile dict
-
- :returns: whether mandatory structure is followed by the profile
- :rtype: bool
- """
- # Level 1: Check if the profile is a dictionary:
- if not isinstance(self.traffic_profile, dict):
- logger.error(u"The wrk traffic profile must be a dictionary.")
- return False
-
- # Level 2: Check if all mandatory parameters are present:
- is_valid = True
- for param in self.MANDATORY_PARAMS:
- if self.traffic_profile.get(param, None) is None:
- logger.error(f"The parameter '{param}' in mandatory.")
- is_valid = False
- return is_valid
-
- def _validate_mandatory_values(self):
- """Validate that mandatory profile values satisfy their constraints
-
- :returns: whether mandatory values are acceptable
- :rtype: bool
- """
- # Level 3: Mandatory params: Check if urls is a list:
- is_valid = True
- if not isinstance(self.traffic_profile[u"urls"], list):
- logger.error(u"The parameter 'urls' must be a list.")
- is_valid = False
-
- # Level 3: Mandatory params: Check if integers are not below minimum
- for param, minimum in self.INTEGER_PARAMS:
- if not self._validate_int_param(param, minimum):
- is_valid = False
- return is_valid
-
- def _validate_optional_values(self):
- """Validate values for optional parameters, if present
-
- :returns: whether present optional values are acceptable
- :rtype: bool
- """
- is_valid = True
- # Level 4: Optional params: Check if script is present:
- script = self.traffic_profile.get(u"script", None)
- if script is not None:
- if not isinstance(script, str):
- logger.error(u"The path to LuaJIT script in invalid")
- is_valid = False
- else:
- if not isfile(script):
- logger.error(f"The file '{script}' does not exist.")
- is_valid = False
- else:
- self.traffic_profile[u"script"] = None
- logger.debug(
- u"The optional parameter 'LuaJIT script' is not defined. "
- u"No problem."
- )
-
- # Level 4: Optional params: Check if header is present:
- header = self.traffic_profile.get(u"header", None)
- if header is not None:
- if isinstance(header, dict):
- header = u", ".join(
- f"{0}: {1}".format(*item) for item in header.items()
- )
- self.traffic_profile[u"header"] = header
- elif not isinstance(header, str):
- logger.error(u"The parameter 'header' type is not valid.")
- is_valid = False
-
- if not header:
- logger.error(u"The parameter 'header' is defined but empty.")
- is_valid = False
- else:
- self.traffic_profile[u"header"] = None
- logger.debug(
- u"The optional parameter 'header' is not defined. No problem."
- )
-
- # Level 4: Optional params: Check if latency is present:
- latency = self.traffic_profile.get(u"latency", None)
- if latency is not None:
- if not isinstance(latency, bool):
- logger.error(u"The parameter 'latency' must be boolean.")
- is_valid = False
- else:
- self.traffic_profile[u"latency"] = False
- logger.debug(
- u"The optional parameter 'latency' is not defined. No problem."
- )
-
- # Level 4: Optional params: Check if timeout is present:
- if u"timeout" in self.traffic_profile:
- if not self._validate_int_param(u"timeout", 1):
- is_valid = False
- else:
- self.traffic_profile[u"timeout"] = None
- logger.debug(
- u"The optional parameter 'timeout' is not defined. No problem."
- )
-
- return is_valid
-
- def _validate_dependencies(self):
- """Validate dependencies between parameters
-
- :returns: whether dependencies between parameters are acceptable
- :rtype: bool
- """
- # Level 5: Check urls and cpus:
- if self.traffic_profile[u"cpus"] % len(self.traffic_profile[u"urls"]):
- logger.error(
- u"The number of CPUs must be a multiple of the number of URLs."
- )
- return False
- return True
-
- def _validate_int_param(self, param, minimum):
- """Validate that an int parameter is set acceptably
- If it is not an int already but a string, convert and store it as int.
-
- :param param: Name of a traffic profile parameter
- :param minimum: The minimum value for the named parameter
- :type param: str
- :type minimum: int
- :returns: whether param is set to an int of at least minimum value
- :rtype: bool
- """
- value = self._traffic_profile[param]
- if isinstance(value, str):
- if value.isdigit():
- value = int(value)
- else:
- value = minimum - 1
- if isinstance(value, int) and value >= minimum:
- self.traffic_profile[param] = value
- return True
- logger.error(
- f"The parameter '{param}' must be an integer and at least {minimum}"
- )
- return False
-
- @property
- def profile_name(self):
- """Getter - Profile name.
-
- :returns: The traffic profile file path
- :rtype: str
- """
- return self._profile_name
-
- @profile_name.setter
- def profile_name(self, profile_name):
- """
-
- :param profile_name:
- :type profile_name: str
- """
- self._profile_name = profile_name
-
- @property
- def traffic_profile(self):
- """Getter: Traffic profile.
-
- :returns: The traffic profile.
- :rtype: dict
- """
- return self._traffic_profile
-
- @traffic_profile.setter
- def traffic_profile(self, profile):
- """Setter - Traffic profile.
-
- :param profile: The new traffic profile.
- :type profile: dict
- """
- self._traffic_profile = profile
diff --git a/resources/tools/wrk/wrk_utils.sh b/resources/tools/wrk/wrk_utils.sh
deleted file mode 100755
index 16af61416b..0000000000
--- a/resources/tools/wrk/wrk_utils.sh
+++ /dev/null
@@ -1,246 +0,0 @@
-#!/bin/bash
-# Copyright (c) 2019 Cisco and/or its affiliates.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at:
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-set -x
-
-function wrk_utils.installed {
-
- # Check if the WRK utility is installed. Fail if not installed.
-
- # Returns:
- # - 0 - If command is installed.
- # - 1 - If command is not installed.
-
- set -exuo pipefail
-
- command -v wrk
-}
-
-
-function wrk_utils.traffic_1_url_1_core {
- # Send traffic
- # - to n URL (NIC)
- # - using n instances of wrk, each on separate core.
-
- # The CPU used for wrk
- cpu=${1}
- # Total number of threads to use by one instance of wrk to send traffic.
- threads=${2}
- # Total number of HTTP connections to keep open with each thread handling
- # N = connections / threads.
- connections=${3}
- # Duration of the test.
- duration=${4}
- # HTTP header to add to request.
- header=${5}
- # Record a timeout if a response is not received within this amount of time.
- timeout=${6}
- # Path to LuaJIT script.
- script=${7}
- # Print detailed latency statistics.
- latency=${8}
- # URL to send the traffic to.
- url=${9}
-
- if [ "${timeout}" != "None" ]; then
- timeout="--timeout ${timeout}"
- else
- timeout=""
- fi
-
- if [ "${latency}" = "True" ]; then
- latency="--latency"
- else
- latency=""
- fi
-
- if [ "${script}" != "None" ]; then
- script="--script '${script}'"
- else
- script=""
- fi
-
- if [ "${header}" != "None" ]; then
- header="${header}"
- else
- header="''"
- fi
-
- taskset --cpu-list ${cpu} \
- wrk --threads ${threads} \
- --connections ${connections} \
- --duration ${duration} \
- --header "${header}" \
- ${timeout} \
- ${script} \
- ${latency} \
- ${url}
-}
-
-function wrk_utils.traffic_n_urls_n_cores {
- # Send traffic
- # - to n URL (NIC)
- # - using n instances of wrk, each on separate core.
-
- # The first CPU used for wrk
- first_cpu=${1}
- # Total number of threads to use by one instance of wrk to send traffic.
- threads=${2}
- # Total number of HTTP connections to keep open with each thread handling
- # N = connections / threads.
- connections=${3}
- # Duration of the test.
- duration=${4}
- # HTTP header to add to request.
- header=${5}
- # Record a timeout if a response is not received within this amount of time.
- timeout=${6}
- # Path to LuaJIT script.
- script=${7}
- # Print detailed latency statistics.
- latency=${8}
- # URL to send the traffic to.
- urls=${9}
-
- if [ "${timeout}" != "None" ]; then
- timeout="--timeout ${timeout}"
- else
- timeout=""
- fi
-
- if [ "${latency}" = "True" ]; then
- latency="--latency"
- else
- latency=""
- fi
-
- if [ "${script}" != "None" ]; then
- script="--script '${script}'"
- else
- script=""
- fi
-
- if [ "${header}" != "None" ]; then
- header="${header}"
- else
- header="''"
- fi
-
- urls=$(echo ${urls} | tr ";" "\n")
- cpu=${first_cpu}
- for url in ${urls}; do
- taskset --cpu-list ${cpu} \
- wrk --threads ${threads} \
- --connections ${connections} \
- --duration ${duration} \
- --header "${header}" \
- ${timeout} \
- ${script} \
- ${latency} \
- ${url} &
- cpu=$((cpu+1))
- done
-
- sleep ${duration}
- sleep 2
-}
-
-function wrk_utils.traffic_n_urls_m_cores {
- # Send traffic
- # - to n URL (NIC)
- # - using m instances of wrk, each on separate core.
-
- # The first CPU used for wrk
- first_cpu=${1}
- # The last CPU used for wrk
- cpus_per_url=${2}
- # Total number of threads to use by one instance of wrk to send traffic.
- threads=${3}
- # Total number of HTTP connections to keep open with each thread handling
- # N = connections / threads.
- connections=${4}
- # Duration of the test.
- duration=${5}
- # HTTP header to add to request.
- header=${6}
- # Record a timeout if a response is not received within this amount of time.
- timeout=${7}
- # Path to LuaJIT script.
- script=${8}
- # Print detailed latency statistics.
- latency=${9}
- # URL to send the traffic to.
- urls=${10}
-
- if [ "${timeout}" != "None" ]; then
- timeout="--timeout ${timeout}"
- else
- timeout=""
- fi
-
- if [ "${latency}" = "True" ]; then
- latency="--latency"
- else
- latency=""
- fi
-
- if [ "${script}" != "None" ]; then
- script="--script '${script}'"
- else
- script=""
- fi
-
- if [ "${header}" != "None" ]; then
- header="${header}"
- else
- header="''"
- fi
-
- urls=$(echo ${urls} | tr ";" "\n")
-
- cpu=${first_cpu}
- for i in `seq 1 ${cpus_per_url}`; do
- for url in ${urls}; do
- taskset --cpu-list ${cpu} \
- wrk --threads ${threads} \
- --connections ${connections} \
- --duration ${duration} \
- --header "${header}" \
- ${timeout} \
- ${script} \
- ${latency} \
- ${url} &
- cpu=$((cpu+1))
- done
- done
-
- sleep ${duration}
- sleep 2
-}
-
-args=("$@")
-case ${1} in
- installed)
- wrk_utils.installed
- ;;
- traffic_1_url_1_core)
- wrk_utils.traffic_1_url_1_core "${args[@]:1}"
- ;;
- traffic_n_urls_n_cores)
- wrk_utils.traffic_n_urls_n_cores "${args[@]:1}"
- ;;
- traffic_n_urls_m_cores)
- wrk_utils.traffic_n_urls_m_cores "${args[@]:1}"
- ;;
-esac