diff options
Diffstat (limited to 'scripts/automation/trex_control_plane')
5 files changed, 154 insertions, 21 deletions
diff --git a/scripts/automation/trex_control_plane/client_utils/parsing_opts.py b/scripts/automation/trex_control_plane/client_utils/parsing_opts.py index 6f9b4c6d..5cb06604 100755 --- a/scripts/automation/trex_control_plane/client_utils/parsing_opts.py +++ b/scripts/automation/trex_control_plane/client_utils/parsing_opts.py @@ -70,7 +70,10 @@ def match_multiplier_common(val, strict_abs = True): op = None else: match = re.match("^(\d+(\.\d+)?)(bps|kbps|mbps|gbps|pps|kpps|mpps|%?)([\+\-])?$", val) - op = match.group(4) + if match: + op = match.group(4) + else: + op = None result = {} diff --git a/scripts/automation/trex_control_plane/client_utils/yaml_utils.py b/scripts/automation/trex_control_plane/client_utils/yaml_utils.py index 60630a04..825d6fc9 100755 --- a/scripts/automation/trex_control_plane/client_utils/yaml_utils.py +++ b/scripts/automation/trex_control_plane/client_utils/yaml_utils.py @@ -14,7 +14,8 @@ 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. """ - +import traceback +import sys import external_packages import yaml diff --git a/scripts/automation/trex_control_plane/common/rpc_defaults.yaml b/scripts/automation/trex_control_plane/common/rpc_defaults.yaml index 32631609..9325a0e4 100755 --- a/scripts/automation/trex_control_plane/common/rpc_defaults.yaml +++ b/scripts/automation/trex_control_plane/common/rpc_defaults.yaml @@ -50,9 +50,7 @@ stream: mode:
type: object
vm:
- type: array
- has_default: YES
- default: [] # no ranging instructions
+ type: object
rx_stats:
type: object
@@ -112,4 +110,15 @@ rx_stats: latency_enabled:
type: boolean
has_default: YES
- default: False
\ No newline at end of file + default: False
+
+vm:
+ instructions:
+ type: array
+ has_default: YES
+ default: []
+ split_by_var:
+ type: string
+ has_default: YES
+ default: ""
+
diff --git a/scripts/automation/trex_control_plane/common/text_opts.py b/scripts/automation/trex_control_plane/common/text_opts.py index 5a86149c..29fbd69b 100755 --- a/scripts/automation/trex_control_plane/common/text_opts.py +++ b/scripts/automation/trex_control_plane/common/text_opts.py @@ -94,9 +94,16 @@ def underline(text): def text_attribute(text, attribute): - return "{start}{txt}{stop}".format(start=TEXT_CODES[attribute]['start'], - txt=text, - stop=TEXT_CODES[attribute]['end']) + if isinstance(text, str): + return "{start}{txt}{stop}".format(start=TEXT_CODES[attribute]['start'], + txt=text, + stop=TEXT_CODES[attribute]['end']) + elif isinstance(text, unicode): + return u"{start}{txt}{stop}".format(start=TEXT_CODES[attribute]['start'], + txt=text, + stop=TEXT_CODES[attribute]['end']) + else: + raise Exception("not a string") FUNC_DICT = {'blue': blue, @@ -117,6 +124,15 @@ def format_text(text, *args): return_string = func(return_string) return return_string +def format_threshold (value, red_zone, green_zone): + if value >= red_zone[0] and value <= red_zone[1]: + return format_text("{0}".format(value), 'red') + + if value >= green_zone[0] and value <= green_zone[1]: + return format_text("{0}".format(value), 'green') + + return "{0}".format(value) + # pretty print for JSON def pretty_json (json_str, use_colors = True): pretty_str = json.dumps(json.loads(json_str), indent = 4, separators=(',', ': '), sort_keys = True) diff --git a/scripts/automation/trex_control_plane/common/trex_stats.py b/scripts/automation/trex_control_plane/common/trex_stats.py index 9562f1f5..f2a965b2 100755 --- a/scripts/automation/trex_control_plane/common/trex_stats.py +++ b/scripts/automation/trex_control_plane/common/trex_stats.py @@ -1,12 +1,13 @@ #!/router/bin/python -from collections import namedtuple, OrderedDict +from collections import namedtuple, OrderedDict, deque from client_utils import text_tables -from common.text_opts import format_text +from common.text_opts import format_text, format_threshold from client.trex_async_client import CTRexAsyncStats import copy import datetime import time import re +import math GLOBAL_STATS = 'g' PORT_STATS = 'p' @@ -16,6 +17,44 @@ COMPACT = {GLOBAL_STATS, PORT_STATS} ExportableStats = namedtuple('ExportableStats', ['raw_data', 'text_table']) +# use to calculate diffs relative to the previous values +# for example, BW +def calculate_diff (samples): + total = 0.0 + + weight_step = 1.0 / sum(xrange(0, len(samples))) + weight = weight_step + + for i in xrange(0, len(samples) - 1): + current = samples[i] if samples[i] > 0 else 1 + next = samples[i + 1] if samples[i + 1] > 0 else 1 + + s = 100 * ((float(next) / current) - 1.0) + + # block change by 100% + total += (min(s, 100) * weight) + weight += weight_step + + return total + + +# calculate by absolute values and not relatives (useful for CPU usage in % and etc.) +def calculate_diff_raw (samples): + total = 0.0 + + weight_step = 1.0 / sum(xrange(0, len(samples))) + weight = weight_step + + for i in xrange(0, len(samples) - 1): + current = samples[i] + next = samples[i + 1] + + total += ( (next - current) * weight ) + weight += weight_step + + return total + + class CTRexStatsGenerator(object): """ @@ -158,7 +197,7 @@ class CTRexStats(object): self.reference_stats = None self.latest_stats = {} self.last_update_ts = time.time() - + self.history = deque(maxlen = 10) def __getitem__(self, item): # override this to allow quick and clean access to fields @@ -210,6 +249,7 @@ class CTRexStats(object): def update(self, snapshot): # update self.latest_stats = snapshot + self.history.append(snapshot) diff_time = time.time() - self.last_update_ts @@ -242,6 +282,54 @@ class CTRexStats(object): else: return self.format_num(self.latest_stats[field] - self.reference_stats[field], suffix) + # get trend for a field + def get_trend (self, field, use_raw = False): + if not field in self.latest_stats: + return 0 + + if len(self.history) < 5: + return 0 + + field_samples = [sample[field] for sample in self.history] + + if use_raw: + return calculate_diff_raw(field_samples) + else: + return calculate_diff(field_samples) + + + def get_trend_gui (self, field, show_value = True, use_raw = False, up_color = 'red', down_color = 'green'): + v = self.get_trend(field, use_raw) + + value = abs(v) + arrow = u'\u25b2' if v > 0 else u'\u25bc' + color = up_color if v > 0 else down_color + + # change in 1% is not meaningful + if value < 1: + return "" + + elif value > 5: + + if show_value: + return format_text(u"{0}{0}{0} {1:.2f}%".format(arrow,v), color) + else: + return format_text(u"{0}{0}{0}".format(arrow), color) + + elif value > 2: + + if show_value: + return format_text(u"{0}{0} {1:.2f}%".format(arrow,v), color) + else: + return format_text(u"{0}{0}".format(arrow), color) + + else: + if show_value: + return format_text(u"{0} {1:.2f}%".format(arrow,v), color) + else: + return format_text(u"{0}".format(arrow), color) + + class CGlobalStats(CTRexStats): @@ -256,11 +344,19 @@ class CGlobalStats(CTRexStats): port=self.connection_info.get("sync_port"))), ("version", "{ver}, UUID: {uuid}".format(ver=self.server_version.get("version", "N/A"), uuid="N/A")), - ("cpu_util", "{0}%".format(self.get("m_cpu_util"))), - ("total_tx", self.get("m_tx_bps", format=True, suffix="b/sec")), - ("total_rx", self.get("m_rx_bps", format=True, suffix="b/sec")), - ("total_pps", self.format_num(self.get("m_tx_pps") + self.get("m_rx_pps"), - suffix="pkt/sec")), + + ("cpu_util", u"{0}% {1}".format( format_threshold(self.get("m_cpu_util"), [85, 100], [0, 85]), + self.get_trend_gui("m_cpu_util", use_raw = True))), + + ("total_tx", u"{0} {1}".format( self.get("m_tx_bps", format=True, suffix="b/sec"), + self.get_trend_gui("m_tx_bps"))), + + ("total_rx", u"{0} {1}".format( self.get("m_rx_bps", format=True, suffix="b/sec"), + self.get_trend_gui("m_rx_bps"))), + + ("total_pps", u"{0} {1}".format( self.get("m_tx_pps", format=True, suffix="pkt/sec"), + self.get_trend_gui("m_tx_pps"))), + ("total_streams", sum([len(port_obj.streams) for _, port_obj in self._ports_dict.iteritems()])), ("active_ports", sum([port_obj.is_active() @@ -291,11 +387,19 @@ class CPortStats(CTRexStats): "rx-pkts": self.get_rel("ipackets", format = True, suffix = "pkts"), "---": "", - "Tx bps": self.get("m_total_tx_bps", format = True, suffix = "bps"), - "Rx bps": self.get("m_total_rx_bps", format = True, suffix = "bps"), + "Tx bps": u"{0} {1}".format(self.get_trend_gui("m_total_tx_bps", show_value = False, up_color = None, down_color = None), + self.get("m_total_tx_bps", format = True, suffix = "bps")), + + "Rx bps": u"{0} {1}".format(self.get_trend_gui("m_total_rx_bps", show_value = False, up_color = None, down_color = None), + self.get("m_total_rx_bps", format = True, suffix = "bps")), + "----": "", - "Tx pps": self.get("m_total_tx_pps", format = True, suffix = "pps"), - "Rx pps": self.get("m_total_rx_pps", format = True, suffix = "pps"), + "Tx pps": u"{0} {1}".format(self.get_trend_gui("m_total_tx_pps", show_value = False, up_color = None, down_color = None), + self.get("m_total_tx_pps", format = True, suffix = "pps")), + + "Rx pps": u"{0} {1}".format(self.get_trend_gui("m_total_rx_pps", show_value = False, up_color = None, down_color = None), + self.get("m_total_rx_pps", format = True, suffix = "pps")), + } |