Cleanup requirements & tox config, update pylint
[nfvbench.git] / nfvbench / summarizer.py
index de62a73..7c69f52 100644 (file)
@@ -219,35 +219,6 @@ class Summarizer(object):
 class NFVBenchSummarizer(Summarizer):
     """Summarize nfvbench json result."""
 
-    ndr_pdr_header = [
-        ('-', Formatter.fixed),
-        ('L2 Frame Size', Formatter.standard),
-        ('Rate (fwd+rev)', Formatter.bits),
-        ('Rate (fwd+rev)', Formatter.suffix(' pps')),
-        ('Avg Drop Rate', Formatter.suffix('%')),
-        ('Avg Latency (usec)', Formatter.standard),
-        ('Min Latency (usec)', Formatter.standard),
-        ('Max Latency (usec)', Formatter.standard)
-    ]
-
-    single_run_header = [
-        ('L2 Frame Size', Formatter.standard),
-        ('Drop Rate', Formatter.suffix('%')),
-        ('Avg Latency (usec)', Formatter.standard),
-        ('Min Latency (usec)', Formatter.standard),
-        ('Max Latency (usec)', Formatter.standard)
-    ]
-
-    config_header = [
-        ('Direction', Formatter.standard),
-        ('Requested TX Rate (bps)', Formatter.bits),
-        ('Actual TX Rate (bps)', Formatter.bits),
-        ('RX Rate (bps)', Formatter.bits),
-        ('Requested TX Rate (pps)', Formatter.suffix(' pps')),
-        ('Actual TX Rate (pps)', Formatter.suffix(' pps')),
-        ('RX Rate (pps)', Formatter.suffix(' pps'))
-    ]
-
     direction_keys = ['direction-forward', 'direction-reverse', 'direction-total']
     direction_names = ['Forward', 'Reverse', 'Total']
 
@@ -259,6 +230,47 @@ class NFVBenchSummarizer(Summarizer):
         self.record_header = None
         self.record_data = None
         self.sender = sender
+
+        self.ndr_pdr_header = [
+            ('-', Formatter.fixed),
+            ('L2 Frame Size', Formatter.standard),
+            ('Rate (fwd+rev)', Formatter.bits),
+            ('Rate (fwd+rev)', Formatter.suffix(' pps')),
+            ('Avg Drop Rate', Formatter.suffix('%')),
+            ('Avg Latency (usec)', Formatter.standard),
+            ('Min Latency (usec)', Formatter.standard),
+            ('Max Latency (usec)', Formatter.standard)
+        ]
+
+        self.single_run_header = [
+            ('L2 Frame Size', Formatter.standard),
+            ('Drop Rate', Formatter.suffix('%')),
+            ('Avg Latency (usec)', Formatter.standard),
+            ('Min Latency (usec)', Formatter.standard),
+            ('Max Latency (usec)', Formatter.standard)
+        ]
+
+        self.config_header = [
+            ('Direction', Formatter.standard),
+            ('Requested TX Rate (bps)', Formatter.bits),
+            ('Actual TX Rate (bps)', Formatter.bits),
+            ('RX Rate (bps)', Formatter.bits),
+            ('Requested TX Rate (pps)', Formatter.suffix(' pps')),
+            ('Actual TX Rate (pps)', Formatter.suffix(' pps')),
+            ('RX Rate (pps)', Formatter.suffix(' pps'))
+        ]
+
+        # add percentiles headers if hdrh enabled
+        if not self.config.disable_hdrh:
+            for percentile in self.config.lat_percentiles:
+                # 'append' expects a single parameter => double parentheses
+                self.ndr_pdr_header.append((str(percentile) + ' %ile lat.', Formatter.standard))
+                self.single_run_header.append((str(percentile) + ' %ile lat.', Formatter.standard))
+
+        if self.config.periodic_gratuitous_arp:
+            self.direction_keys.insert(2, 'garp-direction-total')
+            self.direction_names.insert(2, 'Gratuitous ARP')
+
         # if sender is available initialize record
         if self.sender:
             self.__record_init()
@@ -394,7 +406,8 @@ class NFVBenchSummarizer(Summarizer):
             for frame_size, analysis in list(traffic_result.items()):
                 if frame_size == 'warning':
                     continue
