From 9849050dd53ebf675fc9a701fea5089381eccb70 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Mon, 23 May 2016 18:38:22 +0300 Subject: tui: add histogram --- .../trex_control_plane/stl/console/trex_tui.py | 11 +++- .../stl/trex_stl_lib/trex_stl_stats.py | 70 +++++++++++++++++----- 2 files changed, 65 insertions(+), 16 deletions(-) (limited to 'scripts') diff --git a/scripts/automation/trex_control_plane/stl/console/trex_tui.py b/scripts/automation/trex_control_plane/stl/console/trex_tui.py index 95dc654b..d3be4435 100644 --- a/scripts/automation/trex_control_plane/stl/console/trex_tui.py +++ b/scripts/automation/trex_control_plane/stl/console/trex_tui.py @@ -210,10 +210,15 @@ class TrexTUILatencyStats(TrexTUIPanel): super(TrexTUILatencyStats, self).__init__(mng, "lstats") self.key_actions = OrderedDict() self.key_actions['c'] = {'action': self.action_clear, 'legend': 'clear', 'show': True} + self.key_actions['t'] = {'action': self.action_toggle_histogram, 'legend': 'toggle histogram', 'show': True} + self.is_histogram = False def show (self): - stats = self.stateless_client._get_formatted_stats(port_id_list = None, stats_mask = trex_stl_stats.LS_COMPAT) + if self.is_histogram: + stats = self.stateless_client._get_formatted_stats(port_id_list = None, stats_mask = trex_stl_stats.LH_COMPAT) + else: + stats = self.stateless_client._get_formatted_stats(port_id_list = None, stats_mask = trex_stl_stats.LS_COMPAT) # print stats to screen for stat_type, stat_data in stats.items(): if stat_type == 'latency_statistics': @@ -225,6 +230,10 @@ class TrexTUILatencyStats(TrexTUIPanel): def get_key_actions (self): return self.key_actions + def action_toggle_histogram (self): + self.is_histogram = not self.is_histogram + return "" + def action_clear (self): self.stateless_client.latency_stats.clear_stats() return "" diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py index 98a08d55..6b34b11a 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py @@ -20,13 +20,15 @@ PORT_STATS = 'p' PORT_GRAPH = 'pg' PORT_STATUS = 'ps' STREAMS_STATS = 's' -LATENCY_STATS = 'l' +LATENCY_STATS = 'ls' +LATENCY_HISTOGRAM = 'lh' -ALL_STATS_OPTS = [GLOBAL_STATS, PORT_STATS, PORT_STATUS, STREAMS_STATS, LATENCY_STATS, PORT_GRAPH] +ALL_STATS_OPTS = [GLOBAL_STATS, PORT_STATS, PORT_STATUS, STREAMS_STATS, LATENCY_STATS, PORT_GRAPH, LATENCY_HISTOGRAM] COMPACT = [GLOBAL_STATS, PORT_STATS] GRAPH_PORT_COMPACT = [GLOBAL_STATS, PORT_GRAPH] SS_COMPAT = [GLOBAL_STATS, STREAMS_STATS] # stream stats LS_COMPAT = [GLOBAL_STATS, LATENCY_STATS] # latency stats +LH_COMPAT = [GLOBAL_STATS, LATENCY_HISTOGRAM] # latency histogram ExportableStats = namedtuple('ExportableStats', ['raw_data', 'text_table']) @@ -161,6 +163,9 @@ class CTRexInfoGenerator(object): elif statistic_type == LATENCY_STATS: return self._generate_latency_stats() + elif statistic_type == LATENCY_HISTOGRAM: + return self._generate_latency_histogram() + else: # ignore by returning empty object return {} @@ -357,6 +362,49 @@ class CTRexInfoGenerator(object): return {"latency_statistics": ExportableStats(lstats_data, stats_table)} + def _generate_latency_histogram(self): + lat_stats = self._latency_stats_ref.latest_stats + max_histogram_size = 17 + + # for TUI - maximum 5 + pg_ids = list(filter(is_intable, lat_stats.keys()))[:5] + + merged_histogram = {} + for pg_id in pg_ids: + merged_histogram.update(lat_stats[pg_id]['latency']['histogram']) + histogram_size = min(max_histogram_size, len(merged_histogram)) + + stream_count = len(pg_ids) + stats_table = text_tables.TRexTextTable() + stats_table.set_cols_align(["l"] + ["r"] * stream_count) + stats_table.set_cols_width([12] + [14] * stream_count) + stats_table.set_cols_dtype(['t'] + ['t'] * stream_count) + + for i in range(max_histogram_size - histogram_size): + if i == 0 and not merged_histogram: + stats_table.add_row([' No Data'] + [' '] * stream_count) + else: + stats_table.add_row([' '] * (stream_count + 1)) + for key in list(reversed(sorted(merged_histogram.keys())))[:histogram_size]: + hist_vals = [] + for pg_id in pg_ids: + hist_vals.append(lat_stats[pg_id]['latency']['histogram'].get(key, ' ')) + stats_table.add_row([key] + hist_vals) + + stats_table.add_row(['- Counters -'] + [' '] * stream_count) + err_cntrs_dict = OrderedDict() + for pg_id in pg_ids: + for err_cntr in sorted(lat_stats[pg_id]['err_cntrs'].keys()): + if err_cntr not in err_cntrs_dict: + err_cntrs_dict[err_cntr] = [lat_stats[pg_id]['err_cntrs'][err_cntr]] + else: + err_cntrs_dict[err_cntr].append(lat_stats[pg_id]['err_cntrs'][err_cntr]) + for err_cntr, val_list in err_cntrs_dict.items(): + stats_table.add_row([err_cntr] + val_list) + header = ["PG ID"] + [key for key in pg_ids] + stats_table.header(header) + return {"latency_histogram": ExportableStats(None, stats_table)} + @staticmethod def _get_rational_block_char(value, range_start, interval): # in Konsole, utf-8 is sometimes printed with artifacts, return ascii for now @@ -745,8 +793,8 @@ class CGlobalStats(CTRexStats): self._ports_dict = ports_dict_ref self.events_handler = events_handler - self.watched_cpu_util = WatchedField('CPU util.', '%', 95, 90, events_handler) - self.watched_rx_cpu_util = WatchedField('RX core util.', '%', 95, 90, events_handler) + self.watched_cpu_util = WatchedField('CPU util.', '%', 85, 60, events_handler) + self.watched_rx_cpu_util = WatchedField('RX core util.', '%', 85, 60, events_handler) def get_stats (self): stats = {} @@ -978,17 +1026,9 @@ class CLatencyStats(CTRexStats): if current_pg['latency']['h'] != "": output[int_pg_id]['latency']['average'] = current_pg['latency']['h']['s_avg'] output[int_pg_id]['latency']['total_max'] = current_pg['latency']['h']['max_usec'] - output[int_pg_id]['latency']['histogram'] = current_pg['latency']['h']['histogram'] + output[int_pg_id]['latency']['histogram'] = {elem['key']: elem['val'] for elem in current_pg['latency']['h']['histogram']} zero_count = current_pg['latency']['h']['cnt'] - current_pg['latency']['h']['high_cnt'] - if zero_count != 0: - output[int_pg_id]['latency']['histogram'].append({'key':0, 'val':zero_count}) - output[int_pg_id]['latency']['total_min'] = 1 - else: - min_usec = current_pg['latency']['h']['max_usec'] - for bucket in output[int_pg_id]['latency']['histogram']: - if bucket['key'] < min_usec: - min_usec = bucket['key'] - output[int_pg_id]['latency']['total_min'] = min_usec + output[int_pg_id]['latency']['histogram'][0] = zero_count self.latest_stats = output return True @@ -1191,7 +1231,7 @@ class CRxStats(CTRexStats): def _update (self, snapshot): - + #print(snapshot) # generate a new snapshot new_snapshot = self.process_snapshot(snapshot, self.latest_stats) -- cgit 1.2.3-korg