Report: Add data
[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                         continue
188                 if data_lst:
189                     tbl_item.append({"data": eval(operation)(data_lst)})
190                 else:
191                     tbl_item.append({"data": None})
192             elif cmd == "operation":
193                 operation = args[0]
194                 try:
195                     nr1 = tbl_item[int(args[1])]["data"]
196                     nr2 = tbl_item[int(args[2])]["data"]
197                     if nr1 and nr2:
198                         tbl_item.append({"data": eval(operation)(nr1, nr2)})
199                     else:
200                         tbl_item.append({"data": None})
201                 except IndexError:
202                     logging.error("No data for {0}".format(tbl_item[1]["data"]))
203                     tbl_item.append({"data": None})
204                     continue
205             else:
206                 logging.error("Not supported command {0}. Skipping the table.".
207                               format(cmd))
208                 return None
209         tbl_lst.append(tbl_item)
210
211     # Sort the table according to the relative change
212     tbl_lst.sort(key=lambda rel: rel[-1]["data"], reverse=True)
213
214     # Create the tables and write them to the files
215     file_names = [
216         "{0}_ndr_top{1}".format(table["output-file"], table["output-file-ext"]),
217         "{0}_pdr_top{1}".format(table["output-file"], table["output-file-ext"]),
218         "{0}_ndr_low{1}".format(table["output-file"], table["output-file-ext"]),
219         "{0}_pdr_low{1}".format(table["output-file"], table["output-file-ext"])
220     ]
221
222     for file_name in file_names:
223         logging.info("    Writing the file '{0}'".format(file_name))
224         with open(file_name, "w") as file_handler:
225             file_handler.write(",".join(header) + "\n")
226             for item in tbl_lst:
227                 if "ndr_top" in file_name \
228                         and "ndr" in item[1]["data"] \
229                         and item[-1]["data"] >= 10:
230                     _write_line_to_file(file_handler, item)
231                 elif "pdr_top" in file_name \
232                         and "pdr" in item[1]["data"] \
233                         and item[-1]["data"] >= 10:
234                     _write_line_to_file(file_handler, item)
235                 elif "ndr_low" in file_name \
236                         and "ndr" in item[1]["data"] \
237                         and item[-1]["data"] < 10:
238                     _write_line_to_file(file_handler, item)
239                 elif "pdr_low" in file_name \
240                         and "pdr" in item[1]["data"] \
241                         and item[-1]["data"] < 10:
242                     _write_line_to_file(file_handler, item)
243
244     logging.info("  Done.")
245
246
247 def _read_csv_template(file_name):
248     """Read the template from a .csv file.
249
250     :param file_name: Name / full path / relative path of the file to read.
251     :type file_name: str
252     :returns: Data from the template as list (lines) of lists (items on line).
253     :rtype: list
254     :raises: PresentationError if it is not possible to read the file.
255     """
256
257     try:
258         with open(file_name, 'r') as csv_file:
259             tmpl_data = list()
260             for line in csv_file:
261                 tmpl_data.append(line[:-1].split(","))
262         return tmpl_data
263     except IOError as err:
264         raise PresentationError(str(err), level="ERROR")

©2016 FD.io a Linux Foundation Collaborative Project. All Rights Reserved.
Linux Foundation is a registered trademark of The Linux Foundation. Linux is a registered trademark of Linus Torvalds.
Please see our privacy policy and terms of use.