-                summary_table.add_row([
+
+                row_data = [
                     'NDR',
                     frame_size,
                     analysis['ndr']['rate_bps'],
@@ -403,21 +416,34 @@ class NFVBenchSummarizer(Summarizer):
                     analysis['ndr']['stats']['overall']['avg_delay_usec'],
                     analysis['ndr']['stats']['overall']['min_delay_usec'],
                     analysis['ndr']['stats']['overall']['max_delay_usec']
-                ])
-                self.__record_data_put(frame_size, {'ndr': {
+                ]
+                if not self.config.disable_hdrh:
+                    self.extract_hdrh_percentiles(
+                        analysis['ndr']['stats']['overall']['lat_percentile'], row_data)
+                summary_table.add_row(row_data)
+
+                ndr_data = {
                     'type': 'NDR',
                     'rate_bps': analysis['ndr']['rate_bps'],
                     'rate_pps': analysis['ndr']['rate_pps'],
+                    'offered_tx_rate_bps': analysis['ndr']['stats']['offered_tx_rate_bps'],
+                    'theoretical_tx_rate_pps': analysis['ndr']['stats']['theoretical_tx_rate_pps'],
+                    'theoretical_tx_rate_bps': analysis['ndr']['stats']['theoretical_tx_rate_bps'],
                     'drop_percentage': analysis['ndr']['stats']['overall']['drop_percentage'],
                     'avg_delay_usec': analysis['ndr']['stats']['overall']['avg_delay_usec'],
                     'min_delay_usec': analysis['ndr']['stats']['overall']['min_delay_usec'],
                     'max_delay_usec': analysis['ndr']['stats']['overall']['max_delay_usec']
-                }})
+                }
+                if not self.config.disable_hdrh:
+                    self.extract_hdrh_percentiles(
+                        analysis['ndr']['stats']['overall']['lat_percentile'], ndr_data, True)
+                self.__record_data_put(frame_size, {'ndr': ndr_data})
         if self.config['pdr_run']:
             for frame_size, analysis in list(traffic_result.items()):
                 if frame_size == 'warning':
                     continue
-                summary_table.add_row([
+
+                row_data = [
                     'PDR',
                     frame_size,
                     analysis['pdr']['rate_bps'],
@@ -426,34 +452,73 @@ class NFVBenchSummarizer(Summarizer):
                     analysis['pdr']['stats']['overall']['avg_delay_usec'],
                     analysis['pdr']['stats']['overall']['min_delay_usec'],
                     analysis['pdr']['stats']['overall']['max_delay_usec']
-                ])
-                self.__record_data_put(frame_size, {'pdr': {
+                ]
+                if not self.config.disable_hdrh:
+                    self.extract_hdrh_percentiles(
+                        analysis['pdr']['stats']['overall']['lat_percentile'], row_data)
+                summary_table.add_row(row_data)
+
+                pdr_data = {
                     'type': 'PDR',
                     'rate_bps': analysis['pdr']['rate_bps'],
                     'rate_pps': analysis['pdr']['rate_pps'],
+                    'offered_tx_rate_bps': analysis['pdr']['stats']['offered_tx_rate_bps'],
+                    'theoretical_tx_rate_pps': analysis['pdr']['stats']['theoretical_tx_rate_pps'],
+                    'theoretical_tx_rate_bps': analysis['pdr']['stats']['theoretical_tx_rate_bps'],
                     'drop_percentage': analysis['pdr']['stats']['overall']['drop_percentage'],
                     'avg_delay_usec': analysis['pdr']['stats']['overall']['avg_delay_usec'],
                     'min_delay_usec': analysis['pdr']['stats']['overall']['min_delay_usec'],
                     'max_delay_usec': analysis['pdr']['stats']['overall']['max_delay_usec']
-                }})
+                }
+                if not self.config.disable_hdrh:
+                    self.extract_hdrh_percentiles(
+                        analysis['pdr']['stats']['overall']['lat_percentile'], pdr_data, True)
+                self.__record_data_put(frame_size, {'pdr': pdr_data})
         if self.config['single_run']:
             for frame_size, analysis in list(traffic_result.items()):
