Merge "sriov: Determine path to the bind-tool"
[vswitchperf.git] / tools / report / report.py
1 # Copyright 2015-2017 Intel Corporation.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #   http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 """
16 vSwitch Characterization Report Generation.
17
18 Generate reports in format defined by X.
19 """
20
21 import os
22 import logging
23 import jinja2
24
25 from core.results.results_constants import ResultsConstants
26 from conf import settings as S
27 from tools import systeminfo
28
29 _TEMPLATE_FILES = ['report.jinja', 'report_rst.jinja']
30 _ROOT_DIR = os.path.normpath(os.path.dirname(os.path.realpath(__file__)))
31
32
33 def _get_env(result, versions):
34     """
35     Get system configuration.
36
37     :returns: Return a dictionary of the test environment.
38               The following is an example return value:
39                {'kernel': '3.10.0-229.4.2.el7.x86_64',
40                 'os': 'OS Version',
41                 'cpu': ' CPU 2.30GHz',
42                 'platform': '[2 sockets]',
43                 'nic': 'NIC'}
44
45     """
46     def _get_version(name, versions):
47         """Returns version of tool with given `name` if version was not read
48         during runtime (not inside given `versions` list), then it will be
49         obtained by call of systeminfo.get_version()
50         """
51         for version in versions:
52             if version.get()['name'] == name:
53                 return version
54
55         return systeminfo.get_version(name)
56
57     env = {
58         'os': systeminfo.get_os(),
59         'kernel': systeminfo.get_kernel(),
60         'nics': systeminfo.get_nic(),
61         'cpu': systeminfo.get_cpu(),
62         'cpu_cores': systeminfo.get_cpu_cores(),
63         'memory' : systeminfo.get_memory(),
64         'platform': systeminfo.get_platform(),
65         'vsperf': systeminfo.get_version('vswitchperf'),
66         'traffic_gen': systeminfo.get_version(S.getValue('TRAFFICGEN')),
67         'vswitch': _get_version(S.getValue('VSWITCH'), versions),
68     }
69
70     if str(S.getValue('VSWITCH')).lower().count('dpdk'):
71         env.update({'dpdk': _get_version('dpdk', versions)})
72
73     if result[ResultsConstants.DEPLOYMENT].count('v'):
74         env.update({'vnf': systeminfo.get_version(S.getValue('VNF')),
75                     'guest_image': S.getValue('GUEST_IMAGE'),
76                     'loopback_app': list(map(systeminfo.get_loopback_version,
77                                              S.getValue('GUEST_LOOPBACK'))),
78                    })
79
80     return env
81
82
83 def generate(testcase):
84     """Generate actual report.
85
86     Generate a Markdown and RST formatted files using results of tests and some
87     parsed system info.
88
89     :param input_file: Path to CSV results file
90     :param tc_results: A list of dictionaries with detailed test results.
91         Each dictionary represents test results for one of specified packet
92         sizes.
93     :param tc_stats: System statistics collected during testcase execution.
94         These statistics are overall statistics for all specified packet
95         sizes.
96     :param traffic: Dictionary with traffic definition used by TC to control
97         traffic generator.
98     :test_type: Specifies type of the testcase. Supported values are
99         'performance' and 'integration'.
100
101     :returns: Path to generated report
102     """
103     output_files = [('.'.join([os.path.splitext(testcase.get_output_file())[0], 'md'])),
104                     ('.'.join([os.path.splitext(testcase.get_output_file())[0], 'rst']))]
105     template_loader = jinja2.FileSystemLoader(searchpath=_ROOT_DIR)
106     template_env = jinja2.Environment(loader=template_loader)
107
108     tests = []
109     try:
110         # there might be multiple test results, but they are produced
111         # by the same test, only traffic details (e.g. packet size)
112         # differs
113         # in case that multiple TC conf values will be needed, then
114         # testcase refactoring should be made to store updated cfg
115         # options into testcase._cfg dictionary
116         test_config = {'Description' : testcase.get_desc(),
117                        'bidir' : testcase.get_traffic()['bidir']}
118
119         for result in testcase.get_tc_results():
120             # pass test results, env details and configuration to template
121             tests.append({
122                 'ID': result[ResultsConstants.ID].upper(),
123                 'id': result[ResultsConstants.ID],
124                 'deployment': result[ResultsConstants.DEPLOYMENT],
125                 'conf': test_config,
126                 'result': result,
127                 'env': _get_env(result, testcase.get_versions()),
128                 'stats': testcase.get_collector().get_results(),
129             })
130
131             # remove id and deployment from results before rendering
132             # but after _get_env() is called; tests dict has its shallow copy
133             del result[ResultsConstants.ID]
134             del result[ResultsConstants.DEPLOYMENT]
135
136         template_vars = {
137             'tests': tests,
138         }
139         i = 0
140         # pylint: disable=no-member
141         for output_file in output_files:
142             template = template_env.get_template(_TEMPLATE_FILES[i])
143             output_text = template.render(template_vars)
144             with open(output_file, 'w') as file_:
145                 file_.write(output_text)
146                 logging.info('Test report written to "%s"', output_file)
147             i += 1
148
149     except KeyError:
150         logging.info("Report: Ignoring file (Wrongly defined columns): %s",
151                      testcase.get_output_file())
152         raise
153     return output_files