NFVBENCH-153 Add support for python3
[nfvbench.git] / nfvbench / stats_manager.py
1 #!/usr/bin/env python
2 # Copyright 2016 Cisco Systems, Inc.  All rights reserved.
3 #
4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
5 #    not use this file except in compliance with the License. You may obtain
6 #    a copy of the License at
7 #
8 #         http://www.apache.org/licenses/LICENSE-2.0
9 #
10 #    Unless required by applicable law or agreed to in writing, software
11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 #    License for the specific language governing permissions and limitations
14 #    under the License.
15 #
16 import time
17
18 from .log import LOG
19 from .packet_stats import PacketPathStatsManager
20 from .stats_collector import IntervalCollector
21
22
23 class StatsManager(object):
24     """A class to collect detailed stats and handle fixed rate runs for all chain types."""
25
26     def __init__(self, chain_runner):
27         self.chain_runner = chain_runner
28         self.config = chain_runner.config
29         self.traffic_client = chain_runner.traffic_client
30         self.specs = chain_runner.specs
31         self.notifier = chain_runner.notifier
32         self.interval_collector = None
33         self.factory = chain_runner.factory
34         # create a packet path stats manager for fixed rate runs only
35         if self.config.single_run:
36             pps_list = []
37             self.traffic_client.insert_interface_stats(pps_list)
38             self.pps_mgr = PacketPathStatsManager(pps_list)
39         else:
40             self.pps_mgr = None
41         self.worker = None
42
43     def create_worker(self):
44         """Create a worker to fetch custom data.
45
46         This is done late as we need to know the dest MAC for all VNFs, which can happen
47         as late as after ARP discovery.
48         """
49         if not self.worker and self.specs.openstack:
50             WORKER_CLASS = self.factory.get_chain_worker(self.specs.openstack.encaps,
51                                                          self.config.service_chain)
52             self.worker = WORKER_CLASS(self)
53
54     def _generate_traffic(self):
55         if self.config.no_traffic:
56             return {}
57
58         self.interval_collector = IntervalCollector(time.time())
59         self.interval_collector.attach_notifier(self.notifier)
60         LOG.info('Starting to generate traffic...')
61         stats = {}
62         for stats in self.traffic_client.run_traffic():
63             self.interval_collector.add(stats)
64
65         LOG.info('...traffic generating ended.')
66         return stats
67
68     def get_stats(self):
69         return self.interval_collector.get() if self.interval_collector else []
70
71     def get_version(self):
72         return self.worker.get_version() if self.worker else {}
73
74     def _update_interface_stats(self, diff=False):
75         """Update interface stats for both the traffic generator and the worker."""
76         self.traffic_client.update_interface_stats(diff)
77         if self.worker:
78             self.worker.update_interface_stats(diff)
79
80     def run_fixed_rate(self):
81         """Run a fixed rate and analyze results."""
82         # Baseline the packet path stats
83         self._update_interface_stats()
84
85         in_flight_stats = self._generate_traffic()
86         result = {
87             'stats': in_flight_stats
88         }
89         # New analysis code with packet path stats
90         # Diff all interface stats and return packet path stats analysis
91         # Diff the packet path stats
92         self._update_interface_stats(diff=True)
93         result['packet_path_stats'] = self.pps_mgr.get_results()
94         return result
95
96     def get_compute_nodes_bios(self):
97         return self.worker.get_compute_nodes_bios() if self.worker else {}
98
99     def close(self):
100         if self.worker:
101             self.worker.close()