-                summary_table.add_row([
+                row_data = [
                     frame_size,
                     analysis['stats']['overall']['drop_rate_percent'],
                     analysis['stats']['overall']['rx']['avg_delay_usec'],
                     analysis['stats']['overall']['rx']['min_delay_usec'],
                     analysis['stats']['overall']['rx']['max_delay_usec']
-                ])
-                self.__record_data_put(frame_size, {'single_run': {
+                ]
+                if not self.config.disable_hdrh:
+                    self.extract_hdrh_percentiles(
+                        analysis['stats']['overall']['rx']['lat_percentile'], row_data)
+                summary_table.add_row(row_data)
+
+                single_run_data = {
                     'type': 'single_run',
+                    'offered_tx_rate_bps': analysis['stats']['offered_tx_rate_bps'],
+                    'theoretical_tx_rate_pps': analysis['stats']['theoretical_tx_rate_pps'],
+                    'theoretical_tx_rate_bps': analysis['stats']['theoretical_tx_rate_bps'],
                     'drop_rate_percent': analysis['stats']['overall']['drop_rate_percent'],
                     'avg_delay_usec': analysis['stats']['overall']['rx']['avg_delay_usec'],
                     'min_delay_usec': analysis['stats']['overall']['rx']['min_delay_usec'],
                     'max_delay_usec': analysis['stats']['overall']['rx']['max_delay_usec']
-                }})
+                }
+                if not self.config.disable_hdrh:
+                    self.extract_hdrh_percentiles(
+                        analysis['stats']['overall']['rx']['lat_percentile'], single_run_data, True)
+                self.__record_data_put(frame_size, {'single_run': single_run_data})
         return summary_table
 
+    def extract_hdrh_percentiles(self, lat_percentile, data, add_key=False):
+        if add_key:
+            data['lat_percentile'] = {}
+        for percentile in self.config.lat_percentiles:
+            if add_key:
+                try:
+                    data['lat_percentile_' + str(percentile)] = lat_percentile[percentile]
+                except TypeError:
+                    data['lat_percentile_' + str(percentile)] = "n/a"
+            else:
+                try:
+                    data.append(lat_percentile[percentile])
+                except TypeError:
+                    data.append("n/a")
+
     def __get_config_table(self, run_config, frame_size):
         config_table = Table(self.config_header)
         for key, name in zip(self.direction_keys, self.direction_names):
@@ -498,21 +563,43 @@ class NFVBenchSummarizer(Summarizer):
         _annotate_chain_stats(chains)
         header = [('Chain', Formatter.standard)] + \
                  [(ifname, Formatter.standard) for ifname in chain_stats['interfaces']]
-        # add latency columns if available Avg, Min, Max
+        # add latency columns if available Avg, Min, Max and percentiles
         lat_keys = []
         lat_map = {'lat_avg_usec': 'Avg lat.',
                    'lat_min_usec': 'Min lat.',
                    'lat_max_usec': 'Max lat.'}
         if 'lat_avg_usec' in chains['0']:
             lat_keys = ['lat_avg_usec', 'lat_min_usec', 'lat_max_usec']
-            for key in lat_keys:
-                header.append((lat_map[key], Formatter.standard))
+
+            if not self.config.disable_hdrh:
+                lat_keys.append('lat_percentile')
+                for percentile in self.config.lat_percentiles:
+                    lat_map['lat_' + str(percentile) + '_percentile'] = \
+                        str(percentile) + ' %ile lat.'
+
+            for lat_value in lat_map.values():
+                # 'append' expects a single parameter => double parentheses
+                header.append((lat_value, Formatter.standard))
 
         table = Table(header)
         for chain in sorted(list(chains.keys()), key=str):
             row = [chain] + chains[chain]['packets']
             for lat_key in lat_keys:
-                row.append('{:,} usec'.format(chains[chain][lat_key]))
+
+                if lat_key != 'lat_percentile':
+                    if chains[chain].get(lat_key, None):
+                        row.append(Formatter.standard(chains[chain][lat_key]))
+                    else:
+                        row.append('n/a')
+                else:
+                    if not self.config.disable_hdrh:
+                        if chains[chain].get(lat_key, None):
+                            for percentile in chains[chain][lat_key]:
+                                row.append(Formatter.standard(
+                                    chains[chain][lat_key][percentile]))
+                        else:
+                            for _ in self.config.lat_percentiles:
+                                row.append('n/a')
             table.add_row(row)
         return table
 
@@ -546,9 +633,9 @@ class NFVBenchSummarizer(Summarizer):
                     run_specific_data['pdr'] = data['pdr']
                     run_specific_data['pdr']['drop_limit'] = self.config['measurement']['PDR']
                     del data['pdr']
-                for key in run_specific_data:
+                for data_value in run_specific_data.values():
                     data_to_send = data.copy()
-                    data_to_send.update(run_specific_data[key])
+                    data_to_send.update(data_value)
                     self.sender.record_send(data_to_send)
             self.__record_init()