Report: Add VPP func results
[csit.git] / resources / tools / presentation / generator_tables.py
1 # Copyright (c) 2017 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """Algorithms to generate tables.
15 """
16
17
18 import logging
19 from string import replace
20
21 from errors import PresentationError
22 from utils import mean, stdev, relative_change
23
24
25 def generate_tables(spec, data):
26     """Generate all tables specified in the specification file.
27
28     :param spec: Specification read from the specification file.
29     :param data: Data to process.
30     :type spec: Specification
31     :type data: InputData
32     """
33
34     logging.info("Generating the tables ...")
35     for table in spec.tables:
36         try:
37             eval(table["algorithm"])(table, data)
38         except NameError:
39             logging.error("The algorithm '{0}' is not defined.".
40                           format(table["algorithm"]))
41     logging.info("Done.")
42
43
44 def table_details(table, input_data):
45     """Generate the table(s) with algorithm: table_detailed_test_results
46     specified in the specification file.
47
48     :param table: Table to generate.
49     :param input_data: Data to process.
50     :type table: pandas.Series
51     :type input_data: InputData
52     """
53
54     logging.info("  Generating the table {0} ...".
55                  format(table.get("title", "")))
56
57     # Transform the data
58     data = input_data.filter_data(table)
59
60     # Prepare the header of the tables
61     header = list()
62     for column in table["columns"]:
63         header.append('"{0}"'.format(str(column["title"]).replace('"', '""')))
64
65     # Generate the data for the table according to the model in the table
66     # specification
67
68     job = table["data"].keys()[0]
69     build = str(table["data"][job][0])
70     try:
71         suites = input_data.suites(job, build)
72     except KeyError:
73         logging.error("    No data available. The table will not be generated.")
74         return
75
76     for suite_longname, suite in suites.iteritems():
77         # Generate data
78         suite_name = suite["name"]
79         table_lst = list()
80         for test in data[job][build].keys():
81             if data[job][build][test]["parent"] in suite_name:
82                 row_lst = list()
83                 for column in table["columns"]:
84                     try:
85                         col_data = str(data[job][build][test][column["data"].
86                                        split(" ")[1]]).replace('"', '""')
87                         if column["data"].split(" ")[1] in ("vat-history",
88                                                             "show-run"):
89                             col_data = replace(col_data, " |br| ", "",
90                                                maxreplace=1)
91                             col_data = " |prein| {0} |preout| ".\
92                                 format(col_data[:-5])
93                         row_lst.append('"{0}"'.format(col_data))
94                     except KeyError:
95                         row_lst.append("No data")
96                 table_lst.append(row_lst)
97
98         # Write the data to file
99         if table_lst:
100             file_name = "{0}_{1}{2}".format(table["output-file"], suite_name,
101                                             table["output-file-ext"])
102             logging.info("      Writing file: '{}'".format(file_name))
103             with open(file_name, "w") as file_handler:
104                 file_handler.write(",".join(header) + "\n")
105                 for item in table_lst:
106                     file_handler.write(",".join(item) + "\n")
107
108     logging.info("  Done.")
109
110
111 def table_performance_improvements(table, input_data):
112     """Generate the table(s) with algorithm: table_performance_improvements
113     specified in the specification file.
114
115     :param table: Table to generate.
116     :param input_data: Data to process.
117     :type table: pandas.Series
118     :type input_data: InputData
119     """
120
121     def _write_line_to_file(file_handler, data):
122         """Write a line to the .csv file.
123
124         :param file_handler: File handler for the csv file. It must be open for
125          writing text.
126         :param data: Item to be written to the file.
127         :type file_handler: BinaryIO
128         :type data: list
129         """
130
131         line_lst = list()
132         for item in data:
133             if isinstance(item["data"], str):
134                 line_lst.append(item["data"])
135             elif isinstance(item["data"], float):
136                 line_lst.append("{:.1f}".format(item["data"]))
137         file_handler.write(",".join(line_lst) + "\n")
138
139     logging.info("  Generating the table {0} ...".
140                  format(table.get("title", "")))
141
142     # Read the template
143     file_name = table.get("template", None)
144     if file_name:
145         try:
146             tmpl = _read_csv_template(file_name)
147         except PresentationError:
148             logging.error("  The template '{0}' does not exist. Skipping the "
149                           "table.".format(file_name))
150             return None
151     else:
152         logging.error("The template is not defined. Skipping the table.")
153         return None
154
155     # Transform the data
156     data = input_data.filter_data(table)
157
158     # Prepare the header of the tables
159     header = list()
160     for column in table["columns"]:
161         header.append(column["title"])
162
163     # Generate the data for the table according to the model in the table
164     # specification
165     tbl_lst = list()
166     for tmpl_item in tmpl:
167         tbl_item = list()
168         for column in table["columns"]:
169             cmd = column["data"].split(" ")[0]
170             args = column["data"].split(" ")[1:]
171             if cmd == "template":
172                 try:
173                     val = float(tmpl_item[int(args[0])])
174                 except ValueError:
175                     val = tmpl_item[int(args[0])]
176                 tbl_item.append({"data": val})
177             elif cmd == "data":
178                 job = args[0]
179                 operation = args[1]
180                 data_lst = list()
181                 for build in data[job]:
182                     try:
183                         data_lst.append(float(build[tmpl_item[0]]["throughput"]
184                                               ["value"]) / 1000000)
185                     except (KeyError, TypeError):
186                         # No data, ignore
187                         pass
188                 if data_lst:
189                     tbl_item.append({"data": eval(operation)(data_lst)})
190             elif cmd == "operation":
191                 operation = args[0]
192                 nr1 = tbl_item[int(args[1])]["data"]
193                 nr2 = tbl_item[int(args[2])]["data"]
194                 if nr1 and nr2:
195                     tbl_item.append({"data": eval(operation)(nr1, nr2)})
196                 else:
197                     tbl_item.append({"data": None})
198             else:
199                 logging.error("Not supported command {0}. Skipping the table.".
200                               format(cmd))
201                 return None
202         tbl_lst.append(tbl_item)
203
204     # Sort the table according to the relative change
205     tbl_lst.sort(key=lambda rel: rel[-1]["data"], reverse=True)
206
207     # Create the tables and write them to the files
208     file_names = [
209         "{0}_ndr_top{1}".format(table["output-file"], table["output-file-ext"]),
210         "{0}_pdr_top{1}".format(table["output-file"], table["output-file-ext"]),
211         "{0}_ndr_low{1}".format(table["output-file"], table["output-file-ext"]),
212         "{0}_pdr_low{1}".format(table["output-file"], table["output-file-ext"])
213     ]
214
215     for file_name in file_names:
216         logging.info("    Writing the file '{0}'".format(file_name))
217         with open(file_name, "w") as file_handler:
218             file_handler.write(",".join(header) + "\n")
219             for item in tbl_lst:
220                 if "ndr_top" in file_name \
221                         and "ndr" in item[1]["data"] \
222                         and item[-1]["data"] >= 10:
223                     _write_line_to_file(file_handler, item)
224                 elif "pdr_top" in file_name \
225                         and "pdr" in item[1]["data"] \
226                         and item[-1]["data"] >= 10:
227                     _write_line_to_file(file_handler, item)
228                 elif "ndr_low" in file_name \
229                         and "ndr" in item[1]["data"] \
230                         and item[-1]["data"] < 10:
231                     _write_line_to_file(file_handler, item)
232                 elif "pdr_low" in file_name \
233                         and "pdr" in item[1]["data"] \
234                         and item[-1]["data"] < 10:
235                     _write_line_to_file(file_handler, item)
236
237     logging.info("  Done.")
238
239
240 def _read_csv_template(file_name):
241     """Read the template from a .csv file.
242
243     :param file_name: Name / full path / relative path of the file to read.
244     :type file_name: str
245     :returns: Data from the template as list (lines) of lists (items on line).
246     :rtype: list
247     :raises: PresentationError if it is not possible to read the file.
248     """
249
250     try:
251         with open(file_name, 'r') as csv_file:
252             tmpl_data = list()
253             for line in csv_file:
254                 tmpl_data.append(line[:-1].split(","))
255         return tmpl_data
256     except IOError as err:
257         raise PresentationError(str(err), level="ERROR")