diff options
Diffstat (limited to 'nfvbench/stats_collector.py')
-rw-r--r-- | nfvbench/stats_collector.py | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/nfvbench/stats_collector.py b/nfvbench/stats_collector.py new file mode 100644 index 0000000..964d704 --- /dev/null +++ b/nfvbench/stats_collector.py @@ -0,0 +1,145 @@ +# Copyright 2016 Cisco Systems, Inc. All rights reserved. +# +# 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. + + +import time + + +class StatsCollector(object): + """Base class for all stats collector classes.""" + + def __init__(self, start_time): + self.start_time = start_time + self.stats = [] + + def get(self): + return self.stats + + def peek(self): + return self.stats[-1] + + @staticmethod + def _get_drop_percentage(drop_pkts, total_pkts): + return float(drop_pkts * 100) / total_pkts + + @staticmethod + def _get_rx_pps(tx_pps, drop_percentage): + return (tx_pps * (100 - drop_percentage)) / 100 + + def _get_current_time_diff(self): + return int((time.time() - self.start_time) * 1000) + + +class IntervalCollector(StatsCollector): + """Collects stats while traffic is running. Frequency is specified by 'interval_sec' setting.""" + + last_tx_pkts = 0 + last_rx_pkts = 0 + last_time = 0 + + def __init__(self, start_time): + StatsCollector.__init__(self, start_time) + self.notifier = None + + def attach_notifier(self, notifier): + self.notifier = notifier + + def add(self, stats): + if self.notifier: + current_stats = self.__compute_tx_rx_diff(stats) + self.notifier.send_interval_stats(**current_stats) + + def reset(self): + # don't reset time! + self.last_rx_pkts = 0 + self.last_tx_pkts = 0 + + def add_ndr_pdr(self, tag, stats): + if self.notifier: + + current_time = self._get_current_time_diff() + rx_pps = self._get_rx_pps(stats['tx_pps'], stats['drop_percentage']) + + self.last_tx_pkts = stats['tx_pps'] / 1000 * (current_time - self.last_time) + self.last_rx_pkts = rx_pps / 1000 * (current_time - self.last_time) + self.last_time = current_time + + # 'drop_pct' key is an unfortunate name, since in iteration stats it means + # number of the packets. More suitable would be 'drop_percentage'. + # FDS frontend depends on this key + current_stats = { + '{}_pps'.format(tag): stats['tx_pps'], + 'tx_pps': stats['tx_pps'], + 'rx_pps': rx_pps, + 'drop_pct': stats['drop_percentage'], + 'time_ms': current_time + } + + self.notifier.send_interval_stats(time_ms=current_stats['time_ms'], + tx_pps=current_stats['tx_pps'], + rx_pps=current_stats['rx_pps'], + drop_pct=current_stats['drop_pct']) + if tag == 'ndr': + self.notifier.send_ndr_found(stats['tx_pps']) + else: + self.notifier.send_pdr_found(stats['tx_pps']) + + def __compute_tx_rx_diff(self, stats): + current_time = self._get_current_time_diff() + tx_diff = stats['overall']['tx']['total_pkts'] - self.last_tx_pkts + tx_pps = (tx_diff * 1000) / (current_time - self.last_time) + rx_diff = stats['overall']['rx']['total_pkts'] - self.last_rx_pkts + rx_pps = (rx_diff * 1000) / (current_time - self.last_time) + + self.last_rx_pkts = stats['overall']['rx']['total_pkts'] + self.last_tx_pkts = stats['overall']['tx']['total_pkts'] + self.last_time = current_time + + return { + 'tx_pps': tx_pps, + 'rx_pps': rx_pps, + 'drop_pct': max(0.0, (1 - (float(rx_pps) / tx_pps)) * 100), + 'time_ms': current_time + } + + +class IterationCollector(StatsCollector): + """Collects stats after traffic is stopped. Frequency is specified by 'duration_sec' setting.""" + + def __init__(self, start_time): + StatsCollector.__init__(self, start_time) + + def add(self, stats, tx_pps): + drop_percentage = self._get_drop_percentage(stats['overall']['rx']['dropped_pkts'], + stats['overall']['tx']['total_pkts']) + + record = { + 'total_tx_pps': int(stats['total_tx_rate']), + 'tx_pps': tx_pps, + 'tx_pkts': stats['overall']['tx']['total_pkts'], + 'rx_pps': self._get_rx_pps(tx_pps, drop_percentage), + 'rx_pkts': stats['overall']['rx']['total_pkts'], + 'drop_pct': stats['overall']['rx']['dropped_pkts'], + 'drop_percentage': drop_percentage, + 'time_ms': int(time.time() * 1000) + } + + if 'warning' in stats: + record['warning'] = stats['warning'] + + self.stats.append(record) + + def add_ndr_pdr(self, tag, rate): + last_stats = self.peek() + last_stats['{}_pps'.format(tag)] = rate |