summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xscripts/automation/trex_control_plane/common/text_opts.py22
-rwxr-xr-xscripts/automation/trex_control_plane/common/trex_stats.py79
-rw-r--r--scripts/external_libs/texttable-0.8.4/texttable.py6
3 files changed, 97 insertions, 10 deletions
diff --git a/scripts/automation/trex_control_plane/common/text_opts.py b/scripts/automation/trex_control_plane/common/text_opts.py
index 5a86149c..6c83bc6e 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..a97c33fc 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,33 @@ COMPACT = {GLOBAL_STATS, PORT_STATS}
ExportableStats = namedtuple('ExportableStats', ['raw_data', 'text_table'])
+def calculate_diff (samples):
+ total = 0.0
+
+ 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)
+
+ return (total / (len(samples) - 1))
+
+
+# calculate by absolute values
+def calculate_diff_raw (samples):
+ total = 0.0
+
+ for i in xrange(0, len(samples) - 1):
+ current = samples[i]
+ next = samples[i + 1]
+ total += (next - current)
+
+ return (total / (len(samples) - 1))
+
+
class CTRexStatsGenerator(object):
"""
@@ -158,7 +186,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 +238,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 +271,41 @@ 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, 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:
+ return format_text(u"{0}{0}{0} {1:.2f}%".format(arrow,v), color)
+ elif value > 2:
+ return format_text(u"{0}{0} {1:.2f}%".format(arrow,v), color)
+ else:
+ return format_text(u"{0} {1:.2f}%".format(arrow,v), color)
+
+
class CGlobalStats(CTRexStats):
@@ -256,10 +320,13 @@ 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")),
+
+ ("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", 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"),
+ ("total_pps", self.format_num(self.get("m_tx_pps"),
suffix="pkt/sec")),
("total_streams", sum([len(port_obj.streams)
for _, port_obj in self._ports_dict.iteritems()])),
diff --git a/scripts/external_libs/texttable-0.8.4/texttable.py b/scripts/external_libs/texttable-0.8.4/texttable.py
index 775a43e5..684e63bd 100644
--- a/scripts/external_libs/texttable-0.8.4/texttable.py
+++ b/scripts/external_libs/texttable-0.8.4/texttable.py
@@ -365,7 +365,11 @@ class Texttable:
try:
f = float(x)
except:
- return str(x)
+ try:
+ return str(x)
+ except:
+ return x.encode('utf-8')
+
n = self._precision
dtype = self._dtype[i]